Merge "document and deprecated Rasterizer"
diff --git a/Android.mk b/Android.mk
index 5e634c1..89b2884 100644
--- a/Android.mk
+++ b/Android.mk
@@ -68,6 +68,7 @@
core/java/android/app/IActivityController.aidl \
core/java/android/app/IActivityPendingResult.aidl \
core/java/android/app/IAlarmManager.aidl \
+ core/java/android/app/IAppTask.aidl \
core/java/android/app/IBackupAgent.aidl \
core/java/android/app/IInstrumentationWatcher.aidl \
core/java/android/app/INotificationManager.aidl \
@@ -126,6 +127,8 @@
core/java/android/content/pm/IPackageDeleteObserver.aidl \
core/java/android/content/pm/IPackageInstallObserver.aidl \
core/java/android/content/pm/IPackageInstallObserver2.aidl \
+ core/java/android/content/pm/IPackageInstaller.aidl \
+ core/java/android/content/pm/IPackageInstallerSession.aidl \
core/java/android/content/pm/IPackageManager.aidl \
core/java/android/content/pm/IPackageMoveObserver.aidl \
core/java/android/content/pm/IPackageStatsObserver.aidl \
@@ -302,18 +305,30 @@
media/java/android/media/IRemoteDisplayProvider.aidl \
media/java/android/media/IRemoteVolumeObserver.aidl \
media/java/android/media/IRingtonePlayer.aidl \
- media/java/android/media/routeprovider/IRouteConnection.aidl \
- media/java/android/media/routeprovider/IRouteProvider.aidl \
- media/java/android/media/routeprovider/IRouteProviderCallback.aidl \
- media/java/android/media/session/ISessionController.aidl \
- media/java/android/media/session/ISessionControllerCallback.aidl \
- media/java/android/media/session/ISession.aidl \
- media/java/android/media/session/ISessionCallback.aidl \
- media/java/android/media/session/ISessionManager.aidl \
+ media/java/android/media/routeprovider/IRouteConnection.aidl \
+ media/java/android/media/routeprovider/IRouteProvider.aidl \
+ media/java/android/media/routeprovider/IRouteProviderCallback.aidl \
+ media/java/android/media/session/ISessionController.aidl \
+ media/java/android/media/session/ISessionControllerCallback.aidl \
+ media/java/android/media/session/ISession.aidl \
+ media/java/android/media/session/ISessionCallback.aidl \
+ media/java/android/media/session/ISessionManager.aidl \
+ telecomm/java/com/android/internal/telecomm/ICallService.aidl \
+ telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl \
+ telecomm/java/com/android/internal/telecomm/ICallServiceLookupResponse.aidl \
+ telecomm/java/com/android/internal/telecomm/ICallServiceProvider.aidl \
+ telecomm/java/com/android/internal/telecomm/ICallServiceSelector.aidl \
+ telecomm/java/com/android/internal/telecomm/ICallServiceSelectorAdapter.aidl \
+ telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl \
+ telecomm/java/com/android/internal/telecomm/IInCallService.aidl \
telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
telephony/java/com/android/internal/telephony/ITelephony.aidl \
telephony/java/com/android/internal/telephony/ITelephonyListener.aidl \
+ telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl \
+ telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl \
+ telephony/java/com/android/internal/telephony/IThirdPartyCallSendDtmfCallback.aidl \
+ telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl \
telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
telephony/java/com/android/internal/telephony/ISms.aidl \
telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index 1f4a01e..b7fc562 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -250,7 +250,7 @@
field public static final int actionBarTabBarStyle = 16843508; // 0x10102f4
field public static final int actionBarTabStyle = 16843507; // 0x10102f3
field public static final int actionBarTabTextStyle = 16843509; // 0x10102f5
- field public static final int actionBarTheme = 16843831; // 0x1010437
+ field public static final int actionBarTheme = 16843829; // 0x1010435
field public static final int actionBarWidgetTheme = 16843671; // 0x1010397
field public static final int actionButtonStyle = 16843480; // 0x10102d8
field public static final int actionDropDownStyle = 16843479; // 0x10102d7
@@ -267,7 +267,7 @@
field public static final int actionModeSplitBackground = 16843677; // 0x101039d
field public static final int actionModeStyle = 16843668; // 0x1010394
field public static final int actionOverflowButtonStyle = 16843510; // 0x10102f6
- field public static final int actionOverflowMenuStyle = 16843851; // 0x101044b
+ field public static final int actionOverflowMenuStyle = 16843849; // 0x1010449
field public static final int actionProviderClass = 16843657; // 0x1010389
field public static final int actionViewClass = 16843516; // 0x10102fc
field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
@@ -313,7 +313,7 @@
field public static final int autoCompleteTextViewStyle = 16842859; // 0x101006b
field public static final int autoLink = 16842928; // 0x10100b0
field public static final int autoMirrored = 16843754; // 0x10103ea
- field public static final int autoRemoveFromRecents = 16843853; // 0x101044d
+ field public static final int autoRemoveFromRecents = 16843851; // 0x101044b
field public static final int autoStart = 16843445; // 0x10102b5
field public static final deprecated int autoText = 16843114; // 0x101016a
field public static final int autoUrlDetect = 16843404; // 0x101028c
@@ -386,14 +386,12 @@
field public static final int codes = 16843330; // 0x1010242
field public static final int collapseColumns = 16843083; // 0x101014b
field public static final int color = 16843173; // 0x10101a5
- field public static final int colorAccent = 16843836; // 0x101043c
+ field public static final int colorAccent = 16843834; // 0x101043a
field public static final int colorActivatedHighlight = 16843664; // 0x1010390
field public static final int colorBackground = 16842801; // 0x1010031
field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab
field public static final int colorButtonNormal = 16843823; // 0x101042f
- field public static final int colorButtonNormalColored = 16843825; // 0x1010431
field public static final int colorButtonPressed = 16843824; // 0x1010430
- field public static final int colorButtonPressedColored = 16843826; // 0x1010432
field public static final int colorControlActivated = 16843822; // 0x101042e
field public static final int colorControlNormal = 16843821; // 0x101042d
field public static final int colorFocusedHighlight = 16843663; // 0x101038f
@@ -402,9 +400,9 @@
field public static final int colorLongPressedHighlight = 16843662; // 0x101038e
field public static final int colorMultiSelectHighlight = 16843665; // 0x1010391
field public static final int colorPressedHighlight = 16843661; // 0x101038d
- field public static final int colorPrimary = 16843834; // 0x101043a
- field public static final int colorPrimaryDark = 16843835; // 0x101043b
- field public static final int colorPrimaryLight = 16843833; // 0x1010439
+ field public static final int colorPrimary = 16843832; // 0x1010438
+ field public static final int colorPrimaryDark = 16843833; // 0x1010439
+ field public static final int colorPrimaryLight = 16843831; // 0x1010437
field public static final int columnCount = 16843639; // 0x1010377
field public static final int columnDelay = 16843215; // 0x10101cf
field public static final int columnOrderPreserved = 16843640; // 0x1010378
@@ -463,7 +461,7 @@
field public static final int dividerHorizontal = 16843564; // 0x101032c
field public static final int dividerPadding = 16843562; // 0x101032a
field public static final int dividerVertical = 16843530; // 0x101030a
- field public static final int documentLaunchMode = 16843852; // 0x101044c
+ field public static final int documentLaunchMode = 16843850; // 0x101044a
field public static final int drawSelectorOnTop = 16843004; // 0x10100fc
field public static final int drawable = 16843161; // 0x1010199
field public static final int drawableBottom = 16843118; // 0x101016e
@@ -492,7 +490,7 @@
field public static final int editTextStyle = 16842862; // 0x101006e
field public static final deprecated int editable = 16843115; // 0x101016b
field public static final int editorExtras = 16843300; // 0x1010224
- field public static final int elevation = 16843847; // 0x1010447
+ field public static final int elevation = 16843845; // 0x1010445
field public static final int ellipsize = 16842923; // 0x10100ab
field public static final int ems = 16843096; // 0x1010158
field public static final int enabled = 16842766; // 0x101000e
@@ -502,9 +500,10 @@
field public static final int entries = 16842930; // 0x10100b2
field public static final int entryValues = 16843256; // 0x10101f8
field public static final int eventsInterceptionEnabled = 16843389; // 0x101027d
- field public static final int excludeClass = 16843849; // 0x1010449
+ field public static final int excludeClass = 16843847; // 0x1010447
field public static final int excludeFromRecents = 16842775; // 0x1010017
- field public static final int excludeId = 16843848; // 0x1010448
+ field public static final int excludeId = 16843846; // 0x1010446
+ field public static final int excludeViewName = 16843858; // 0x1010452
field public static final int exitFadeDuration = 16843533; // 0x101030d
field public static final int expandableListPreferredChildIndicatorLeft = 16842834; // 0x1010052
field public static final int expandableListPreferredChildIndicatorRight = 16842835; // 0x1010053
@@ -567,6 +566,7 @@
field public static final int freezesText = 16843116; // 0x101016c
field public static final int fromAlpha = 16843210; // 0x10101ca
field public static final int fromDegrees = 16843187; // 0x10101b3
+ field public static final int fromId = 16843854; // 0x101044e
field public static final int fromScene = 16843741; // 0x10103dd
field public static final int fromXDelta = 16843206; // 0x10101c6
field public static final int fromXScale = 16843202; // 0x10101c2
@@ -599,7 +599,7 @@
field public static final int headerBackground = 16843055; // 0x101012f
field public static final int headerDividersEnabled = 16843310; // 0x101022e
field public static final int height = 16843093; // 0x1010155
- field public static final int hideOnContentScroll = 16843850; // 0x101044a
+ field public static final int hideOnContentScroll = 16843848; // 0x1010448
field public static final int hint = 16843088; // 0x1010150
field public static final int homeAsUpIndicator = 16843531; // 0x101030b
field public static final int homeLayout = 16843549; // 0x101031d
@@ -796,6 +796,7 @@
field public static final int manageSpaceActivity = 16842756; // 0x1010004
field public static final int mapViewStyle = 16842890; // 0x101008a
field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
+ field public static final int matchOrder = 16843859; // 0x1010453
field public static final int max = 16843062; // 0x1010136
field public static final int maxDate = 16843584; // 0x1010340
field public static final int maxEms = 16843095; // 0x1010157
@@ -828,9 +829,10 @@
field public static final int moreIcon = 16843061; // 0x1010135
field public static final int multiprocess = 16842771; // 0x1010013
field public static final int name = 16842755; // 0x1010003
+ field public static final int navigationBarColor = 16843862; // 0x1010456
field public static final int navigationMode = 16843471; // 0x10102cf
field public static final int negativeButtonText = 16843254; // 0x10101f6
- field public static final int nestedScrollingEnabled = 16843837; // 0x101043d
+ field public static final int nestedScrollingEnabled = 16843835; // 0x101043b
field public static final int nextFocusDown = 16842980; // 0x10100e4
field public static final int nextFocusForward = 16843580; // 0x101033c
field public static final int nextFocusLeft = 16842977; // 0x10100e1
@@ -879,7 +881,7 @@
field public static final int permissionFlags = 16843719; // 0x10103c7
field public static final int permissionGroup = 16842762; // 0x101000a
field public static final int permissionGroupFlags = 16843717; // 0x10103c5
- field public static final int persistable = 16843827; // 0x1010433
+ field public static final int persistable = 16843825; // 0x1010431
field public static final int persistent = 16842765; // 0x101000d
field public static final int persistentDrawingCache = 16842990; // 0x10100ee
field public static final deprecated int phoneNumber = 16843111; // 0x1010167
@@ -956,6 +958,7 @@
field public static final int restoreAnyVersion = 16843450; // 0x10102ba
field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
field public static final int restrictedAccountType = 16843733; // 0x10103d5
+ field public static final int reversible = 16843855; // 0x101044f
field public static final int right = 16843183; // 0x10101af
field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
field public static final int ringtoneType = 16843257; // 0x10101f9
@@ -1011,7 +1014,7 @@
field public static final int selectableItemBackground = 16843534; // 0x101030e
field public static final int selectedDateVerticalBar = 16843591; // 0x1010347
field public static final int selectedWeekBackgroundColor = 16843586; // 0x1010342
- field public static final int sessionService = 16843844; // 0x1010444
+ field public static final int sessionService = 16843842; // 0x1010442
field public static final int settingsActivity = 16843301; // 0x1010225
field public static final int shadowColor = 16843105; // 0x1010161
field public static final int shadowDx = 16843106; // 0x1010162
@@ -1019,7 +1022,6 @@
field public static final int shadowRadius = 16843108; // 0x1010164
field public static final int shape = 16843162; // 0x101019a
field public static final int shareInterpolator = 16843195; // 0x10101bb
- field public static final int sharedElementName = 16843803; // 0x101041b
field public static final int sharedUserId = 16842763; // 0x101000b
field public static final int sharedUserLabel = 16843361; // 0x1010261
field public static final int shouldDisableView = 16843246; // 0x10101ee
@@ -1033,7 +1035,7 @@
field public static final int shrinkColumns = 16843082; // 0x101014a
field public static final deprecated int singleLine = 16843101; // 0x101015d
field public static final int singleUser = 16843711; // 0x10103bf
- field public static final int slideEdge = 16843830; // 0x1010436
+ field public static final int slideEdge = 16843828; // 0x1010434
field public static final int smallIcon = 16843422; // 0x101029e
field public static final int smallScreens = 16843396; // 0x1010284
field public static final int smoothScrollbar = 16843313; // 0x1010231
@@ -1045,18 +1047,19 @@
field public static final int spinnerStyle = 16842881; // 0x1010081
field public static final int spinnersShown = 16843595; // 0x101034b
field public static final int splitMotionEvents = 16843503; // 0x10102ef
+ field public static final int splitTrack = 16843856; // 0x1010450
field public static final int src = 16843033; // 0x1010119
field public static final int ssp = 16843747; // 0x10103e3
field public static final int sspPattern = 16843749; // 0x10103e5
field public static final int sspPrefix = 16843748; // 0x10103e4
field public static final int stackFromBottom = 16843005; // 0x10100fd
- field public static final int stackViewStyle = 16843845; // 0x1010445
+ field public static final int stackViewStyle = 16843843; // 0x1010443
field public static final int starStyle = 16842882; // 0x1010082
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 deprecated int startYear = 16843132; // 0x101017c
- field public static final int stateListAnimator = 16843854; // 0x101044e
+ field public static final int stateListAnimator = 16843852; // 0x101044c
field public static final int stateNotNeeded = 16842774; // 0x1010016
field public static final int state_above_anchor = 16842922; // 0x10100aa
field public static final int state_accelerated = 16843547; // 0x101031b
@@ -1081,6 +1084,7 @@
field public static final int state_single = 16842915; // 0x10100a3
field public static final int state_window_focused = 16842909; // 0x101009d
field public static final int staticWallpaperPreview = 16843569; // 0x1010331
+ field public static final int statusBarColor = 16843861; // 0x1010455
field public static final int stepSize = 16843078; // 0x1010146
field public static final int stopWithTask = 16843626; // 0x101036a
field public static final int streamType = 16843273; // 0x1010209
@@ -1092,7 +1096,7 @@
field public static final int strokeOpacity = 16843811; // 0x1010423
field public static final int strokeWidth = 16843812; // 0x1010424
field public static final int subtitle = 16843473; // 0x10102d1
- field public static final int subtitleTextAppearance = 16843829; // 0x1010435
+ field public static final int subtitleTextAppearance = 16843827; // 0x1010433
field public static final int subtitleTextStyle = 16843513; // 0x10102f9
field public static final int subtypeExtraValue = 16843674; // 0x101039a
field public static final int subtypeId = 16843713; // 0x10103c1
@@ -1109,7 +1113,7 @@
field public static final int switchMinWidth = 16843632; // 0x1010370
field public static final int switchPadding = 16843633; // 0x1010371
field public static final int switchPreferenceStyle = 16843629; // 0x101036d
- field public static final int switchStyle = 16843846; // 0x1010446
+ field public static final int switchStyle = 16843844; // 0x1010444
field public static final int switchTextAppearance = 16843630; // 0x101036e
field public static final int switchTextOff = 16843628; // 0x101036c
field public static final int switchTextOn = 16843627; // 0x101036b
@@ -1125,6 +1129,7 @@
field public static final int targetId = 16843740; // 0x10103dc
field public static final int targetPackage = 16842785; // 0x1010021
field public static final int targetSdkVersion = 16843376; // 0x1010270
+ field public static final int targetViewName = 16843857; // 0x1010451
field public static final int taskAffinity = 16842770; // 0x1010012
field public static final int taskCloseEnterAnimation = 16842942; // 0x10100be
field public static final int taskCloseExitAnimation = 16842943; // 0x10100bf
@@ -1146,7 +1151,7 @@
field public static final int textAppearanceLargeInverse = 16842819; // 0x1010043
field public static final int textAppearanceLargePopupMenu = 16843521; // 0x1010301
field public static final int textAppearanceListItem = 16843678; // 0x101039e
- field public static final int textAppearanceListItemSecondary = 16843832; // 0x1010438
+ field public static final int textAppearanceListItemSecondary = 16843830; // 0x1010436
field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
field public static final int textAppearanceMedium = 16842817; // 0x1010041
field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
@@ -1210,10 +1215,11 @@
field public static final int tintMode = 16843798; // 0x1010416
field public static final int title = 16843233; // 0x10101e1
field public static final int titleCondensed = 16843234; // 0x10101e2
- field public static final int titleTextAppearance = 16843828; // 0x1010434
+ field public static final int titleTextAppearance = 16843826; // 0x1010432
field public static final int titleTextStyle = 16843512; // 0x10102f8
field public static final int toAlpha = 16843211; // 0x10101cb
field public static final int toDegrees = 16843188; // 0x10101b4
+ field public static final int toId = 16843853; // 0x101044d
field public static final int toScene = 16843742; // 0x10103de
field public static final int toXDelta = 16843207; // 0x10101c7
field public static final int toXScale = 16843203; // 0x10101c3
@@ -1262,6 +1268,7 @@
field public static final int verticalGap = 16843328; // 0x1010240
field public static final int verticalScrollbarPosition = 16843572; // 0x1010334
field public static final int verticalSpacing = 16843029; // 0x1010115
+ field public static final int viewName = 16843803; // 0x101041b
field public static final int viewportHeight = 16843806; // 0x101041e
field public static final int viewportWidth = 16843805; // 0x101041d
field public static final int visibility = 16842972; // 0x10100dc
@@ -1292,8 +1299,8 @@
field public static final int windowActionBar = 16843469; // 0x10102cd
field public static final int windowActionBarOverlay = 16843492; // 0x10102e4
field public static final int windowActionModeOverlay = 16843485; // 0x10102dd
- field public static final int windowAllowEnterTransitionOverlap = 16843843; // 0x1010443
- field public static final int windowAllowExitTransitionOverlap = 16843842; // 0x1010442
+ field public static final int windowAllowEnterTransitionOverlap = 16843841; // 0x1010441
+ field public static final int windowAllowExitTransitionOverlap = 16843840; // 0x1010440
field public static final int windowAnimationStyle = 16842926; // 0x10100ae
field public static final int windowBackground = 16842836; // 0x1010054
field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
@@ -1301,11 +1308,12 @@
field public static final int windowContentTransitionManager = 16843796; // 0x1010414
field public static final int windowContentTransitions = 16843795; // 0x1010413
field public static final int windowDisablePreview = 16843298; // 0x1010222
+ field public static final int windowDrawsSystemBarBackgrounds = 16843860; // 0x1010454
field public static final int windowEnableSplitTouch = 16843543; // 0x1010317
field public static final int windowEnterAnimation = 16842932; // 0x10100b4
- field public static final int windowEnterTransition = 16843838; // 0x101043e
+ field public static final int windowEnterTransition = 16843836; // 0x101043c
field public static final int windowExitAnimation = 16842933; // 0x10100b5
- field public static final int windowExitTransition = 16843839; // 0x101043f
+ field public static final int windowExitTransition = 16843837; // 0x101043d
field public static final int windowFrame = 16842837; // 0x1010055
field public static final int windowFullscreen = 16843277; // 0x101020d
field public static final int windowHideAnimation = 16842935; // 0x10100b7
@@ -1316,8 +1324,8 @@
field public static final int windowNoDisplay = 16843294; // 0x101021e
field public static final int windowNoTitle = 16842838; // 0x1010056
field public static final int windowOverscan = 16843727; // 0x10103cf
- field public static final int windowSharedElementEnterTransition = 16843840; // 0x1010440
- field public static final int windowSharedElementExitTransition = 16843841; // 0x1010441
+ field public static final int windowSharedElementEnterTransition = 16843838; // 0x101043e
+ field public static final int windowSharedElementExitTransition = 16843839; // 0x101043f
field public static final int windowShowAnimation = 16842934; // 0x10100b6
field public static final int windowShowWallpaper = 16843410; // 0x1010292
field public static final int windowSoftInputMode = 16843307; // 0x101022b
@@ -1623,7 +1631,7 @@
field public static final int l_resource_pad8 = 16908345; // 0x1020039
field public static final int l_resource_pad9 = 16908344; // 0x1020038
field public static final int list = 16908298; // 0x102000a
- field public static final int mask = 16908354; // 0x1020042
+ field public static final int mask = 16908353; // 0x1020041
field public static final int message = 16908299; // 0x102000b
field public static final int paste = 16908322; // 0x1020022
field public static final int primary = 16908300; // 0x102000c
@@ -1632,8 +1640,7 @@
field public static final int selectAll = 16908319; // 0x102001f
field public static final int selectTextMode = 16908333; // 0x102002d
field public static final int selectedIcon = 16908302; // 0x102000e
- field public static final int shared_element = 16908355; // 0x1020043
- field public static final int shared_element_name = 16908353; // 0x1020041
+ field public static final int shared_element = 16908354; // 0x1020042
field public static final int startSelectingText = 16908328; // 0x1020028
field public static final int stopSelectingText = 16908329; // 0x1020029
field public static final int summary = 16908304; // 0x1020010
@@ -1856,28 +1863,28 @@
field public static final int TextAppearance_Medium = 16973892; // 0x1030044
field public static final int TextAppearance_Medium_Inverse = 16973893; // 0x1030045
field public static final int TextAppearance_Quantum = 16974352; // 0x1030210
- field public static final int TextAppearance_Quantum_Body1 = 16974544; // 0x10302d0
- field public static final int TextAppearance_Quantum_Body2 = 16974543; // 0x10302cf
- field public static final int TextAppearance_Quantum_Button = 16974547; // 0x10302d3
- field public static final int TextAppearance_Quantum_Caption = 16974545; // 0x10302d1
+ field public static final int TextAppearance_Quantum_Body1 = 16974549; // 0x10302d5
+ field public static final int TextAppearance_Quantum_Body2 = 16974548; // 0x10302d4
+ field public static final int TextAppearance_Quantum_Button = 16974552; // 0x10302d8
+ field public static final int TextAppearance_Quantum_Caption = 16974550; // 0x10302d6
field public static final int TextAppearance_Quantum_DialogWindowTitle = 16974353; // 0x1030211
- field public static final int TextAppearance_Quantum_Display1 = 16974539; // 0x10302cb
- field public static final int TextAppearance_Quantum_Display2 = 16974538; // 0x10302ca
- field public static final int TextAppearance_Quantum_Display3 = 16974537; // 0x10302c9
- field public static final int TextAppearance_Quantum_Display4 = 16974536; // 0x10302c8
- field public static final int TextAppearance_Quantum_Headline = 16974540; // 0x10302cc
+ field public static final int TextAppearance_Quantum_Display1 = 16974544; // 0x10302d0
+ field public static final int TextAppearance_Quantum_Display2 = 16974543; // 0x10302cf
+ field public static final int TextAppearance_Quantum_Display3 = 16974542; // 0x10302ce
+ field public static final int TextAppearance_Quantum_Display4 = 16974541; // 0x10302cd
+ field public static final int TextAppearance_Quantum_Headline = 16974545; // 0x10302d1
field public static final int TextAppearance_Quantum_Inverse = 16974354; // 0x1030212
field public static final int TextAppearance_Quantum_Large = 16974355; // 0x1030213
field public static final int TextAppearance_Quantum_Large_Inverse = 16974356; // 0x1030214
field public static final int TextAppearance_Quantum_Medium = 16974357; // 0x1030215
field public static final int TextAppearance_Quantum_Medium_Inverse = 16974358; // 0x1030216
- field public static final int TextAppearance_Quantum_Menu = 16974546; // 0x10302d2
+ field public static final int TextAppearance_Quantum_Menu = 16974551; // 0x10302d7
field public static final int TextAppearance_Quantum_SearchResult_Subtitle = 16974359; // 0x1030217
field public static final int TextAppearance_Quantum_SearchResult_Title = 16974360; // 0x1030218
field public static final int TextAppearance_Quantum_Small = 16974361; // 0x1030219
field public static final int TextAppearance_Quantum_Small_Inverse = 16974362; // 0x103021a
- field public static final int TextAppearance_Quantum_Subhead = 16974542; // 0x10302ce
- field public static final int TextAppearance_Quantum_Title = 16974541; // 0x10302cd
+ field public static final int TextAppearance_Quantum_Subhead = 16974547; // 0x10302d3
+ field public static final int TextAppearance_Quantum_Title = 16974546; // 0x10302d2
field public static final int TextAppearance_Quantum_Widget = 16974364; // 0x103021c
field public static final int TextAppearance_Quantum_Widget_ActionBar_Menu = 16974365; // 0x103021d
field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle = 16974366; // 0x103021e
@@ -1924,6 +1931,11 @@
field public static final int TextAppearance_Widget_TextView_SpinnerItem = 16973906; // 0x1030052
field public static final int TextAppearance_WindowTitle = 16973907; // 0x1030053
field public static final int Theme = 16973829; // 0x1030005
+ field public static final int ThemeOverlay = 16974414; // 0x103024e
+ field public static final int ThemeOverlay_Quantum = 16974415; // 0x103024f
+ field public static final int ThemeOverlay_Quantum_ActionBarWidget = 16974418; // 0x1030252
+ field public static final int ThemeOverlay_Quantum_Dark = 16974417; // 0x1030251
+ field public static final int ThemeOverlay_Quantum_Light = 16974416; // 0x1030250
field public static final int Theme_Black = 16973832; // 0x1030008
field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a
@@ -2315,128 +2327,128 @@
field public static final int Widget_ProgressBar_Large_Inverse = 16973916; // 0x103005c
field public static final int Widget_ProgressBar_Small = 16973854; // 0x103001e
field public static final int Widget_ProgressBar_Small_Inverse = 16973917; // 0x103005d
- field public static final int Widget_Quantum = 16974414; // 0x103024e
- field public static final int Widget_Quantum_ActionBar = 16974415; // 0x103024f
- field public static final int Widget_Quantum_ActionBar_Solid = 16974416; // 0x1030250
- field public static final int Widget_Quantum_ActionBar_TabBar = 16974417; // 0x1030251
- field public static final int Widget_Quantum_ActionBar_TabText = 16974418; // 0x1030252
- field public static final int Widget_Quantum_ActionBar_TabView = 16974419; // 0x1030253
- field public static final int Widget_Quantum_ActionButton = 16974420; // 0x1030254
- field public static final int Widget_Quantum_ActionButton_CloseMode = 16974421; // 0x1030255
- field public static final int Widget_Quantum_ActionButton_Overflow = 16974422; // 0x1030256
- field public static final int Widget_Quantum_ActionMode = 16974423; // 0x1030257
- field public static final int Widget_Quantum_AutoCompleteTextView = 16974424; // 0x1030258
- field public static final int Widget_Quantum_Button = 16974425; // 0x1030259
- field public static final int Widget_Quantum_ButtonBar = 16974431; // 0x103025f
- field public static final int Widget_Quantum_ButtonBar_AlertDialog = 16974432; // 0x1030260
- field public static final int Widget_Quantum_Button_Borderless = 16974426; // 0x103025a
- field public static final int Widget_Quantum_Button_Borderless_Small = 16974427; // 0x103025b
- field public static final int Widget_Quantum_Button_Inset = 16974428; // 0x103025c
- field public static final int Widget_Quantum_Button_Small = 16974429; // 0x103025d
- field public static final int Widget_Quantum_Button_Toggle = 16974430; // 0x103025e
- field public static final int Widget_Quantum_CalendarView = 16974433; // 0x1030261
- field public static final int Widget_Quantum_CheckedTextView = 16974434; // 0x1030262
- field public static final int Widget_Quantum_CompoundButton_CheckBox = 16974435; // 0x1030263
- field public static final int Widget_Quantum_CompoundButton_RadioButton = 16974436; // 0x1030264
- field public static final int Widget_Quantum_CompoundButton_Star = 16974437; // 0x1030265
- field public static final int Widget_Quantum_DatePicker = 16974438; // 0x1030266
- field public static final int Widget_Quantum_DropDownItem = 16974439; // 0x1030267
- field public static final int Widget_Quantum_DropDownItem_Spinner = 16974440; // 0x1030268
- field public static final int Widget_Quantum_EditText = 16974441; // 0x1030269
- field public static final int Widget_Quantum_ExpandableListView = 16974442; // 0x103026a
- field public static final int Widget_Quantum_FastScroll = 16974443; // 0x103026b
- field public static final int Widget_Quantum_FragmentBreadCrumbs = 16974444; // 0x103026c
- field public static final int Widget_Quantum_GridView = 16974445; // 0x103026d
- field public static final int Widget_Quantum_HorizontalScrollView = 16974446; // 0x103026e
- field public static final int Widget_Quantum_ImageButton = 16974447; // 0x103026f
- field public static final int Widget_Quantum_Light = 16974474; // 0x103028a
- field public static final int Widget_Quantum_Light_ActionBar = 16974475; // 0x103028b
- field public static final int Widget_Quantum_Light_ActionBar_Solid = 16974476; // 0x103028c
- field public static final int Widget_Quantum_Light_ActionBar_TabBar = 16974477; // 0x103028d
- field public static final int Widget_Quantum_Light_ActionBar_TabText = 16974478; // 0x103028e
- field public static final int Widget_Quantum_Light_ActionBar_TabView = 16974479; // 0x103028f
- field public static final int Widget_Quantum_Light_ActionButton = 16974480; // 0x1030290
- field public static final int Widget_Quantum_Light_ActionButton_CloseMode = 16974481; // 0x1030291
- field public static final int Widget_Quantum_Light_ActionButton_Overflow = 16974482; // 0x1030292
- field public static final int Widget_Quantum_Light_ActionMode = 16974483; // 0x1030293
- field public static final int Widget_Quantum_Light_AutoCompleteTextView = 16974484; // 0x1030294
- field public static final int Widget_Quantum_Light_Button = 16974485; // 0x1030295
- field public static final int Widget_Quantum_Light_ButtonBar = 16974491; // 0x103029b
- field public static final int Widget_Quantum_Light_ButtonBar_AlertDialog = 16974492; // 0x103029c
- field public static final int Widget_Quantum_Light_Button_Borderless = 16974486; // 0x1030296
- field public static final int Widget_Quantum_Light_Button_Borderless_Small = 16974487; // 0x1030297
- field public static final int Widget_Quantum_Light_Button_Inset = 16974488; // 0x1030298
- field public static final int Widget_Quantum_Light_Button_Small = 16974489; // 0x1030299
- field public static final int Widget_Quantum_Light_Button_Toggle = 16974490; // 0x103029a
- field public static final int Widget_Quantum_Light_CalendarView = 16974493; // 0x103029d
- field public static final int Widget_Quantum_Light_CheckedTextView = 16974494; // 0x103029e
- field public static final int Widget_Quantum_Light_CompoundButton_CheckBox = 16974495; // 0x103029f
- field public static final int Widget_Quantum_Light_CompoundButton_RadioButton = 16974496; // 0x10302a0
- field public static final int Widget_Quantum_Light_CompoundButton_Star = 16974497; // 0x10302a1
- field public static final int Widget_Quantum_Light_DropDownItem = 16974498; // 0x10302a2
- field public static final int Widget_Quantum_Light_DropDownItem_Spinner = 16974499; // 0x10302a3
- field public static final int Widget_Quantum_Light_EditText = 16974500; // 0x10302a4
- field public static final int Widget_Quantum_Light_ExpandableListView = 16974501; // 0x10302a5
- field public static final int Widget_Quantum_Light_FastScroll = 16974502; // 0x10302a6
- field public static final int Widget_Quantum_Light_FragmentBreadCrumbs = 16974503; // 0x10302a7
- field public static final int Widget_Quantum_Light_GridView = 16974504; // 0x10302a8
- field public static final int Widget_Quantum_Light_HorizontalScrollView = 16974505; // 0x10302a9
- field public static final int Widget_Quantum_Light_ImageButton = 16974506; // 0x10302aa
- field public static final int Widget_Quantum_Light_ListPopupWindow = 16974507; // 0x10302ab
- field public static final int Widget_Quantum_Light_ListView = 16974508; // 0x10302ac
- field public static final int Widget_Quantum_Light_ListView_DropDown = 16974509; // 0x10302ad
- field public static final int Widget_Quantum_Light_MediaRouteButton = 16974510; // 0x10302ae
- field public static final int Widget_Quantum_Light_PopupMenu = 16974511; // 0x10302af
- field public static final int Widget_Quantum_Light_PopupMenu_Overflow = 16974512; // 0x10302b0
- field public static final int Widget_Quantum_Light_PopupWindow = 16974513; // 0x10302b1
- field public static final int Widget_Quantum_Light_ProgressBar = 16974514; // 0x10302b2
- field public static final int Widget_Quantum_Light_ProgressBar_Horizontal = 16974515; // 0x10302b3
- field public static final int Widget_Quantum_Light_ProgressBar_Inverse = 16974516; // 0x10302b4
- field public static final int Widget_Quantum_Light_ProgressBar_Large = 16974517; // 0x10302b5
- field public static final int Widget_Quantum_Light_ProgressBar_Large_Inverse = 16974518; // 0x10302b6
- field public static final int Widget_Quantum_Light_ProgressBar_Small = 16974519; // 0x10302b7
- field public static final int Widget_Quantum_Light_ProgressBar_Small_Inverse = 16974520; // 0x10302b8
- field public static final int Widget_Quantum_Light_ProgressBar_Small_Title = 16974521; // 0x10302b9
- field public static final int Widget_Quantum_Light_RatingBar = 16974522; // 0x10302ba
- field public static final int Widget_Quantum_Light_RatingBar_Indicator = 16974523; // 0x10302bb
- field public static final int Widget_Quantum_Light_RatingBar_Small = 16974524; // 0x10302bc
- field public static final int Widget_Quantum_Light_ScrollView = 16974525; // 0x10302bd
- field public static final int Widget_Quantum_Light_SeekBar = 16974526; // 0x10302be
- field public static final int Widget_Quantum_Light_SegmentedButton = 16974527; // 0x10302bf
- field public static final int Widget_Quantum_Light_Spinner = 16974529; // 0x10302c1
- field public static final int Widget_Quantum_Light_StackView = 16974528; // 0x10302c0
- field public static final int Widget_Quantum_Light_Tab = 16974530; // 0x10302c2
- field public static final int Widget_Quantum_Light_TabWidget = 16974531; // 0x10302c3
- field public static final int Widget_Quantum_Light_TextView = 16974532; // 0x10302c4
- field public static final int Widget_Quantum_Light_TextView_SpinnerItem = 16974533; // 0x10302c5
- field public static final int Widget_Quantum_Light_WebTextView = 16974534; // 0x10302c6
- field public static final int Widget_Quantum_Light_WebView = 16974535; // 0x10302c7
- field public static final int Widget_Quantum_ListPopupWindow = 16974448; // 0x1030270
- field public static final int Widget_Quantum_ListView = 16974449; // 0x1030271
- field public static final int Widget_Quantum_ListView_DropDown = 16974450; // 0x1030272
- field public static final int Widget_Quantum_MediaRouteButton = 16974451; // 0x1030273
- field public static final int Widget_Quantum_PopupMenu = 16974452; // 0x1030274
- field public static final int Widget_Quantum_PopupMenu_Overflow = 16974453; // 0x1030275
- field public static final int Widget_Quantum_PopupWindow = 16974454; // 0x1030276
- field public static final int Widget_Quantum_ProgressBar = 16974455; // 0x1030277
- field public static final int Widget_Quantum_ProgressBar_Horizontal = 16974456; // 0x1030278
- field public static final int Widget_Quantum_ProgressBar_Large = 16974457; // 0x1030279
- field public static final int Widget_Quantum_ProgressBar_Small = 16974458; // 0x103027a
- field public static final int Widget_Quantum_ProgressBar_Small_Title = 16974459; // 0x103027b
- field public static final int Widget_Quantum_RatingBar = 16974460; // 0x103027c
- field public static final int Widget_Quantum_RatingBar_Indicator = 16974461; // 0x103027d
- field public static final int Widget_Quantum_RatingBar_Small = 16974462; // 0x103027e
- field public static final int Widget_Quantum_ScrollView = 16974463; // 0x103027f
- field public static final int Widget_Quantum_SeekBar = 16974464; // 0x1030280
- field public static final int Widget_Quantum_SegmentedButton = 16974465; // 0x1030281
- field public static final int Widget_Quantum_Spinner = 16974467; // 0x1030283
- field public static final int Widget_Quantum_StackView = 16974466; // 0x1030282
- field public static final int Widget_Quantum_Tab = 16974468; // 0x1030284
- field public static final int Widget_Quantum_TabWidget = 16974469; // 0x1030285
- field public static final int Widget_Quantum_TextView = 16974470; // 0x1030286
- field public static final int Widget_Quantum_TextView_SpinnerItem = 16974471; // 0x1030287
- field public static final int Widget_Quantum_WebTextView = 16974472; // 0x1030288
- field public static final int Widget_Quantum_WebView = 16974473; // 0x1030289
+ field public static final int Widget_Quantum = 16974419; // 0x1030253
+ field public static final int Widget_Quantum_ActionBar = 16974420; // 0x1030254
+ field public static final int Widget_Quantum_ActionBar_Solid = 16974421; // 0x1030255
+ field public static final int Widget_Quantum_ActionBar_TabBar = 16974422; // 0x1030256
+ field public static final int Widget_Quantum_ActionBar_TabText = 16974423; // 0x1030257
+ field public static final int Widget_Quantum_ActionBar_TabView = 16974424; // 0x1030258
+ field public static final int Widget_Quantum_ActionButton = 16974425; // 0x1030259
+ field public static final int Widget_Quantum_ActionButton_CloseMode = 16974426; // 0x103025a
+ field public static final int Widget_Quantum_ActionButton_Overflow = 16974427; // 0x103025b
+ field public static final int Widget_Quantum_ActionMode = 16974428; // 0x103025c
+ field public static final int Widget_Quantum_AutoCompleteTextView = 16974429; // 0x103025d
+ field public static final int Widget_Quantum_Button = 16974430; // 0x103025e
+ field public static final int Widget_Quantum_ButtonBar = 16974436; // 0x1030264
+ field public static final int Widget_Quantum_ButtonBar_AlertDialog = 16974437; // 0x1030265
+ field public static final int Widget_Quantum_Button_Borderless = 16974431; // 0x103025f
+ field public static final int Widget_Quantum_Button_Borderless_Small = 16974432; // 0x1030260
+ field public static final int Widget_Quantum_Button_Inset = 16974433; // 0x1030261
+ field public static final int Widget_Quantum_Button_Small = 16974434; // 0x1030262
+ field public static final int Widget_Quantum_Button_Toggle = 16974435; // 0x1030263
+ field public static final int Widget_Quantum_CalendarView = 16974438; // 0x1030266
+ field public static final int Widget_Quantum_CheckedTextView = 16974439; // 0x1030267
+ field public static final int Widget_Quantum_CompoundButton_CheckBox = 16974440; // 0x1030268
+ field public static final int Widget_Quantum_CompoundButton_RadioButton = 16974441; // 0x1030269
+ field public static final int Widget_Quantum_CompoundButton_Star = 16974442; // 0x103026a
+ field public static final int Widget_Quantum_DatePicker = 16974443; // 0x103026b
+ field public static final int Widget_Quantum_DropDownItem = 16974444; // 0x103026c
+ field public static final int Widget_Quantum_DropDownItem_Spinner = 16974445; // 0x103026d
+ field public static final int Widget_Quantum_EditText = 16974446; // 0x103026e
+ field public static final int Widget_Quantum_ExpandableListView = 16974447; // 0x103026f
+ field public static final int Widget_Quantum_FastScroll = 16974448; // 0x1030270
+ field public static final int Widget_Quantum_FragmentBreadCrumbs = 16974449; // 0x1030271
+ field public static final int Widget_Quantum_GridView = 16974450; // 0x1030272
+ field public static final int Widget_Quantum_HorizontalScrollView = 16974451; // 0x1030273
+ field public static final int Widget_Quantum_ImageButton = 16974452; // 0x1030274
+ field public static final int Widget_Quantum_Light = 16974479; // 0x103028f
+ field public static final int Widget_Quantum_Light_ActionBar = 16974480; // 0x1030290
+ field public static final int Widget_Quantum_Light_ActionBar_Solid = 16974481; // 0x1030291
+ field public static final int Widget_Quantum_Light_ActionBar_TabBar = 16974482; // 0x1030292
+ field public static final int Widget_Quantum_Light_ActionBar_TabText = 16974483; // 0x1030293
+ field public static final int Widget_Quantum_Light_ActionBar_TabView = 16974484; // 0x1030294
+ field public static final int Widget_Quantum_Light_ActionButton = 16974485; // 0x1030295
+ field public static final int Widget_Quantum_Light_ActionButton_CloseMode = 16974486; // 0x1030296
+ field public static final int Widget_Quantum_Light_ActionButton_Overflow = 16974487; // 0x1030297
+ field public static final int Widget_Quantum_Light_ActionMode = 16974488; // 0x1030298
+ field public static final int Widget_Quantum_Light_AutoCompleteTextView = 16974489; // 0x1030299
+ field public static final int Widget_Quantum_Light_Button = 16974490; // 0x103029a
+ field public static final int Widget_Quantum_Light_ButtonBar = 16974496; // 0x10302a0
+ field public static final int Widget_Quantum_Light_ButtonBar_AlertDialog = 16974497; // 0x10302a1
+ field public static final int Widget_Quantum_Light_Button_Borderless = 16974491; // 0x103029b
+ field public static final int Widget_Quantum_Light_Button_Borderless_Small = 16974492; // 0x103029c
+ field public static final int Widget_Quantum_Light_Button_Inset = 16974493; // 0x103029d
+ field public static final int Widget_Quantum_Light_Button_Small = 16974494; // 0x103029e
+ field public static final int Widget_Quantum_Light_Button_Toggle = 16974495; // 0x103029f
+ field public static final int Widget_Quantum_Light_CalendarView = 16974498; // 0x10302a2
+ field public static final int Widget_Quantum_Light_CheckedTextView = 16974499; // 0x10302a3
+ field public static final int Widget_Quantum_Light_CompoundButton_CheckBox = 16974500; // 0x10302a4
+ field public static final int Widget_Quantum_Light_CompoundButton_RadioButton = 16974501; // 0x10302a5
+ field public static final int Widget_Quantum_Light_CompoundButton_Star = 16974502; // 0x10302a6
+ field public static final int Widget_Quantum_Light_DropDownItem = 16974503; // 0x10302a7
+ field public static final int Widget_Quantum_Light_DropDownItem_Spinner = 16974504; // 0x10302a8
+ field public static final int Widget_Quantum_Light_EditText = 16974505; // 0x10302a9
+ field public static final int Widget_Quantum_Light_ExpandableListView = 16974506; // 0x10302aa
+ field public static final int Widget_Quantum_Light_FastScroll = 16974507; // 0x10302ab
+ field public static final int Widget_Quantum_Light_FragmentBreadCrumbs = 16974508; // 0x10302ac
+ field public static final int Widget_Quantum_Light_GridView = 16974509; // 0x10302ad
+ field public static final int Widget_Quantum_Light_HorizontalScrollView = 16974510; // 0x10302ae
+ field public static final int Widget_Quantum_Light_ImageButton = 16974511; // 0x10302af
+ field public static final int Widget_Quantum_Light_ListPopupWindow = 16974512; // 0x10302b0
+ field public static final int Widget_Quantum_Light_ListView = 16974513; // 0x10302b1
+ field public static final int Widget_Quantum_Light_ListView_DropDown = 16974514; // 0x10302b2
+ field public static final int Widget_Quantum_Light_MediaRouteButton = 16974515; // 0x10302b3
+ field public static final int Widget_Quantum_Light_PopupMenu = 16974516; // 0x10302b4
+ field public static final int Widget_Quantum_Light_PopupMenu_Overflow = 16974517; // 0x10302b5
+ field public static final int Widget_Quantum_Light_PopupWindow = 16974518; // 0x10302b6
+ field public static final int Widget_Quantum_Light_ProgressBar = 16974519; // 0x10302b7
+ field public static final int Widget_Quantum_Light_ProgressBar_Horizontal = 16974520; // 0x10302b8
+ field public static final int Widget_Quantum_Light_ProgressBar_Inverse = 16974521; // 0x10302b9
+ field public static final int Widget_Quantum_Light_ProgressBar_Large = 16974522; // 0x10302ba
+ field public static final int Widget_Quantum_Light_ProgressBar_Large_Inverse = 16974523; // 0x10302bb
+ field public static final int Widget_Quantum_Light_ProgressBar_Small = 16974524; // 0x10302bc
+ field public static final int Widget_Quantum_Light_ProgressBar_Small_Inverse = 16974525; // 0x10302bd
+ field public static final int Widget_Quantum_Light_ProgressBar_Small_Title = 16974526; // 0x10302be
+ field public static final int Widget_Quantum_Light_RatingBar = 16974527; // 0x10302bf
+ field public static final int Widget_Quantum_Light_RatingBar_Indicator = 16974528; // 0x10302c0
+ field public static final int Widget_Quantum_Light_RatingBar_Small = 16974529; // 0x10302c1
+ field public static final int Widget_Quantum_Light_ScrollView = 16974530; // 0x10302c2
+ field public static final int Widget_Quantum_Light_SeekBar = 16974531; // 0x10302c3
+ field public static final int Widget_Quantum_Light_SegmentedButton = 16974532; // 0x10302c4
+ field public static final int Widget_Quantum_Light_Spinner = 16974534; // 0x10302c6
+ field public static final int Widget_Quantum_Light_StackView = 16974533; // 0x10302c5
+ field public static final int Widget_Quantum_Light_Tab = 16974535; // 0x10302c7
+ field public static final int Widget_Quantum_Light_TabWidget = 16974536; // 0x10302c8
+ field public static final int Widget_Quantum_Light_TextView = 16974537; // 0x10302c9
+ field public static final int Widget_Quantum_Light_TextView_SpinnerItem = 16974538; // 0x10302ca
+ field public static final int Widget_Quantum_Light_WebTextView = 16974539; // 0x10302cb
+ field public static final int Widget_Quantum_Light_WebView = 16974540; // 0x10302cc
+ field public static final int Widget_Quantum_ListPopupWindow = 16974453; // 0x1030275
+ field public static final int Widget_Quantum_ListView = 16974454; // 0x1030276
+ field public static final int Widget_Quantum_ListView_DropDown = 16974455; // 0x1030277
+ field public static final int Widget_Quantum_MediaRouteButton = 16974456; // 0x1030278
+ field public static final int Widget_Quantum_PopupMenu = 16974457; // 0x1030279
+ field public static final int Widget_Quantum_PopupMenu_Overflow = 16974458; // 0x103027a
+ field public static final int Widget_Quantum_PopupWindow = 16974459; // 0x103027b
+ field public static final int Widget_Quantum_ProgressBar = 16974460; // 0x103027c
+ field public static final int Widget_Quantum_ProgressBar_Horizontal = 16974461; // 0x103027d
+ field public static final int Widget_Quantum_ProgressBar_Large = 16974462; // 0x103027e
+ field public static final int Widget_Quantum_ProgressBar_Small = 16974463; // 0x103027f
+ field public static final int Widget_Quantum_ProgressBar_Small_Title = 16974464; // 0x1030280
+ field public static final int Widget_Quantum_RatingBar = 16974465; // 0x1030281
+ field public static final int Widget_Quantum_RatingBar_Indicator = 16974466; // 0x1030282
+ field public static final int Widget_Quantum_RatingBar_Small = 16974467; // 0x1030283
+ field public static final int Widget_Quantum_ScrollView = 16974468; // 0x1030284
+ field public static final int Widget_Quantum_SeekBar = 16974469; // 0x1030285
+ field public static final int Widget_Quantum_SegmentedButton = 16974470; // 0x1030286
+ field public static final int Widget_Quantum_Spinner = 16974472; // 0x1030288
+ field public static final int Widget_Quantum_StackView = 16974471; // 0x1030287
+ field public static final int Widget_Quantum_Tab = 16974473; // 0x1030289
+ field public static final int Widget_Quantum_TabWidget = 16974474; // 0x103028a
+ field public static final int Widget_Quantum_TextView = 16974475; // 0x103028b
+ field public static final int Widget_Quantum_TextView_SpinnerItem = 16974476; // 0x103028c
+ field public static final int Widget_Quantum_WebTextView = 16974477; // 0x103028d
+ field public static final int Widget_Quantum_WebView = 16974478; // 0x103028e
field public static final int Widget_RatingBar = 16973857; // 0x1030021
field public static final int Widget_ScrollView = 16973869; // 0x103002d
field public static final int Widget_SeekBar = 16973856; // 0x1030020
@@ -3248,6 +3260,7 @@
method public boolean navigateUpToFromChild(android.app.Activity, android.content.Intent);
method public void onActionModeFinished(android.view.ActionMode);
method public void onActionModeStarted(android.view.ActionMode);
+ method protected void onActivityReenter(int, android.content.Intent);
method protected void onActivityResult(int, int, android.content.Intent);
method public void onAttachFragment(android.app.Fragment);
method public void onAttachedToWindow();
@@ -3258,6 +3271,7 @@
method public boolean onContextItemSelected(android.view.MenuItem);
method public void onContextMenuClosed(android.view.Menu);
method protected void onCreate(android.os.Bundle);
+ method protected void onCreate(android.os.Bundle, android.os.PersistableBundle);
method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
method public java.lang.CharSequence onCreateDescription();
method protected deprecated android.app.Dialog onCreateDialog(int);
@@ -3288,6 +3302,7 @@
method public void onPanelClosed(int, android.view.Menu);
method protected void onPause();
method protected void onPostCreate(android.os.Bundle);
+ method protected void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
method protected void onPostResume();
method protected deprecated void onPrepareDialog(int, android.app.Dialog);
method protected deprecated void onPrepareDialog(int, android.app.Dialog, android.os.Bundle);
@@ -3297,9 +3312,11 @@
method public void onProvideAssistData(android.os.Bundle);
method protected void onRestart();
method protected void onRestoreInstanceState(android.os.Bundle);
+ method protected void onRestoreInstanceState(android.os.Bundle, android.os.PersistableBundle);
method protected void onResume();
method public deprecated java.lang.Object onRetainNonConfigurationInstance();
method protected void onSaveInstanceState(android.os.Bundle);
+ method protected void onSaveInstanceState(android.os.Bundle, android.os.PersistableBundle);
method public boolean onSearchRequested();
method protected void onStart();
method protected void onStop();
@@ -3322,7 +3339,6 @@
method public final boolean requestWindowFeature(int);
method public final void runOnUiThread(java.lang.Runnable);
method public void setActionBar(android.widget.Toolbar);
- method public void setActivityTransitionListener(android.app.ActivityOptions.ActivityTransitionListener);
method public void setContentTransitionManager(android.transition.TransitionManager);
method public void setContentView(int);
method public void setContentView(android.view.View);
@@ -3344,6 +3360,7 @@
method public final void setResult(int);
method public final void setResult(int, android.content.Intent);
method public final void setSecondaryProgress(int);
+ method public void setSharedElementListener(android.app.SharedElementListener);
method public void setTitle(java.lang.CharSequence);
method public void setTitle(int);
method public deprecated void setTitleColor(int);
@@ -3396,6 +3413,7 @@
public class ActivityManager {
method public boolean clearApplicationUserData();
method public void dumpPackageState(java.io.FileDescriptor, java.lang.String);
+ method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks();
method public android.content.pm.ConfigurationInfo getDeviceConfigurationInfo();
method public int getLargeMemoryClass();
method public int getLauncherLargeIconDensity();
@@ -3424,6 +3442,11 @@
field public static final int RECENT_WITH_EXCLUDED = 1; // 0x1
}
+ public static class ActivityManager.AppTask {
+ method public void finishAndRemoveTask();
+ method public android.app.ActivityManager.RecentTaskInfo getTaskInfo();
+ }
+
public static class ActivityManager.MemoryInfo implements android.os.Parcelable {
ctor public ActivityManager.MemoryInfo();
method public int describeContents();
@@ -3557,28 +3580,13 @@
public class ActivityOptions {
method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
method public static android.app.ActivityOptions makeScaleUpAnimation(android.view.View, int, int, int, int);
- method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.view.Window, android.view.View, java.lang.String);
- method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.view.Window, android.app.ActivityOptions.ActivityTransitionListener);
+ method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.app.Activity, android.view.View, java.lang.String);
+ method public static android.app.ActivityOptions makeSceneTransitionAnimation(android.app.Activity, android.util.Pair<android.view.View, java.lang.String>...);
method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
method public android.os.Bundle toBundle();
method public void update(android.app.ActivityOptions);
}
- public static class ActivityOptions.ActivityTransitionListener {
- ctor public ActivityOptions.ActivityTransitionListener();
- method public android.util.Pair<android.view.View, java.lang.String>[] getSharedElementsMapping();
- method public boolean handleRejectedSharedElements(java.util.List<android.view.View>);
- method public void onCaptureSharedElementEnd(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
- method public void onCaptureSharedElementStart(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
- method public void onEnterReady();
- method public void onExitTransitionComplete();
- method public void onRemoteExitComplete();
- method public void onSharedElementExitTransitionComplete();
- method public void onSharedElementTransferred(java.util.List<java.lang.String>, java.util.List<android.view.View>);
- method public void onStartEnterTransition(java.util.List<java.lang.String>, java.util.List<android.view.View>);
- method public void onStartExitTransition(java.util.List<java.lang.String>, java.util.List<android.view.View>);
- }
-
public class AlarmManager {
method public void cancel(android.app.PendingIntent);
method public void set(int, long, android.app.PendingIntent);
@@ -4195,14 +4203,18 @@
method public android.app.Instrumentation.ActivityMonitor addMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
method public android.app.Instrumentation.ActivityMonitor addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
method public void callActivityOnCreate(android.app.Activity, android.os.Bundle);
+ method public void callActivityOnCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
method public void callActivityOnDestroy(android.app.Activity);
method public void callActivityOnNewIntent(android.app.Activity, android.content.Intent);
method public void callActivityOnPause(android.app.Activity);
method public void callActivityOnPostCreate(android.app.Activity, android.os.Bundle);
+ method public void callActivityOnPostCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
method public void callActivityOnRestart(android.app.Activity);
method public void callActivityOnRestoreInstanceState(android.app.Activity, android.os.Bundle);
+ method public void callActivityOnRestoreInstanceState(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
method public void callActivityOnResume(android.app.Activity);
method public void callActivityOnSaveInstanceState(android.app.Activity, android.os.Bundle);
+ method public void callActivityOnSaveInstanceState(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
method public void callActivityOnStart(android.app.Activity);
method public void callActivityOnStop(android.app.Activity);
method public void callActivityOnUserLeaving(android.app.Activity);
@@ -4798,6 +4810,14 @@
field public static final int START_STICKY_COMPATIBILITY = 0; // 0x0
}
+ public class SharedElementListener {
+ ctor public SharedElementListener();
+ method public void handleRejectedSharedElements(java.util.List<android.view.View>);
+ method public void remapSharedElements(java.util.List<java.lang.String>, java.util.Map<java.lang.String, android.view.View>);
+ method public void setSharedElementEnd(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
+ method public void setSharedElementStart(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
+ }
+
public deprecated class TabActivity extends android.app.ActivityGroup {
ctor public TabActivity();
method public android.widget.TabHost getTabHost();
@@ -4838,6 +4858,7 @@
method public void clearWindowAnimationFrameStats();
method public boolean clearWindowContentFrameStats(int);
method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
+ method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
@@ -7600,7 +7621,7 @@
method public long getMaxExecutionDelayMillis();
method public long getMinLatencyMillis();
method public int getNetworkCapabilities();
- method public java.lang.String getServiceClassName();
+ method public android.content.ComponentName getService();
method public int getTaskId();
method public boolean isPeriodic();
method public boolean isRequireCharging();
@@ -7615,7 +7636,7 @@
}
public final class Task.Builder {
- ctor public Task.Builder(int, java.lang.Class<android.app.task.TaskService>);
+ ctor public Task.Builder(int, android.content.ComponentName);
method public android.content.Task build();
method public android.content.Task.Builder setBackoffCriteria(long, int);
method public android.content.Task.Builder setExtras(android.os.Bundle);
@@ -10099,6 +10120,7 @@
ctor public Matrix(android.graphics.Matrix);
method public void getValues(float[]);
method public boolean invert(android.graphics.Matrix);
+ method public boolean isAffine();
method public boolean isIdentity();
method public void mapPoints(float[], int, float[], int, int);
method public void mapPoints(float[], float[]);
@@ -10822,6 +10844,12 @@
method public abstract void stop();
}
+ public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
+ ctor public AnimatedStateListDrawable();
+ method public void addState(int[], android.graphics.drawable.Drawable, int);
+ method public void addTransition(int, int, android.graphics.drawable.AnimationDrawable, boolean);
+ }
+
public class AnimationDrawable extends android.graphics.drawable.DrawableContainer implements android.graphics.drawable.Animatable java.lang.Runnable {
ctor public AnimationDrawable();
method public void addFrame(android.graphics.drawable.Drawable, int);
@@ -11332,6 +11360,24 @@
method public android.graphics.pdf.PdfDocument.PageInfo.Builder setContentRect(android.graphics.Rect);
}
+ public final class PdfRenderer implements java.lang.AutoCloseable {
+ ctor public PdfRenderer(android.os.ParcelFileDescriptor) throws java.io.IOException;
+ method public void close();
+ method public void closePage(android.graphics.pdf.PdfRenderer.Page);
+ method public int getPageCount();
+ method public android.graphics.pdf.PdfRenderer.Page openPage(int);
+ method public boolean shouldScaleForPrinting();
+ }
+
+ public final class PdfRenderer.Page {
+ method public int getHeight();
+ method public int getIndex();
+ method public int getWidth();
+ method public void render(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Matrix, int);
+ field public static final int RENDER_MODE_FOR_DISPLAY = 1; // 0x1
+ field public static final int RENDER_MODE_FOR_PRINT = 2; // 0x2
+ }
+
}
package android.hardware {
@@ -11835,16 +11881,8 @@
field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_MAX_NUM_OUTPUT_STREAMS;
field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PARTIAL_RESULT_COUNT;
field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PIPELINE_MAX_DEPTH;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_FORMATS;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_JPEG_MIN_DURATIONS;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_JPEG_SIZES;
field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_PROCESSED_SIZES;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_STALL_DURATIONS;
- field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
+ field public static final android.hardware.camera2.CameraMetadata.Key SCALER_STREAM_CONFIGURATION_MAP;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_AVAILABLE_TEST_PATTERN_MODES;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_BASE_GAIN_FACTOR;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_BLACK_LEVEL_PATTERN;
@@ -12054,8 +12092,6 @@
field public static final int REQUEST_AVAILABLE_CAPABILITIES_DNG = 5; // 0x5
field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 2; // 0x2
field public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4; // 0x4
- field public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT = 1; // 0x1
- field public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT = 0; // 0x0
field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR = 3; // 0x3
field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG = 2; // 0x2
field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG = 1; // 0x1
@@ -12336,6 +12372,22 @@
method public final int getWidth();
}
+ public final class TonemapCurve {
+ method public void copyColorCurve(int, float[], int);
+ method public android.graphics.PointF getPoint(int, int);
+ method public int getPointCount(int);
+ field public static final int CHANNEL_BLUE = 2; // 0x2
+ field public static final int CHANNEL_GREEN = 1; // 0x1
+ field public static final int CHANNEL_RED = 0; // 0x0
+ field public static final float LEVEL_BLACK = 0.0f;
+ field public static final float LEVEL_WHITE = 1.0f;
+ field public static final int POINT_SIZE = 2; // 0x2
+ }
+
+}
+
+package android.hardware.camera2.params {
+
public final class StreamConfigurationMap {
method public final int[] getOutputFormats();
method public long getOutputMinFrameDuration(int, android.util.Size);
@@ -12349,18 +12401,6 @@
method public boolean isOutputSupportedFor(android.view.Surface);
}
- public final class TonemapCurve {
- method public void copyColorCurve(int, float[], int);
- method public android.graphics.PointF getPoint(int, int);
- method public int getPointCount(int);
- field public static final int CHANNEL_BLUE = 2; // 0x2
- field public static final int CHANNEL_GREEN = 1; // 0x1
- field public static final int CHANNEL_RED = 0; // 0x0
- field public static final float LEVEL_BLACK = 0.0f;
- field public static final float LEVEL_WHITE = 1.0f;
- field public static final int POINT_SIZE = 2; // 0x2
- }
-
}
package android.hardware.display {
@@ -13322,6 +13362,45 @@
method public void stop();
}
+ public final class AudioAttributes {
+ method public int getContentType();
+ method public int getFlags();
+ method public java.util.Set<java.lang.String> getTags();
+ method public int getUsage();
+ field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
+ field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
+ field public static final int CONTENT_TYPE_SONIFICATION = 4; // 0x4
+ field public static final int CONTENT_TYPE_SPEECH = 1; // 0x1
+ field public static final int CONTENT_TYPE_UNKNOWN = 0; // 0x0
+ field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
+ field public static final int USAGE_ALARM = 4; // 0x4
+ field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
+ field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
+ field public static final int USAGE_ASSISTANCE_SONIFICATION = 13; // 0xd
+ field public static final int USAGE_GAME = 14; // 0xe
+ field public static final int USAGE_MEDIA = 1; // 0x1
+ field public static final int USAGE_NOTIFICATION = 5; // 0x5
+ field public static final int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9; // 0x9
+ field public static final int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8; // 0x8
+ field public static final int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7; // 0x7
+ field public static final int USAGE_NOTIFICATION_EVENT = 10; // 0xa
+ field public static final int USAGE_NOTIFICATION_TELEPHONY_RINGTONE = 6; // 0x6
+ field public static final int USAGE_UNKNOWN = 0; // 0x0
+ field public static final int USAGE_VOICE_COMMUNICATION = 2; // 0x2
+ field public static final int USAGE_VOICE_COMMUNICATION_SIGNALLING = 3; // 0x3
+ }
+
+ public static class AudioAttributes.Builder {
+ ctor public AudioAttributes.Builder();
+ ctor public AudioAttributes.Builder(android.media.AudioAttributes);
+ method public android.media.AudioAttributes.Builder addTag(java.lang.String);
+ method public android.media.AudioAttributes build();
+ method public android.media.AudioAttributes.Builder setContentType(int);
+ method public android.media.AudioAttributes.Builder setFlags(int);
+ method public android.media.AudioAttributes.Builder setLegacyStreamType(int);
+ method public android.media.AudioAttributes.Builder setUsage(int);
+ }
+
public class AudioFormat {
ctor public AudioFormat();
field public static final deprecated int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1
@@ -13366,6 +13445,7 @@
field public static final int ENCODING_INVALID = 0; // 0x0
field public static final int ENCODING_PCM_16BIT = 2; // 0x2
field public static final int ENCODING_PCM_8BIT = 3; // 0x3
+ field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
}
public class AudioManager {
@@ -13583,6 +13663,7 @@
method public void stop() throws java.lang.IllegalStateException;
method public int write(byte[], int, int);
method public int write(short[], int, int);
+ method public int write(float[], int, int, int);
method public int write(java.nio.ByteBuffer, int, int);
field public static final int ERROR = -1; // 0xffffffff
field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
@@ -13815,6 +13896,7 @@
method public final void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
method public final void release();
method public final void releaseOutputBuffer(int, boolean);
+ method public final void releaseOutputBuffer(int, long);
method public void setNotificationCallback(android.media.MediaCodec.NotificationCallback);
method public final void setParameters(android.os.Bundle);
method public final void setVideoScalingMode(int);
@@ -19582,7 +19664,7 @@
field public static final int JELLY_BEAN_MR1 = 17; // 0x11
field public static final int JELLY_BEAN_MR2 = 18; // 0x12
field public static final int KITKAT = 19; // 0x13
- field public static final int KITKAT_WATCH = 10000; // 0x2710
+ field public static final int KITKAT_WATCH = 20; // 0x14
field public static final int L = 10000; // 0x2710
}
@@ -23437,6 +23519,7 @@
method public static boolean putLong(android.content.ContentResolver, java.lang.String, long);
method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
method public static final deprecated void setLocationProviderEnabled(android.content.ContentResolver, java.lang.String, boolean);
+ field public static final java.lang.String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED = "accessibility_display_inversion_enabled";
field public static final java.lang.String ACCESSIBILITY_ENABLED = "accessibility_enabled";
field public static final java.lang.String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
field public static final deprecated java.lang.String ADB_ENABLED = "adb_enabled";
@@ -23945,25 +24028,32 @@
}
public static abstract interface TvContract.BaseTvColumns implements android.provider.BaseColumns {
- field public static final java.lang.String PACKAGE_NAME = "package_name";
+ field public static final java.lang.String COLUMN_PACKAGE_NAME = "package_name";
}
public static final class TvContract.Channels implements android.provider.TvContract.BaseTvColumns {
- field public static final java.lang.String BROWSABLE = "browsable";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
+ field public static final java.lang.String COLUMN_DATA = "data";
+ field public static final java.lang.String COLUMN_DESCRIPTION = "description";
+ field public static final java.lang.String COLUMN_DISPLAY_NAME = "display_name";
+ field public static final java.lang.String COLUMN_DISPLAY_NUMBER = "display_number";
+ field public static final java.lang.String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
+ field public static final java.lang.String COLUMN_SERVICE_ID = "service_id";
+ field public static final java.lang.String COLUMN_SERVICE_NAME = "service_name";
+ field public static final java.lang.String COLUMN_SERVICE_TYPE = "service_type";
+ field public static final java.lang.String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
+ field public static final java.lang.String COLUMN_TYPE = "type";
+ field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.com.android.tv.channels";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.com.android.tv.channels";
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String DATA = "data";
- field public static final java.lang.String DESCRIPTION = "description";
- field public static final java.lang.String DISPLAY_NAME = "display_name";
- field public static final java.lang.String DISPLAY_NUMBER = "display_number";
- field public static final java.lang.String SERVICE_NAME = "service_name";
- field public static final java.lang.String TRANSPORT_STREAM_ID = "transport_stream_id";
- field public static final java.lang.String TYPE = "type";
+ field public static final int SERVICE_TYPE_OTHER = 0; // 0x0
+ field public static final int SERVICE_TYPE_RADIO = 2; // 0x2
+ field public static final int SERVICE_TYPE_TV = 1; // 0x1
field public static final int TYPE_1SEG = 263168; // 0x40400
- field public static final int TYPE_ATSC = 196608; // 0x30000
- field public static final int TYPE_ATSC_2_0 = 196609; // 0x30001
- field public static final int TYPE_ATSC_M_H = 196864; // 0x30100
+ field public static final int TYPE_ATSC_C = 197120; // 0x30200
+ field public static final int TYPE_ATSC_M_H = 197120; // 0x30200
+ field public static final int TYPE_ATSC_T = 196608; // 0x30000
field public static final int TYPE_CMMB = 327936; // 0x50100
field public static final int TYPE_DTMB = 327680; // 0x50000
field public static final int TYPE_DVB_C = 131584; // 0x20200
@@ -23982,21 +24072,20 @@
field public static final int TYPE_PASSTHROUGH = 65536; // 0x10000
field public static final int TYPE_S_DMB = 393472; // 0x60100
field public static final int TYPE_T_DMB = 393216; // 0x60000
- field public static final java.lang.String VERSION_NUMBER = "version_number";
}
public static final class TvContract.Programs implements android.provider.TvContract.BaseTvColumns {
- field public static final java.lang.String CHANNEL_ID = "channel_id";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
+ field public static final java.lang.String COLUMN_DATA = "data";
+ field public static final java.lang.String COLUMN_DESCRIPTION = "description";
+ field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
+ field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
+ field public static final java.lang.String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
+ field public static final java.lang.String COLUMN_TITLE = "title";
+ field public static final java.lang.String COLUMN_VERSION_NUMBER = "version_number";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.com.android.tv.programs";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.com.android.tv.programs";
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String DATA = "data";
- field public static final java.lang.String DESCRIPTION = "description";
- field public static final java.lang.String END_TIME_UTC_MILLIS = "end_time_utc_millis";
- field public static final java.lang.String LONG_DESCRIPTION = "long_description";
- field public static final java.lang.String START_TIME_UTC_MILLIS = "start_time_utc_millis";
- field public static final java.lang.String TITLE = "title";
- field public static final java.lang.String VERSION_NUMBER = "version_number";
}
public class UserDictionary {
@@ -25161,16 +25250,24 @@
method public final deprecated void cancelNotification(java.lang.String, java.lang.String, int);
method public final void cancelNotification(java.lang.String);
method public final void cancelNotifications(java.lang.String[]);
- method public java.lang.String[] getActiveNotificationKeys();
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
method public android.service.notification.StatusBarNotification[] getActiveNotifications(java.lang.String[]);
+ method public java.lang.String[] getOrderedNotificationKeys();
method public android.os.IBinder onBind(android.content.Intent);
method public void onListenerConnected(java.lang.String[]);
+ method public void onNotificationOrderUpdate();
method public abstract void onNotificationPosted(android.service.notification.StatusBarNotification);
method public abstract void onNotificationRemoved(android.service.notification.StatusBarNotification);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
}
+ public class NotificationOrderUpdate implements android.os.Parcelable {
+ ctor public NotificationOrderUpdate(android.os.Parcel);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
public class StatusBarNotification implements android.os.Parcelable {
ctor public StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
ctor public StatusBarNotification(android.os.Parcel);
@@ -25768,6 +25865,7 @@
method public static boolean isatty(java.io.FileDescriptor);
method public static void kill(int, int) throws android.system.ErrnoException;
method public static void lchown(java.lang.String, int, int) throws android.system.ErrnoException;
+ method public static void link(java.lang.String, java.lang.String) throws android.system.ErrnoException;
method public static void listen(java.io.FileDescriptor, int) throws android.system.ErrnoException;
method public static long lseek(java.io.FileDescriptor, long, int) throws android.system.ErrnoException;
method public static android.system.StructStat lstat(java.lang.String) throws android.system.ErrnoException;
@@ -26354,6 +26452,217 @@
}
+package android.telecomm {
+
+ public final class CallAudioState implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static int ROUTE_ALL;
+ field public static int ROUTE_BLUETOOTH;
+ field public static int ROUTE_EARPIECE;
+ field public static int ROUTE_SPEAKER;
+ field public static int ROUTE_WIRED_HEADSET;
+ field public static int ROUTE_WIRED_OR_EARPIECE;
+ field public final boolean isMuted;
+ field public final int route;
+ field public final int supportedRouteMask;
+ }
+
+ public class CallCapabilities {
+ ctor public CallCapabilities();
+ field public static final int ADD_CALL = 16; // 0x10
+ field public static final int ALL = 511; // 0x1ff
+ field public static final int CONNECTION_HANDOFF = 256; // 0x100
+ field public static final int GENERIC_CONFERENCE = 128; // 0x80
+ field public static final int HOLD = 1; // 0x1
+ field public static final int MERGE_CALLS = 4; // 0x4
+ field public static final int MUTE = 64; // 0x40
+ field public static final int RESPOND_VIA_TEXT = 32; // 0x20
+ field public static final int SUPPORT_HOLD = 2; // 0x2
+ field public static final int SWAP_CALLS = 8; // 0x8
+ }
+
+ public final class CallInfo implements android.os.Parcelable {
+ ctor public CallInfo(java.lang.String, android.telecomm.CallState, android.net.Uri);
+ method public int describeContents();
+ method public android.telecomm.CallServiceDescriptor getCurrentCallServiceDescriptor();
+ method public android.os.Bundle getExtras();
+ method public android.telecomm.GatewayInfo getGatewayInfo();
+ method public android.net.Uri getHandle();
+ method public java.lang.String getId();
+ method public android.net.Uri getOriginalHandle();
+ method public android.telecomm.CallState getState();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public final class CallNumberPresentation extends java.lang.Enum {
+ method public static android.telecomm.CallNumberPresentation valueOf(java.lang.String);
+ method public static final android.telecomm.CallNumberPresentation[] values();
+ enum_constant public static final android.telecomm.CallNumberPresentation ALLOWED;
+ enum_constant public static final android.telecomm.CallNumberPresentation PAYPHONE;
+ enum_constant public static final android.telecomm.CallNumberPresentation RESTRICTED;
+ enum_constant public static final android.telecomm.CallNumberPresentation UNKNOWN;
+ }
+
+ public abstract class CallService extends android.app.Service {
+ ctor public CallService();
+ method public abstract void abort(java.lang.String);
+ method public abstract void answer(java.lang.String);
+ method public abstract void call(android.telecomm.CallInfo);
+ method public abstract void disconnect(java.lang.String);
+ method protected final android.telecomm.CallServiceAdapter getAdapter();
+ method public final android.os.IBinder getBinder();
+ method public abstract void hold(java.lang.String);
+ method public abstract void isCompatibleWith(android.telecomm.CallInfo);
+ method protected void onAdapterAttached(android.telecomm.CallServiceAdapter);
+ method public abstract void onAudioStateChanged(java.lang.String, android.telecomm.CallAudioState);
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public abstract void playDtmfTone(java.lang.String, char);
+ method public abstract void reject(java.lang.String);
+ method public abstract void setIncomingCallId(java.lang.String, android.os.Bundle);
+ method public abstract void stopDtmfTone(java.lang.String);
+ method public abstract void unhold(java.lang.String);
+ }
+
+ public final class CallServiceAdapter {
+ method public void handleFailedOutgoingCall(java.lang.String, java.lang.String);
+ method public void handleSuccessfulOutgoingCall(java.lang.String);
+ method public void notifyIncomingCall(android.telecomm.CallInfo);
+ method public void setActive(java.lang.String);
+ method public void setDialing(java.lang.String);
+ method public void setDisconnected(java.lang.String, int, java.lang.String);
+ method public void setIsCompatibleWith(java.lang.String, boolean);
+ method public void setOnHold(java.lang.String);
+ method public void setRinging(java.lang.String);
+ }
+
+ public final class CallServiceDescriptor implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.lang.String getCallServiceId();
+ method public int getNetworkType();
+ method public android.content.ComponentName getServiceComponent();
+ method public static android.telecomm.CallServiceDescriptor.Builder newBuilder(android.content.Context);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int FLAG_MOBILE = 4; // 0x4
+ field public static final int FLAG_PSTN = 2; // 0x2
+ field public static final int FLAG_WIFI = 1; // 0x1
+ }
+
+ public static class CallServiceDescriptor.Builder {
+ method public android.telecomm.CallServiceDescriptor build();
+ method public android.telecomm.CallServiceDescriptor.Builder setCallService(java.lang.Class<? extends android.telecomm.CallService>);
+ method public android.telecomm.CallServiceDescriptor.Builder setNetworkType(int);
+ }
+
+ public final class CallServiceLookupResponse {
+ method public void setCallServiceDescriptors(java.util.List<android.telecomm.CallServiceDescriptor>);
+ }
+
+ public abstract class CallServiceProvider extends android.app.Service {
+ ctor protected CallServiceProvider();
+ method public abstract void lookupCallServices(android.telecomm.CallServiceLookupResponse);
+ method public android.os.IBinder onBind(android.content.Intent);
+ }
+
+ public abstract class CallServiceSelector extends android.app.Service {
+ ctor protected CallServiceSelector();
+ method protected final void cancelOutgoingCall(android.telecomm.CallInfo);
+ method protected final android.telecomm.CallServiceSelectorAdapter getAdapter();
+ method protected final java.util.Collection<android.telecomm.CallInfo> getCalls();
+ method protected void onAdapterAttached(android.telecomm.CallServiceSelectorAdapter);
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method protected abstract void select(android.telecomm.CallInfo, java.util.List<android.telecomm.CallServiceDescriptor>);
+ }
+
+ public final class CallServiceSelectorAdapter {
+ method public void cancelOutgoingCall(java.lang.String);
+ method public void setHandoffInfo(java.lang.String, android.net.Uri, android.os.Bundle);
+ method public void setSelectedCallServices(java.lang.String, java.util.List<android.telecomm.CallServiceDescriptor>);
+ }
+
+ public final class CallState extends java.lang.Enum {
+ method public static android.telecomm.CallState valueOf(java.lang.String);
+ method public static final android.telecomm.CallState[] values();
+ enum_constant public static final android.telecomm.CallState ACTIVE;
+ enum_constant public static final android.telecomm.CallState DIALING;
+ enum_constant public static final android.telecomm.CallState DISCONNECTED;
+ enum_constant public static final android.telecomm.CallState NEW;
+ enum_constant public static final android.telecomm.CallState ON_HOLD;
+ enum_constant public static final android.telecomm.CallState POST_DIAL;
+ enum_constant public static final android.telecomm.CallState POST_DIAL_WAIT;
+ enum_constant public static final android.telecomm.CallState RINGING;
+ }
+
+ public class GatewayInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.net.Uri getGatewayHandle();
+ method public java.lang.String getGatewayProviderPackageName();
+ method public android.net.Uri getOriginalHandle();
+ method public boolean isEmpty();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public final class InCallAdapter {
+ method public void answerCall(java.lang.String);
+ method public void disconnectCall(java.lang.String);
+ method public void handoffCall(java.lang.String);
+ method public void holdCall(java.lang.String);
+ method public void mute(boolean);
+ method public void playDtmfTone(java.lang.String, char);
+ method public void postDialContinue(java.lang.String);
+ method public void rejectCall(java.lang.String);
+ method public void setAudioRoute(int);
+ method public void stopDtmfTone(java.lang.String);
+ method public void unholdCall(java.lang.String);
+ }
+
+ public final class InCallCall implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getCapabilities();
+ method public long getConnectTimeMillis();
+ method public android.telecomm.CallServiceDescriptor getCurrentCallServiceDescriptor();
+ method public int getDisconnectCause();
+ method public android.telecomm.GatewayInfo getGatewayInfo();
+ method public android.net.Uri getHandle();
+ method public android.telecomm.CallServiceDescriptor getHandoffCallServiceDescriptor();
+ method public java.lang.String getId();
+ method public android.telecomm.CallState getState();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public abstract class InCallService extends android.app.Service {
+ ctor protected InCallService();
+ method protected abstract void addCall(android.telecomm.InCallCall);
+ method protected final android.telecomm.InCallAdapter getAdapter();
+ method protected void onAdapterAttached(android.telecomm.InCallAdapter);
+ method protected abstract void onAudioStateChanged(android.telecomm.CallAudioState);
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method protected abstract void setPostDial(java.lang.String, java.lang.String);
+ method protected abstract void setPostDialWait(java.lang.String, java.lang.String);
+ method protected abstract void updateCall(android.telecomm.InCallCall);
+ }
+
+ public final class TelecommConstants {
+ ctor public TelecommConstants();
+ field public static final java.lang.String ACTION_CALL_SERVICE;
+ field public static final java.lang.String ACTION_CALL_SERVICE_PROVIDER;
+ field public static final java.lang.String ACTION_CALL_SERVICE_SELECTOR;
+ field public static final java.lang.String ACTION_INCOMING_CALL = "android.intent.action.INCOMING_CALL";
+ field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
+ field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
+ field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecomm.extra.CALL_DISCONNECT_CAUSE";
+ field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecomm.extra.CALL_DISCONNECT_MESSAGE";
+ field public static final java.lang.String EXTRA_CALL_SERVICE_DESCRIPTOR = "android.intent.extra.CALL_SERVICE_DESCRIPTOR";
+ field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.intent.extra.INCOMING_CALL_EXTRAS";
+ }
+
+}
+
package android.telephony {
public final class CellIdentityCdma implements android.os.Parcelable {
@@ -26502,6 +26811,50 @@
field public static final android.os.Parcelable.Creator CREATOR;
}
+ public class DisconnectCause {
+ method public static java.lang.String toString(int);
+ field public static final int BUSY = 4; // 0x4
+ field public static final int CALL_BARRED = 20; // 0x14
+ field public static final int CDMA_ACCESS_BLOCKED = 35; // 0x23
+ field public static final int CDMA_ACCESS_FAILURE = 32; // 0x20
+ field public static final int CDMA_DROP = 27; // 0x1b
+ field public static final int CDMA_INTERCEPT = 28; // 0x1c
+ field public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 26; // 0x1a
+ field public static final int CDMA_NOT_EMERGENCY = 34; // 0x22
+ field public static final int CDMA_PREEMPTED = 33; // 0x21
+ field public static final int CDMA_REORDER = 29; // 0x1d
+ field public static final int CDMA_RETRY_ORDER = 31; // 0x1f
+ field public static final int CDMA_SO_REJECT = 30; // 0x1e
+ field public static final int CONGESTION = 5; // 0x5
+ field public static final int CS_RESTRICTED = 22; // 0x16
+ field public static final int CS_RESTRICTED_EMERGENCY = 24; // 0x18
+ field public static final int CS_RESTRICTED_NORMAL = 23; // 0x17
+ field public static final int ERROR_UNSPECIFIED = 36; // 0x24
+ field public static final int FDN_BLOCKED = 21; // 0x15
+ field public static final int ICC_ERROR = 19; // 0x13
+ field public static final int INCOMING_MISSED = 1; // 0x1
+ field public static final int INCOMING_REJECTED = 16; // 0x10
+ field public static final int INVALID_CREDENTIALS = 10; // 0xa
+ field public static final int INVALID_NUMBER = 7; // 0x7
+ field public static final int LIMIT_EXCEEDED = 15; // 0xf
+ field public static final int LOCAL = 3; // 0x3
+ field public static final int LOST_SIGNAL = 14; // 0xe
+ field public static final int MAXIMUM_VALID_VALUE = 36; // 0x24
+ field public static final int MINIMUM_VALID_VALUE = 0; // 0x0
+ field public static final int MMI = 6; // 0x6
+ field public static final int NORMAL = 2; // 0x2
+ field public static final int NOT_DISCONNECTED = 0; // 0x0
+ field public static final int NOT_VALID = -1; // 0xffffffff
+ field public static final int NUMBER_UNREACHABLE = 8; // 0x8
+ field public static final int OUT_OF_NETWORK = 11; // 0xb
+ field public static final int OUT_OF_SERVICE = 18; // 0x12
+ field public static final int POWER_OFF = 17; // 0x11
+ field public static final int SERVER_ERROR = 12; // 0xc
+ field public static final int SERVER_UNREACHABLE = 9; // 0x9
+ field public static final int TIMED_OUT = 13; // 0xd
+ field public static final int UNOBTAINABLE_NUMBER = 25; // 0x19
+ }
+
public class NeighboringCellInfo implements android.os.Parcelable {
ctor public deprecated NeighboringCellInfo();
ctor public deprecated NeighboringCellInfo(int, int);
@@ -28984,6 +29337,7 @@
ctor public Transition();
method public android.transition.Transition addListener(android.transition.Transition.TransitionListener);
method public android.transition.Transition addTarget(int);
+ method public android.transition.Transition addTarget(java.lang.String);
method public android.transition.Transition addTarget(java.lang.Class);
method public android.transition.Transition addTarget(android.view.View);
method public boolean canRemoveViews();
@@ -28995,6 +29349,7 @@
method public android.transition.Transition excludeChildren(android.view.View, boolean);
method public android.transition.Transition excludeChildren(java.lang.Class, boolean);
method public android.transition.Transition excludeTarget(int, boolean);
+ method public android.transition.Transition excludeTarget(java.lang.String, boolean);
method public android.transition.Transition excludeTarget(android.view.View, boolean);
method public android.transition.Transition excludeTarget(java.lang.Class, boolean);
method public long getDuration();
@@ -29005,17 +29360,26 @@
method public android.transition.TransitionPropagation getPropagation();
method public long getStartDelay();
method public java.util.List<java.lang.Integer> getTargetIds();
+ method public java.util.List<java.lang.Class> getTargetTypes();
+ method public java.util.List<java.lang.String> getTargetViewNames();
method public java.util.List<android.view.View> getTargets();
method public java.lang.String[] getTransitionProperties();
method public android.transition.TransitionValues getTransitionValues(android.view.View, boolean);
method public android.transition.Transition removeListener(android.transition.Transition.TransitionListener);
method public android.transition.Transition removeTarget(int);
+ method public android.transition.Transition removeTarget(java.lang.String);
method public android.transition.Transition removeTarget(android.view.View);
+ method public android.transition.Transition removeTarget(java.lang.Class);
method public android.transition.Transition setDuration(long);
method public void setEpicenterCallback(android.transition.Transition.EpicenterCallback);
method public android.transition.Transition setInterpolator(android.animation.TimeInterpolator);
+ method public void setMatchOrder(int...);
method public void setPropagation(android.transition.TransitionPropagation);
method public android.transition.Transition setStartDelay(long);
+ field public static final int MATCH_ID = 3; // 0x3
+ field public static final int MATCH_INSTANCE = 1; // 0x1
+ field public static final int MATCH_ITEM_ID = 4; // 0x4
+ field public static final int MATCH_VIEW_NAME = 2; // 0x2
}
public static abstract class Transition.EpicenterCallback {
@@ -29108,11 +29472,11 @@
}
public final class TvInputManager {
- method public void createSession(android.content.ComponentName, android.tv.TvInputManager.SessionCreateCallback, android.os.Handler);
- method public boolean getAvailability(android.content.ComponentName);
+ method public void createSession(java.lang.String, android.tv.TvInputManager.SessionCallback, android.os.Handler);
+ method public boolean getAvailability(java.lang.String);
method public java.util.List<android.tv.TvInputInfo> getTvInputList();
- method public void registerListener(android.content.ComponentName, android.tv.TvInputManager.TvInputListener, android.os.Handler);
- method public void unregisterListener(android.content.ComponentName, android.tv.TvInputManager.TvInputListener);
+ method public void registerListener(java.lang.String, android.tv.TvInputManager.TvInputListener, android.os.Handler);
+ method public void unregisterListener(java.lang.String, android.tv.TvInputManager.TvInputListener);
}
public static final class TvInputManager.Session {
@@ -29121,13 +29485,15 @@
method public void tune(android.net.Uri);
}
- public static abstract interface TvInputManager.SessionCreateCallback {
- method public abstract void onSessionCreated(android.tv.TvInputManager.Session);
+ public static abstract class TvInputManager.SessionCallback {
+ ctor public TvInputManager.SessionCallback();
+ method public void onSessionCreated(android.tv.TvInputManager.Session);
+ method public void onSessionReleased(android.tv.TvInputManager.Session);
}
public static abstract class TvInputManager.TvInputListener {
ctor public TvInputManager.TvInputListener();
- method public void onAvailabilityChanged(android.content.ComponentName, boolean);
+ method public void onAvailabilityChanged(java.lang.String, boolean);
}
public abstract class TvInputService extends android.app.Service {
@@ -29159,7 +29525,7 @@
ctor public TvView(android.content.Context);
ctor public TvView(android.content.Context, android.util.AttributeSet);
ctor public TvView(android.content.Context, android.util.AttributeSet, int);
- method public void bindTvInput(android.content.ComponentName, android.tv.TvInputManager.SessionCreateCallback);
+ method public void bindTvInput(java.lang.String, android.tv.TvInputManager.SessionCallback);
method public boolean dispatchUnhandledInputEvent(android.view.InputEvent);
method public boolean onUnhandledInputEvent(android.view.InputEvent);
method public void setOnUnhandledInputEventListener(android.tv.TvView.OnUnhandledInputEventListener);
@@ -31238,7 +31604,6 @@
method public int getScrollBarStyle();
method public final int getScrollX();
method public final int getScrollY();
- method public java.lang.String getSharedElementName();
method public int getSolidColor();
method public android.animation.StateListAnimator getStateListAnimator();
method protected int getSuggestedMinimumHeight();
@@ -31259,6 +31624,7 @@
method public int getVerticalFadingEdgeLength();
method public int getVerticalScrollbarPosition();
method public int getVerticalScrollbarWidth();
+ method public java.lang.String getViewName();
method public android.view.ViewTreeObserver getViewTreeObserver();
method public int getVisibility();
method public final int getWidth();
@@ -31503,7 +31869,6 @@
method public void setScrollY(int);
method public void setScrollbarFadingEnabled(boolean);
method public void setSelected(boolean);
- method public void setSharedElementName(java.lang.String);
method public void setSoundEffectsEnabled(boolean);
method public void setStateListAnimator(android.animation.StateListAnimator);
method public void setSystemUiVisibility(int);
@@ -31519,6 +31884,7 @@
method public void setVerticalFadingEdgeEnabled(boolean);
method public void setVerticalScrollBarEnabled(boolean);
method public void setVerticalScrollbarPosition(int);
+ method public final void setViewName(java.lang.String);
method public void setVisibility(int);
method public void setWillNotCacheDrawing(boolean);
method public void setWillNotDraw(boolean);
@@ -32209,8 +32575,10 @@
method protected final int getForcedWindowFlags();
method public abstract android.view.LayoutInflater getLayoutInflater();
method protected final int getLocalFeatures();
+ method public abstract int getNavigationBarColor();
method public android.transition.Transition getSharedElementEnterTransition();
method public android.transition.Transition getSharedElementExitTransition();
+ method public abstract int getStatusBarColor();
method public android.transition.TransitionManager getTransitionManager();
method public abstract int getVolumeControlStream();
method public android.view.WindowManager getWindowManager();
@@ -32262,9 +32630,11 @@
method public void setLayout(int, int);
method public void setLocalFocus(boolean, boolean);
method public void setLogo(int);
+ method public abstract void setNavigationBarColor(int);
method public void setSharedElementEnterTransition(android.transition.Transition);
method public void setSharedElementExitTransition(android.transition.Transition);
method public void setSoftInputMode(int);
+ method public abstract void setStatusBarColor(int);
method public abstract void setTitle(java.lang.CharSequence);
method public abstract deprecated void setTitleColor(int);
method public void setTransitionManager(android.transition.TransitionManager);
@@ -32422,6 +32792,7 @@
field public static final int FLAG_DIM_BEHIND = 2; // 0x2
field public static final int FLAG_DISMISS_KEYGUARD = 4194304; // 0x400000
field public static final deprecated int FLAG_DITHER = 4096; // 0x1000
+ field public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = -2147483648; // 0x80000000
field public static final int FLAG_FORCE_NOT_FULLSCREEN = 2048; // 0x800
field public static final int FLAG_FULLSCREEN = 1024; // 0x400
field public static final int FLAG_HARDWARE_ACCELERATED = 16777216; // 0x1000000
@@ -32612,7 +32983,8 @@
}
public class AccessibilityNodeInfo implements android.os.Parcelable {
- method public void addAction(int);
+ method public void addAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction);
+ method public deprecated void addAction(int);
method public void addChild(android.view.View);
method public void addChild(android.view.View, int);
method public boolean canOpenPopup();
@@ -32621,7 +32993,8 @@
method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(java.lang.String);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
method public android.view.accessibility.AccessibilityNodeInfo focusSearch(int);
- method public int getActions();
+ method public java.util.List<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> getActionList();
+ method public deprecated int getActions();
method public void getBoundsInParent(android.graphics.Rect);
method public void getBoundsInScreen(android.graphics.Rect);
method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
@@ -32669,7 +33042,8 @@
method public boolean performAction(int, android.os.Bundle);
method public void recycle();
method public boolean refresh();
- method public void removeAction(int);
+ method public deprecated void removeAction(int);
+ method public boolean removeAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction);
method public boolean removeChild(android.view.View);
method public boolean removeChild(android.view.View, int);
method public void setAccessibilityFocused(boolean);
@@ -32750,6 +33124,34 @@
field public static final int MOVEMENT_GRANULARITY_WORD = 2; // 0x2
}
+ public static final class AccessibilityNodeInfo.AccessibilityAction {
+ ctor public AccessibilityNodeInfo.AccessibilityAction(int, java.lang.CharSequence);
+ method public int getId();
+ method public java.lang.CharSequence getLabel();
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_ACCESSIBILITY_FOCUS;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_CLEAR_FOCUS;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_CLEAR_SELECTION;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_CLICK;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_COLLAPSE;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_COPY;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_CUT;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_DISMISS;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_EXPAND;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_FOCUS;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_LONG_CLICK;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_NEXT_HTML_ELEMENT;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PASTE;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PREVIOUS_HTML_ELEMENT;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SCROLL_BACKWARD;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SCROLL_FORWARD;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SELECT;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_SELECTION;
+ field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_TEXT;
+ }
+
public static final class AccessibilityNodeInfo.CollectionInfo {
method public int getColumnCount();
method public int getRowCount();
@@ -33229,9 +33631,9 @@
public final class CursorAnchorInfo implements android.os.Parcelable {
ctor public CursorAnchorInfo(android.os.Parcel);
method public int describeContents();
- method public int getCandidatesEnd();
- method public int getCandidatesStart();
method public android.graphics.RectF getCharacterRect(int);
+ method public java.lang.String getComposingText();
+ method public int getComposingTextStart();
method public float getInsertionMarkerBaseline();
method public float getInsertionMarkerBottom();
method public float getInsertionMarkerHorizontal();
@@ -33248,7 +33650,7 @@
method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder addCharacterRect(int, float, float, float, float);
method public android.view.inputmethod.CursorAnchorInfo build();
method public void reset();
- method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setCandidateRange(int, int);
+ method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setComposingText(int, java.lang.CharSequence);
method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setInsertionMarkerLocation(float, float, float, float);
method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setMatrix(android.graphics.Matrix);
method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setSelectionRange(int, int);
@@ -34325,9 +34727,11 @@
ctor public AbsSeekBar(android.content.Context, android.util.AttributeSet, int);
ctor public AbsSeekBar(android.content.Context, android.util.AttributeSet, int, int);
method public int getKeyProgressIncrement();
+ method public boolean getSplitTrack();
method public android.graphics.drawable.Drawable getThumb();
method public int getThumbOffset();
method public void setKeyProgressIncrement(int);
+ method public void setSplitTrack(boolean);
method public void setThumb(android.graphics.drawable.Drawable);
method public void setThumbOffset(int);
}
@@ -34864,9 +35268,11 @@
ctor public EdgeEffect(android.content.Context);
method public boolean draw(android.graphics.Canvas);
method public void finish();
+ method public int getMaxHeight();
method public boolean isFinished();
method public void onAbsorb(int);
method public void onPull(float);
+ method public void onPull(float, float);
method public void onRelease();
method public void setSize(int, int);
}
@@ -36130,6 +36536,7 @@
ctor public Switch(android.content.Context, android.util.AttributeSet);
ctor public Switch(android.content.Context, android.util.AttributeSet, int);
ctor public Switch(android.content.Context, android.util.AttributeSet, int, int);
+ method public boolean getSplitTrack();
method public int getSwitchMinWidth();
method public int getSwitchPadding();
method public java.lang.CharSequence getTextOff();
@@ -36138,6 +36545,7 @@
method public int getThumbTextPadding();
method public android.graphics.drawable.Drawable getTrackDrawable();
method public void onMeasure(int, int);
+ method public void setSplitTrack(boolean);
method public void setSwitchMinWidth(int);
method public void setSwitchPadding(int);
method public void setSwitchTextAppearance(android.content.Context, int);
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index 7c25354..74a2f7b 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -1,6 +1,5 @@
LOCAL_PATH:= $(call my-dir)
-# 32-bit app_process
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
@@ -15,10 +14,14 @@
LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := app_process
+LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64
include $(BUILD_EXECUTABLE)
+# Create a symlink from app_process to app_process32 or 64
+# depending on the target configuration.
+include $(BUILD_SYSTEM)/executable_prefer_symlink.mk
+
# Build a variant of app_process binary linked with ASan runtime.
# ARM-only at the moment.
ifeq ($(TARGET_ARCH),arm)
diff --git a/cmds/svc/src/com/android/commands/svc/DataCommand.java b/cmds/svc/src/com/android/commands/svc/DataCommand.java
index 72cb86d..406e33b 100644
--- a/cmds/svc/src/com/android/commands/svc/DataCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/DataCommand.java
@@ -36,9 +36,7 @@
return shortHelp() + "\n"
+ "\n"
+ "usage: svc data [enable|disable]\n"
- + " Turn mobile data on or off.\n\n"
- + " svc data prefer\n"
- + " Set mobile as the preferred data network\n";
+ + " Turn mobile data on or off.\n\n";
}
public void run(String[] args) {
@@ -51,15 +49,6 @@
} else if ("disable".equals(args[1])) {
flag = false;
validCommand = true;
- } else if ("prefer".equals(args[1])) {
- IConnectivityManager connMgr =
- IConnectivityManager.Stub.asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
- try {
- connMgr.setNetworkPreference(ConnectivityManager.TYPE_MOBILE);
- } catch (RemoteException e) {
- System.err.println("Failed to set preferred network: " + e);
- }
- return;
}
if (validCommand) {
ITelephony phoneMgr
@@ -78,4 +67,4 @@
}
System.err.println(longHelp());
}
-}
\ No newline at end of file
+}
diff --git a/cmds/svc/src/com/android/commands/svc/WifiCommand.java b/cmds/svc/src/com/android/commands/svc/WifiCommand.java
index d29e8b2..39f0e35 100644
--- a/cmds/svc/src/com/android/commands/svc/WifiCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/WifiCommand.java
@@ -36,9 +36,7 @@
return shortHelp() + "\n"
+ "\n"
+ "usage: svc wifi [enable|disable]\n"
- + " Turn Wi-Fi on or off.\n\n"
- + " svc wifi prefer\n"
- + " Set Wi-Fi as the preferred data network\n";
+ + " Turn Wi-Fi on or off.\n\n";
}
public void run(String[] args) {
@@ -51,15 +49,6 @@
} else if ("disable".equals(args[1])) {
flag = false;
validCommand = true;
- } else if ("prefer".equals(args[1])) {
- IConnectivityManager connMgr =
- IConnectivityManager.Stub.asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
- try {
- connMgr.setNetworkPreference(ConnectivityManager.TYPE_WIFI);
- } catch (RemoteException e) {
- System.err.println("Failed to set preferred network: " + e);
- }
- return;
}
if (validCommand) {
IWifiManager wifiMgr
@@ -75,4 +64,4 @@
}
System.err.println(longHelp());
}
-}
\ No newline at end of file
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ef6fcb7..36c36a8 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -17,6 +17,7 @@
package android.app;
import android.annotation.NonNull;
+import android.os.PersistableBundle;
import android.transition.Scene;
import android.transition.TransitionManager;
import android.util.ArrayMap;
@@ -29,7 +30,6 @@
import android.annotation.IntDef;
import android.annotation.Nullable;
-import android.app.admin.DevicePolicyManager;
import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -777,8 +777,9 @@
private Thread mUiThread;
final Handler mHandler = new Handler();
- private ActivityOptions mCalledActivityOptions;
- private EnterTransitionCoordinator mEnterTransitionCoordinator;
+
+ private ActivityTransitionState mActivityTransitionState = new ActivityTransitionState();
+ SharedElementListener mTransitionListener = new SharedElementListener();
/** Return the intent that started this activity. */
public Intent getIntent() {
@@ -922,6 +923,30 @@
}
/**
+ * Same as {@link #onCreate(android.os.Bundle)} but called for those activities created with
+ * the attribute {@link android.R.attr#persistable} set true.
+ *
+ * @param savedInstanceState if the activity is being re-initialized after
+ * previously being shut down then this Bundle contains the data it most
+ * recently supplied in {@link #onSaveInstanceState}.
+ * <b><i>Note: Otherwise it is null.</i></b>
+ * @param persistentState if the activity is being re-initialized after
+ * previously being shut down or powered off then this Bundle contains the data it most
+ * recently supplied to outPersistentState in {@link #onSaveInstanceState}.
+ * <b><i>Note: Otherwise it is null.</i></b>
+ *
+ * @see #onCreate(android.os.Bundle)
+ * @see #onStart
+ * @see #onSaveInstanceState
+ * @see #onRestoreInstanceState
+ * @see #onPostCreate
+ */
+ protected void onCreate(@Nullable Bundle savedInstanceState,
+ @Nullable PersistableBundle persistentState) {
+ onCreate(savedInstanceState);
+ }
+
+ /**
* The hook for {@link ActivityThread} to restore the state of this activity.
*
* Calls {@link #onSaveInstanceState(android.os.Bundle)} and
@@ -935,6 +960,23 @@
}
/**
+ * The hook for {@link ActivityThread} to restore the state of this activity.
+ *
+ * Calls {@link #onSaveInstanceState(android.os.Bundle)} and
+ * {@link #restoreManagedDialogs(android.os.Bundle)}.
+ *
+ * @param savedInstanceState contains the saved state
+ * @param persistentState contains the persistable saved state
+ */
+ final void performRestoreInstanceState(Bundle savedInstanceState,
+ PersistableBundle persistentState) {
+ onRestoreInstanceState(savedInstanceState, persistentState);
+ if (savedInstanceState != null) {
+ restoreManagedDialogs(savedInstanceState);
+ }
+ }
+
+ /**
* This method is called after {@link #onStart} when the activity is
* being re-initialized from a previously saved state, given here in
* <var>savedInstanceState</var>. Most implementations will simply use {@link #onCreate}
@@ -962,7 +1004,34 @@
}
}
}
-
+
+ /**
+ * This is the same as {@link #onRestoreInstanceState(Bundle)} but is called for activities
+ * created with the attribute {@link android.R.attr#persistable}. The {@link
+ * android.os.PersistableBundle} passed came from the restored PersistableBundle first
+ * saved in {@link #onSaveInstanceState(Bundle, PersistableBundle)}.
+ *
+ * <p>This method is called between {@link #onStart} and
+ * {@link #onPostCreate}.
+ *
+ * <p>If this method is called {@link #onRestoreInstanceState(Bundle)} will not be called.
+ *
+ * @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}.
+ * @param persistentState the data most recently supplied in {@link #onSaveInstanceState}.
+ *
+ * @see #onRestoreInstanceState(Bundle)
+ * @see #onCreate
+ * @see #onPostCreate
+ * @see #onResume
+ * @see #onSaveInstanceState
+ */
+ protected void onRestoreInstanceState(Bundle savedInstanceState,
+ PersistableBundle persistentState) {
+ if (savedInstanceState != null) {
+ onRestoreInstanceState(savedInstanceState);
+ }
+ }
+
/**
* Restore the state of any saved managed dialogs.
*
@@ -1032,13 +1101,25 @@
mTitleReady = true;
onTitleChanged(getTitle(), getTitleColor());
}
- if (mEnterTransitionCoordinator != null) {
- mEnterTransitionCoordinator.readyToEnter();
- }
mCalled = true;
}
/**
+ * This is the same as {@link #onPostCreate(Bundle)} but is called for activities
+ * created with the attribute {@link android.R.attr#persistable}.
+ *
+ * @param savedInstanceState The data most recently supplied in {@link #onSaveInstanceState}
+ * @param persistentState The data caming from the PersistableBundle first
+ * saved in {@link #onSaveInstanceState(Bundle, PersistableBundle)}.
+ *
+ * @see #onCreate
+ */
+ protected void onPostCreate(@Nullable Bundle savedInstanceState,
+ @Nullable PersistableBundle persistentState) {
+ onPostCreate(savedInstanceState);
+ }
+
+ /**
* Called after {@link #onCreate} — or after {@link #onRestart} when
* the activity had been stopped, but is now again being displayed to the
* user. It will be followed by {@link #onResume}.
@@ -1115,7 +1196,6 @@
protected void onResume() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
getApplication().dispatchActivityResumed(this);
- mCalledActivityOptions = null;
mCalled = true;
}
@@ -1190,10 +1270,27 @@
final void performSaveInstanceState(Bundle outState) {
onSaveInstanceState(outState);
saveManagedDialogs(outState);
+ mActivityTransitionState.saveState(outState);
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState);
}
/**
+ * The hook for {@link ActivityThread} to save the state of this activity.
+ *
+ * Calls {@link #onSaveInstanceState(android.os.Bundle)}
+ * and {@link #saveManagedDialogs(android.os.Bundle)}.
+ *
+ * @param outState The bundle to save the state to.
+ * @param outPersistentState The bundle to save persistent state to.
+ */
+ final void performSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
+ onSaveInstanceState(outState, outPersistentState);
+ saveManagedDialogs(outState);
+ if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState +
+ ", " + outPersistentState);
+ }
+
+ /**
* Called to retrieve per-instance state from an activity before being killed
* so that the state can be restored in {@link #onCreate} or
* {@link #onRestoreInstanceState} (the {@link Bundle} populated by this method
@@ -1248,6 +1345,25 @@
}
/**
+ * This is the same as {@link #onSaveInstanceState} but is called for activities
+ * created with the attribute {@link android.R.attr#persistable}. The {@link
+ * android.os.PersistableBundle} passed in will be saved and presented in
+ * {@link #onCreate(Bundle, PersistableBundle)} the first time that this activity
+ * is restarted following the next device reboot.
+ *
+ * @param outState Bundle in which to place your saved state.
+ * @param outPersistentState State which will be saved across reboots.
+ *
+ * @see #onSaveInstanceState(Bundle)
+ * @see #onCreate
+ * @see #onRestoreInstanceState(Bundle, PersistableBundle)
+ * @see #onPause
+ */
+ protected void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
+ onSaveInstanceState(outState);
+ }
+
+ /**
* Save the state of any managed dialogs.
*
* @param outState place to store the saved state.
@@ -1425,10 +1541,7 @@
protected void onStop() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
- if (mCalledActivityOptions != null) {
- mCalledActivityOptions.dispatchActivityStopped();
- mCalledActivityOptions = null;
- }
+ mActivityTransitionState.onStop();
getApplication().dispatchActivityStopped(this);
mTranslucentCallback = null;
mCalled = true;
@@ -3499,13 +3612,15 @@
}
// Get the primary color and update the RecentsActivityValues for this activity
- TypedArray a = getTheme().obtainStyledAttributes(com.android.internal.R.styleable.Theme);
- int colorPrimary = a.getColor(com.android.internal.R.styleable.Theme_colorPrimary, 0);
- a.recycle();
- if (colorPrimary != 0) {
- ActivityManager.RecentsActivityValues v = new ActivityManager.RecentsActivityValues();
- v.colorPrimary = colorPrimary;
- setRecentsActivityValues(v);
+ if (theme != null) {
+ TypedArray a = theme.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
+ int colorPrimary = a.getColor(com.android.internal.R.styleable.Theme_colorPrimary, 0);
+ a.recycle();
+ if (colorPrimary != 0) {
+ ActivityManager.RecentsActivityValues v = new ActivityManager.RecentsActivityValues();
+ v.colorPrimary = colorPrimary;
+ setRecentsActivityValues(v);
+ }
}
}
@@ -3524,7 +3639,7 @@
public void startActivityForResult(Intent intent, int requestCode) {
Bundle options = null;
if (mWindow.hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
- options = ActivityOptions.makeSceneTransitionAnimation(mWindow, null).toBundle();
+ options = ActivityOptions.makeSceneTransitionAnimation(this).toBundle();
}
startActivityForResult(intent, requestCode, options);
}
@@ -3565,9 +3680,7 @@
*/
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
if (options != null) {
- ActivityOptions activityOptions = new ActivityOptions(options);
- activityOptions.dispatchStartExit();
- mCalledActivityOptions = activityOptions;
+ mActivityTransitionState.startExitOutTransition(this, options);
}
if (mParent == null) {
Instrumentation.ActivityResult ar =
@@ -4433,13 +4546,10 @@
* to reverse its exit Transition. When the exit Transition completes,
* {@link #finish()} is called. If no entry Transition was used, finish() is called
* immediately and the Activity exit Transition is run.
- * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
- * android.app.ActivityOptions.ActivityTransitionListener)
+ * @see android.app.ActivityOptions#makeSceneTransitionAnimation(Activity, android.util.Pair[])
*/
public void finishWithTransition() {
- if (mEnterTransitionCoordinator != null) {
- mEnterTransitionCoordinator.startExit();
- } else {
+ if (!mActivityTransitionState.startExitBackTransition(this)) {
finish();
}
}
@@ -4517,6 +4627,27 @@
}
/**
+ * Called when an activity you launched with an activity transition exposes this
+ * Activity through a returning activity transition, giving you the resultCode
+ * and any additional data from it. This method will only be called if the activity
+ * set a result code other than {@link #RESULT_CANCELED} and it supports activity
+ * transitions with {@link Window#FEATURE_CONTENT_TRANSITIONS}.
+ *
+ * <p>The purpose of this function is to let the called Activity send a hint about
+ * its state so that this underlying Activity can prepare to be exposed. A call to
+ * this method does not guarantee that the called Activity has or will be exiting soon.
+ * It only indicates that it will expose this Activity's Window and it has
+ * some data to pass to prepare it.</p>
+ *
+ * @param resultCode The integer result code returned by the child activity
+ * through its setResult().
+ * @param data An Intent, which can return result data to the caller
+ * (various data can be attached to Intent "extras").
+ */
+ protected void onActivityReenter(int resultCode, Intent data) {
+ }
+
+ /**
* Create a new PendingIntent object which you can hand to others
* for them to use to send result data back to your
* {@link #onActivityResult} callback. The created object will be either
@@ -5120,7 +5251,8 @@
* This call has no effect on non-translucent activities or on activities with the
* {@link android.R.attr#windowIsFloating} attribute.
*
- * @see #convertToTranslucent(TranslucentConversionListener)
+ * @see #convertToTranslucent(android.app.Activity.TranslucentConversionListener,
+ * ActivityOptions)
* @see TranslucentConversionListener
*
* @hide
@@ -5151,19 +5283,29 @@
*
* @param callback the method to call when all visible Activities behind this one have been
* drawn and it is safe to make this Activity translucent again.
+ * @param options activity options delivered to the activity below this one. The options
+ * are retrieved using {@link #getActivityOptions}.
*
* @see #convertFromTranslucent()
* @see TranslucentConversionListener
*
* @hide
*/
- public void convertToTranslucent(TranslucentConversionListener callback) {
+ void convertToTranslucent(TranslucentConversionListener callback, ActivityOptions options) {
+ boolean drawComplete;
try {
mTranslucentCallback = callback;
mChangeCanvasToTranslucent =
- ActivityManagerNative.getDefault().convertToTranslucent(mToken);
+ ActivityManagerNative.getDefault().convertToTranslucent(mToken, options);
+ drawComplete = true;
} catch (RemoteException e) {
- // pass
+ // Make callback return as though it timed out.
+ mChangeCanvasToTranslucent = false;
+ drawComplete = false;
+ }
+ if (!mChangeCanvasToTranslucent && mTranslucentCallback != null) {
+ // Window is already translucent.
+ mTranslucentCallback.onTranslucentConversionComplete(drawComplete);
}
}
@@ -5179,6 +5321,22 @@
}
/**
+ * Retrieve the ActivityOptions passed in from the launching activity or passed back
+ * from an activity launched by this activity in its call to {@link
+ * #convertToTranslucent(TranslucentConversionListener, ActivityOptions)}
+ *
+ * @return The ActivityOptions passed to {@link #convertToTranslucent}.
+ * @hide
+ */
+ ActivityOptions getActivityOptions() {
+ try {
+ return ActivityManagerNative.getDefault().getActivityOptions(mToken);
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+
+ /**
* Adjust the current immersive mode setting.
*
* Note that changing this value will have no effect on the activity's
@@ -5392,18 +5550,18 @@
}
/**
- * When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
- * android.app.ActivityOptions.ActivityTransitionListener)} was used to start an Activity,
- * the Window will be triggered to enter with a Transition. <code>listener</code> allows
- * The Activity to listen to events of the entering transition and control the mapping of
- * shared elements. This requires {@link Window#FEATURE_CONTENT_TRANSITIONS}.
+ * When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity,
+ * android.view.View, String)} was used to start an Activity, <var>listener</var>
+ * will be called to handle shared elements. This requires
+ * {@link Window#FEATURE_CONTENT_TRANSITIONS}.
*
- * @param listener Used to listen to events in the entering transition.
+ * @param listener Used to manipulate how shared element transitions function.
*/
- public void setActivityTransitionListener(ActivityOptions.ActivityTransitionListener listener) {
- if (mEnterTransitionCoordinator != null) {
- mEnterTransitionCoordinator.setActivityTransitionListener(listener);
+ public void setSharedElementListener(SharedElementListener listener) {
+ if (listener == null) {
+ listener = new SharedElementListener();
}
+ mTransitionListener = listener;
}
// ------------------ Internal API ------------------
@@ -5412,30 +5570,12 @@
mParent = parent;
}
- final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token,
- Application application, Intent intent, ActivityInfo info, CharSequence title,
- Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances,
- Configuration config) {
- attach(context, aThread, instr, token, 0, application, intent, info, title, parent, id,
- lastNonConfigurationInstances, config);
- }
-
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
- Configuration config) {
- attach(context, aThread, instr, token, ident, application, intent, info, title, parent, id,
- lastNonConfigurationInstances, config, null, null);
- }
-
- final void attach(Context context, ActivityThread aThread,
- Instrumentation instr, IBinder token, int ident,
- Application application, Intent intent, ActivityInfo info,
- CharSequence title, Activity parent, String id,
- NonConfigurationInstances lastNonConfigurationInstances,
- Configuration config, Bundle options, IVoiceInteractor voiceInteractor) {
+ Configuration config, IVoiceInteractor voiceInteractor) {
attachBaseContext(context);
mFragments.attachActivity(this, mContainer, null);
@@ -5476,12 +5616,6 @@
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
- if (options != null) {
- ActivityOptions activityOptions = new ActivityOptions(options);
- if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
- mEnterTransitionCoordinator = activityOptions.createEnterActivityTransition(this);
- }
- }
}
/** @hide */
@@ -5489,14 +5623,27 @@
return mParent != null ? mParent.getActivityToken() : mToken;
}
- final void performCreate(Bundle icicle) {
- onCreate(icicle);
+ final void performCreateCommon() {
mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
com.android.internal.R.styleable.Window_windowNoDisplay, false);
mFragments.dispatchActivityCreated();
+ mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
+ }
+
+ final void performCreate(Bundle icicle) {
+ onCreate(icicle);
+ mActivityTransitionState.readState(icicle);
+ performCreateCommon();
+ }
+
+ final void performCreate(Bundle icicle, PersistableBundle persistentState) {
+ onCreate(icicle, persistentState);
+ mActivityTransitionState.readState(icicle);
+ performCreateCommon();
}
final void performStart() {
+ mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
mFragments.noteStateNotSaved();
mCalled = false;
mFragments.execPendingActions();
@@ -5519,6 +5666,7 @@
lm.doReportStart();
}
}
+ mActivityTransitionState.enterReady(this);
}
final void performRestart() {
@@ -5743,7 +5891,7 @@
* occurred waiting for the Activity to complete drawing.
*
* @see Activity#convertFromTranslucent()
- * @see Activity#convertToTranslucent(TranslucentConversionListener)
+ * @see Activity#convertToTranslucent(TranslucentConversionListener, ActivityOptions)
*/
public void onTranslucentConversionComplete(boolean drawComplete);
}
diff --git a/core/java/android/app/ActivityManager.aidl b/core/java/android/app/ActivityManager.aidl
new file mode 100644
index 0000000..92350da
--- /dev/null
+++ b/core/java/android/app/ActivityManager.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+parcelable ActivityManager.RecentTaskInfo;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 044727d..1d05320 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -52,6 +52,7 @@
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -474,7 +475,7 @@
}
/**
- * Information you can set and retrieve about the current activity within Recents.
+ * Information you can set and retrieve about the current activity within the recent task list.
*/
public static class RecentsActivityValues implements Parcelable {
public CharSequence label;
@@ -879,7 +880,29 @@
readFromParcel(source);
}
}
-
+
+ /**
+ * Get the list of tasks associated with the calling application.
+ *
+ * @return The list of tasks associated with the application making this call.
+ * @throws SecurityException
+ */
+ public List<ActivityManager.AppTask> getAppTasks() {
+ ArrayList<AppTask> tasks = new ArrayList<AppTask>();
+ List<IAppTask> appTasks;
+ try {
+ appTasks = ActivityManagerNative.getDefault().getAppTasks();
+ } catch (RemoteException e) {
+ // System dead, we will be dead too soon!
+ return null;
+ }
+ int numAppTasks = appTasks.size();
+ for (int i = 0; i < numAppTasks; i++) {
+ tasks.add(new AppTask(appTasks.get(i)));
+ }
+ return tasks;
+ }
+
/**
* Return a list of the tasks that are currently running, with
* the most recent being first and older ones after in order. Note that
@@ -2382,4 +2405,42 @@
return false;
}
}
+
+ /**
+ * The AppTask allows you to manage your own application's tasks.
+ * See {@link android.app.ActivityManager#getAppTasks()}
+ */
+ public static class AppTask {
+ private IAppTask mAppTaskImpl;
+
+ /** @hide */
+ public AppTask(IAppTask task) {
+ mAppTaskImpl = task;
+ }
+
+ /**
+ * Finishes all activities in this task and removes it from the recent tasks list.
+ */
+ public void finishAndRemoveTask() {
+ try {
+ mAppTaskImpl.finishAndRemoveTask();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Invalid AppTask", e);
+ }
+ }
+
+ /**
+ * Get the RecentTaskInfo associated with this task.
+ *
+ * @return The RecentTaskInfo for this task, or null if the task no longer exists.
+ */
+ public RecentTaskInfo getTaskInfo() {
+ try {
+ return mAppTaskImpl.getTaskInfo();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Invalid AppTask", e);
+ return null;
+ }
+ }
+ }
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 57da21e..e704a1c 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -40,6 +40,7 @@
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
@@ -454,7 +455,8 @@
case ACTIVITY_PAUSED_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
- activityPaused(token);
+ PersistableBundle persistentState = data.readPersistableBundle();
+ activityPaused(token, persistentState);
reply.writeNoException();
return true;
}
@@ -463,10 +465,9 @@
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
Bundle map = data.readBundle();
- Bitmap thumbnail = data.readInt() != 0
- ? Bitmap.CREATOR.createFromParcel(data) : null;
+ PersistableBundle persistentState = data.readPersistableBundle();
CharSequence description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
- activityStopped(token, map, thumbnail, description);
+ activityStopped(token, map, persistentState, description);
reply.writeNoException();
return true;
}
@@ -505,6 +506,20 @@
return true;
}
+ case GET_APP_TASKS_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ List<IAppTask> list = getAppTasks();
+ reply.writeNoException();
+ int N = list != null ? list.size() : -1;
+ reply.writeInt(N);
+ int i;
+ for (i=0; i<N; i++) {
+ IAppTask task = list.get(i);
+ reply.writeStrongBinder(task.asBinder());
+ }
+ return true;
+ }
+
case GET_TASKS_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int maxNum = data.readInt();
@@ -1113,7 +1128,8 @@
int pid = data.readInt();
int uid = data.readInt();
int mode = data.readInt();
- int res = checkUriPermission(uri, pid, uid, mode);
+ int userId = data.readInt();
+ int res = checkUriPermission(uri, pid, uid, mode, userId);
reply.writeNoException();
reply.writeInt(res);
return true;
@@ -1138,7 +1154,8 @@
String targetPkg = data.readString();
Uri uri = Uri.CREATOR.createFromParcel(data);
int mode = data.readInt();
- grantUriPermission(app, targetPkg, uri, mode);
+ int userId = data.readInt();
+ grantUriPermission(app, targetPkg, uri, mode, userId);
reply.writeNoException();
return true;
}
@@ -1149,7 +1166,8 @@
IApplicationThread app = ApplicationThreadNative.asInterface(b);
Uri uri = Uri.CREATOR.createFromParcel(data);
int mode = data.readInt();
- revokeUriPermission(app, uri, mode);
+ int userId = data.readInt();
+ revokeUriPermission(app, uri, mode, userId);
reply.writeNoException();
return true;
}
@@ -1158,7 +1176,8 @@
data.enforceInterface(IActivityManager.descriptor);
Uri uri = Uri.CREATOR.createFromParcel(data);
int mode = data.readInt();
- takePersistableUriPermission(uri, mode);
+ int userId = data.readInt();
+ takePersistableUriPermission(uri, mode, userId);
reply.writeNoException();
return true;
}
@@ -1167,7 +1186,8 @@
data.enforceInterface(IActivityManager.descriptor);
Uri uri = Uri.CREATOR.createFromParcel(data);
int mode = data.readInt();
- releasePersistableUriPermission(uri, mode);
+ int userId = data.readInt();
+ releasePersistableUriPermission(uri, mode, userId);
reply.writeNoException();
return true;
}
@@ -1541,12 +1561,28 @@
case CONVERT_TO_TRANSLUCENT_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
- boolean converted = convertToTranslucent(token);
+ final Bundle bundle;
+ if (data.readInt() == 0) {
+ bundle = null;
+ } else {
+ bundle = data.readBundle();
+ }
+ final ActivityOptions options = bundle == null ? null : new ActivityOptions(bundle);
+ boolean converted = convertToTranslucent(token, options);
reply.writeNoException();
reply.writeInt(converted ? 1 : 0);
return true;
}
+ case GET_ACTIVITY_OPTIONS_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ final ActivityOptions options = getActivityOptions(token);
+ reply.writeNoException();
+ reply.writeBundle(options == null ? null : options.toBundle());
+ return true;
+ }
+
case SET_IMMERSIVE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
@@ -1601,7 +1637,8 @@
String targetPkg = data.readString();
Uri uri = Uri.CREATOR.createFromParcel(data);
int mode = data.readInt();
- grantUriPermissionFromOwner(owner, fromUid, targetPkg, uri, mode);
+ int userId = data.readInt();
+ grantUriPermissionFromOwner(owner, fromUid, targetPkg, uri, mode, userId);
reply.writeNoException();
return true;
}
@@ -1611,10 +1648,11 @@
IBinder owner = data.readStrongBinder();
Uri uri = null;
if (data.readInt() != 0) {
- Uri.CREATOR.createFromParcel(data);
+ uri = Uri.CREATOR.createFromParcel(data);
}
int mode = data.readInt();
- revokeUriPermissionFromOwner(owner, uri, mode);
+ int userId = data.readInt();
+ revokeUriPermissionFromOwner(owner, uri, mode, userId);
reply.writeNoException();
return true;
}
@@ -1625,7 +1663,8 @@
String targetPkg = data.readString();
Uri uri = Uri.CREATOR.createFromParcel(data);
int modeFlags = data.readInt();
- int res = checkGrantUriPermission(callingUid, targetPkg, uri, modeFlags);
+ int userId = data.readInt();
+ int res = checkGrantUriPermission(callingUid, targetPkg, uri, modeFlags, userId);
reply.writeNoException();
reply.writeInt(res);
return true;
@@ -2583,31 +2622,27 @@
data.recycle();
reply.recycle();
}
- public void activityPaused(IBinder token) throws RemoteException
+ public void activityPaused(IBinder token, PersistableBundle persistentState) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
+ data.writePersistableBundle(persistentState);
mRemote.transact(ACTIVITY_PAUSED_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
public void activityStopped(IBinder token, Bundle state,
- Bitmap thumbnail, CharSequence description) throws RemoteException
+ PersistableBundle persistentState, CharSequence description) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
data.writeBundle(state);
- if (thumbnail != null) {
- data.writeInt(1);
- thumbnail.writeToParcel(data, 0);
- } else {
- data.writeInt(0);
- }
+ data.writePersistableBundle(persistentState);
TextUtils.writeToParcel(description, data, 0);
mRemote.transact(ACTIVITY_STOPPED_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
reply.readException();
@@ -2662,6 +2697,26 @@
reply.recycle();
return res;
}
+ public List<IAppTask> getAppTasks() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(GET_APP_TASKS_TRANSACTION, data, reply, 0);
+ reply.readException();
+ ArrayList<IAppTask> list = null;
+ int N = reply.readInt();
+ if (N >= 0) {
+ list = new ArrayList<IAppTask>();
+ while (N > 0) {
+ IAppTask task = IAppTask.Stub.asInterface(reply.readStrongBinder());
+ list.add(task);
+ N--;
+ }
+ }
+ data.recycle();
+ reply.recycle();
+ return list;
+ }
public List getTasks(int maxNum, int flags) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -2677,7 +2732,7 @@
while (N > 0) {
ActivityManager.RunningTaskInfo info =
ActivityManager.RunningTaskInfo.CREATOR
- .createFromParcel(reply);
+ .createFromParcel(reply);
list.add(info);
N--;
}
@@ -3543,7 +3598,7 @@
reply.recycle();
return res;
}
- public int checkUriPermission(Uri uri, int pid, int uid, int mode)
+ public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -3552,6 +3607,7 @@
data.writeInt(pid);
data.writeInt(uid);
data.writeInt(mode);
+ data.writeInt(userId);
mRemote.transact(CHECK_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
@@ -3560,7 +3616,7 @@
return res;
}
public void grantUriPermission(IApplicationThread caller, String targetPkg,
- Uri uri, int mode) throws RemoteException {
+ Uri uri, int mode, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -3568,19 +3624,21 @@
data.writeString(targetPkg);
uri.writeToParcel(data, 0);
data.writeInt(mode);
+ data.writeInt(userId);
mRemote.transact(GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
public void revokeUriPermission(IApplicationThread caller, Uri uri,
- int mode) throws RemoteException {
+ int mode, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller.asBinder());
uri.writeToParcel(data, 0);
data.writeInt(mode);
+ data.writeInt(userId);
mRemote.transact(REVOKE_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
@@ -3588,12 +3646,14 @@
}
@Override
- public void takePersistableUriPermission(Uri uri, int mode) throws RemoteException {
+ public void takePersistableUriPermission(Uri uri, int mode, int userId)
+ throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
uri.writeToParcel(data, 0);
data.writeInt(mode);
+ data.writeInt(userId);
mRemote.transact(TAKE_PERSISTABLE_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
@@ -3601,12 +3661,14 @@
}
@Override
- public void releasePersistableUriPermission(Uri uri, int mode) throws RemoteException {
+ public void releasePersistableUriPermission(Uri uri, int mode, int userId)
+ throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
uri.writeToParcel(data, 0);
data.writeInt(mode);
+ data.writeInt(userId);
mRemote.transact(RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
@@ -4062,12 +4124,18 @@
return res;
}
- public boolean convertToTranslucent(IBinder token)
+ public boolean convertToTranslucent(IBinder token, ActivityOptions options)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
+ if (options == null) {
+ data.writeInt(0);
+ } else {
+ data.writeInt(1);
+ data.writeBundle(options.toBundle());
+ }
mRemote.transact(CONVERT_TO_TRANSLUCENT_TRANSACTION, data, reply, 0);
reply.readException();
boolean res = reply.readInt() != 0;
@@ -4076,6 +4144,20 @@
return res;
}
+ public ActivityOptions getActivityOptions(IBinder token) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(GET_ACTIVITY_OPTIONS_TRANSACTION, data, reply, 0);
+ reply.readException();
+ Bundle bundle = reply.readBundle();
+ ActivityOptions options = bundle == null ? null : new ActivityOptions(bundle);
+ data.recycle();
+ reply.recycle();
+ return options;
+ }
+
public void setImmersive(IBinder token, boolean immersive)
throws RemoteException {
Parcel data = Parcel.obtain();
@@ -4160,7 +4242,7 @@
}
public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
- Uri uri, int mode) throws RemoteException {
+ Uri uri, int mode, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -4169,6 +4251,7 @@
data.writeString(targetPkg);
uri.writeToParcel(data, 0);
data.writeInt(mode);
+ data.writeInt(userId);
mRemote.transact(GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
@@ -4176,7 +4259,7 @@
}
public void revokeUriPermissionFromOwner(IBinder owner, Uri uri,
- int mode) throws RemoteException {
+ int mode, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -4188,6 +4271,7 @@
data.writeInt(0);
}
data.writeInt(mode);
+ data.writeInt(userId);
mRemote.transact(REVOKE_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
@@ -4195,7 +4279,7 @@
}
public int checkGrantUriPermission(int callingUid, String targetPkg,
- Uri uri, int modeFlags) throws RemoteException {
+ Uri uri, int modeFlags, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -4203,6 +4287,7 @@
data.writeString(targetPkg);
uri.writeToParcel(data, 0);
data.writeInt(modeFlags);
+ data.writeInt(userId);
mRemote.transact(CHECK_GRANT_URI_PERMISSION_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index a49359f..a057c3e 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -17,18 +17,18 @@
package android.app;
import android.content.Context;
+import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.transition.Transition;
-import android.util.ArrayMap;
import android.util.Pair;
import android.view.View;
import android.view.Window;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -108,6 +108,12 @@
private static final String KEY_TRANSITION_COMPLETE_LISTENER
= "android:transitionCompleteListener";
+ private static final String KEY_TRANSITION_IS_RETURNING = "android:transitionIsReturning";
+ private static final String KEY_TRANSITION_SHARED_ELEMENTS = "android:sharedElementNames";
+ private static final String KEY_LOCAL_SHARED_ELEMENTS = "android:localSharedElementNames";
+ private static final String KEY_RESULT_DATA = "android:resultData";
+ private static final String KEY_RESULT_CODE = "android:resultCode";
+
/** @hide */
public static final int ANIM_NONE = 0;
/** @hide */
@@ -131,7 +137,12 @@
private int mStartWidth;
private int mStartHeight;
private IRemoteCallback mAnimationStartedListener;
- private ResultReceiver mExitReceiver;
+ private ResultReceiver mTransitionReceiver;
+ private boolean mIsReturning;
+ private ArrayList<String> mSharedElementNames;
+ private ArrayList<String> mLocalSharedElementNames;
+ private Intent mResultData;
+ private int mResultCode;
/**
* Create an ActivityOptions specifying a custom animation to run when
@@ -334,7 +345,7 @@
* <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be
* enabled on the calling Activity to cause an exit transition. The same must be in
* the called Activity to get an entering transition.</p>
- * @param window The window containing shared elements.
+ * @param activity The Activity whose window contains the shared elements.
* @param sharedElement The View to transition to the started Activity. sharedElement must
* have a non-null sharedElementName.
* @param sharedElementName The shared element name as used in the target Activity. This may
@@ -344,36 +355,70 @@
* @see android.transition.Transition#setEpicenterCallback(
* android.transition.Transition.EpicenterCallback)
*/
- public static ActivityOptions makeSceneTransitionAnimation(Window window,
+ public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
View sharedElement, String sharedElementName) {
- return makeSceneTransitionAnimation(window,
- new SharedElementMappingListener(sharedElement, sharedElementName));
+ return makeSceneTransitionAnimation(activity, Pair.create(sharedElement, sharedElementName));
}
/**
* Create an ActivityOptions to transition between Activities using cross-Activity scene
* animations. This method carries the position of multiple shared elements to the started
- * Activity. The position of the first element in the value returned from
- * {@link android.app.ActivityOptions.ActivityTransitionListener#getSharedElementsMapping()}
+ * Activity. The position of the first element in sharedElements
* will be used as the epicenter for the exit Transition. The position of the associated
* shared element in the launched Activity will be the epicenter of its entering Transition.
*
* <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be
* enabled on the calling Activity to cause an exit transition. The same must be in
* the called Activity to get an entering transition.</p>
- * @param window The window containing shared elements.
- * @param listener The listener to use to monitor activity transition events.
+ * @param activity The Activity whose window contains the shared elements.
+ * @param sharedElements The names of the shared elements to transfer to the called
+ * Activity and their associated Views. The Views must each have
+ * a unique shared element name.
* @return Returns a new ActivityOptions object that you can use to
* supply these options as the options Bundle when starting an activity.
+ * Returns null if the Window does not have {@link Window#FEATURE_CONTENT_TRANSITIONS}.
* @see android.transition.Transition#setEpicenterCallback(
* android.transition.Transition.EpicenterCallback)
*/
- public static ActivityOptions makeSceneTransitionAnimation(Window window,
- ActivityTransitionListener listener) {
+ public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
+ Pair<View, String>... sharedElements) {
+ if (!activity.getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
+ return null;
+ }
ActivityOptions opts = new ActivityOptions();
opts.mAnimationType = ANIM_SCENE_TRANSITION;
- ExitTransitionCoordinator exit = new ExitTransitionCoordinator(window, listener);
- opts.mExitReceiver = exit;
+
+ ArrayList<String> names = new ArrayList<String>();
+ ArrayList<String> mappedNames = new ArrayList<String>();
+
+ if (sharedElements != null) {
+ for (int i = 0; i < sharedElements.length; i++) {
+ Pair<View, String> sharedElement = sharedElements[i];
+ names.add(sharedElement.second);
+ mappedNames.add(sharedElement.first.getViewName());
+ }
+ }
+
+ ExitTransitionCoordinator exit = new ExitTransitionCoordinator(activity, names, names,
+ mappedNames, false);
+ opts.mTransitionReceiver = exit;
+ opts.mSharedElementNames = names;
+ opts.mLocalSharedElementNames = mappedNames;
+ opts.mIsReturning = false;
+ return opts;
+ }
+
+ /** @hide */
+ public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
+ ExitTransitionCoordinator exitCoordinator, ArrayList<String> sharedElementNames,
+ int resultCode, Intent resultData) {
+ ActivityOptions opts = new ActivityOptions();
+ opts.mAnimationType = ANIM_SCENE_TRANSITION;
+ opts.mSharedElementNames = sharedElementNames;
+ opts.mTransitionReceiver = exitCoordinator;
+ opts.mIsReturning = true;
+ opts.mResultCode = resultCode;
+ opts.mResultData = resultData;
return opts;
}
@@ -409,7 +454,12 @@
break;
case ANIM_SCENE_TRANSITION:
- mExitReceiver = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER);
+ mTransitionReceiver = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER);
+ mIsReturning = opts.getBoolean(KEY_TRANSITION_IS_RETURNING, false);
+ mSharedElementNames = opts.getStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS);
+ mLocalSharedElementNames = opts.getStringArrayList(KEY_LOCAL_SHARED_ELEMENTS);
+ mResultData = opts.getParcelable(KEY_RESULT_DATA);
+ mResultCode = opts.getInt(KEY_RESULT_CODE);
break;
}
}
@@ -466,15 +516,15 @@
/** @hide */
public void dispatchActivityStopped() {
- if (mExitReceiver != null) {
- mExitReceiver.send(ActivityTransitionCoordinator.MSG_ACTIVITY_STOPPED, null);
+ if (mTransitionReceiver != null) {
+ mTransitionReceiver.send(ActivityTransitionCoordinator.MSG_ACTIVITY_STOPPED, null);
}
}
/** @hide */
public void dispatchStartExit() {
- if (mExitReceiver != null) {
- mExitReceiver.send(ActivityTransitionCoordinator.MSG_START_EXIT_TRANSITION, null);
+ if (mTransitionReceiver != null) {
+ mTransitionReceiver.send(ActivityTransitionCoordinator.MSG_START_EXIT_TRANSITION, null);
}
}
@@ -489,21 +539,39 @@
}
/** @hide */
+ public void setReturning() {
+ mIsReturning = true;
+ }
+
+ /** @hide */
+ public boolean isReturning() {
+ return mIsReturning;
+ }
+
+ /** @hide */
+ public ArrayList<String> getSharedElementNames() {
+ return mSharedElementNames;
+ }
+
+ /** @hide */
+ public ArrayList<String> getLocalSharedElementNames() { return mLocalSharedElementNames; }
+
+ /** @hide */
+ public ResultReceiver getResultReceiver() { return mTransitionReceiver; }
+
+ /** @hide */
+ public int getResultCode() { return mResultCode; }
+
+ /** @hide */
+ public Intent getResultData() { return mResultData; }
+
+ /** @hide */
public static void abort(Bundle options) {
if (options != null) {
(new ActivityOptions(options)).abort();
}
}
- /** @hide */
- public EnterTransitionCoordinator createEnterActivityTransition(Activity activity) {
- EnterTransitionCoordinator coordinator = null;
- if (mAnimationType == ANIM_SCENE_TRANSITION) {
- coordinator = new EnterTransitionCoordinator(activity, mExitReceiver);
- }
- return coordinator;
- }
-
/**
* Update the current values in this ActivityOptions from those supplied
* in <var>otherOptions</var>. Any values
@@ -513,7 +581,12 @@
if (otherOptions.mPackageName != null) {
mPackageName = otherOptions.mPackageName;
}
- mExitReceiver = null;
+ mTransitionReceiver = null;
+ mSharedElementNames = null;
+ mLocalSharedElementNames = null;
+ mIsReturning = false;
+ mResultData = null;
+ mResultCode = 0;
switch (otherOptions.mAnimationType) {
case ANIM_CUSTOM:
mAnimationType = otherOptions.mAnimationType;
@@ -558,9 +631,14 @@
break;
case ANIM_SCENE_TRANSITION:
mAnimationType = otherOptions.mAnimationType;
- mExitReceiver = otherOptions.mExitReceiver;
+ mTransitionReceiver = otherOptions.mTransitionReceiver;
+ mSharedElementNames = otherOptions.mSharedElementNames;
+ mLocalSharedElementNames = otherOptions.mLocalSharedElementNames;
+ mIsReturning = otherOptions.mIsReturning;
mThumbnail = null;
mAnimationStartedListener = null;
+ mResultData = otherOptions.mResultData;
+ mResultCode = otherOptions.mResultCode;
break;
}
}
@@ -604,9 +682,14 @@
break;
case ANIM_SCENE_TRANSITION:
b.putInt(KEY_ANIM_TYPE, mAnimationType);
- if (mExitReceiver != null) {
- b.putParcelable(KEY_TRANSITION_COMPLETE_LISTENER, mExitReceiver);
+ if (mTransitionReceiver != null) {
+ b.putParcelable(KEY_TRANSITION_COMPLETE_LISTENER, mTransitionReceiver);
}
+ b.putBoolean(KEY_TRANSITION_IS_RETURNING, mIsReturning);
+ b.putStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS, mSharedElementNames);
+ b.putStringArrayList(KEY_LOCAL_SHARED_ELEMENTS, mLocalSharedElementNames);
+ b.putParcelable(KEY_RESULT_DATA, mResultData);
+ b.putInt(KEY_RESULT_CODE, mResultCode);
break;
}
return b;
@@ -626,126 +709,4 @@
return null;
}
- /**
- * Listener provided in
- * {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
- * android.app.ActivityOptions.ActivityTransitionListener)} or in
- * {@link android.app.Activity#setActivityTransitionListener(
- * android.app.ActivityOptions.ActivityTransitionListener)} to monitor the Activity transitions.
- * The events can be used to customize or override Activity Transition behavior.
- */
- public static class ActivityTransitionListener {
- /**
- * Called when the enter Transition is ready to start, but hasn't started yet. If
- * {@link android.view.Window#getEnterTransition()} is non-null,
- * The entering views will be {@link View#INVISIBLE}.
- */
- public void onEnterReady() {}
-
- /**
- * Called when the remote exiting transition completes.
- */
- public void onRemoteExitComplete() {}
-
- /**
- * Called when the start state for shared elements is captured on enter.
- *
- * @param sharedElementNames The names of the shared elements that were accepted into
- * the View hierarchy.
- * @param sharedElements The shared elements that are part of the View hierarchy.
- * @param sharedElementSnapshots The Views containing snap shots of the shared element
- * from the launching Window. These elements will not
- * be part of the scene, but will be positioned relative
- * to the Window decor View.
- */
- public void onCaptureSharedElementStart(List<String> sharedElementNames,
- List<View> sharedElements, List<View> sharedElementSnapshots) {}
-
- /**
- * Called when the end state for shared elements is captured on enter.
- *
- * @param sharedElementNames The names of the shared elements that were accepted into
- * the View hierarchy.
- * @param sharedElements The shared elements that are part of the View hierarchy.
- * @param sharedElementSnapshots The Views containing snap shots of the shared element
- * from the launching Window. These elements will not
- * be part of the scene, but will be positioned relative
- * to the Window decor View.
- */
- public void onCaptureSharedElementEnd(List<String> sharedElementNames,
- List<View> sharedElements, List<View> sharedElementSnapshots) {}
-
- /**
- * Called when the enter Transition has been started.
- * @param sharedElementNames The names of shared elements that were transferred.
- * @param sharedElements The shared elements that were transferred.
- */
- public void onStartEnterTransition(List<String> sharedElementNames,
- List<View> sharedElements) {}
-
- /**
- * Called when the exit Transition has been started.
- * @param sharedElementNames The names of all shared elements that will be transferred.
- * @param sharedElements All shared elements that will be transferred.
- */
- public void onStartExitTransition(List<String> sharedElementNames,
- List<View> sharedElements) {}
-
- /**
- * Called when the exiting shared element transition completes.
- */
- public void onSharedElementExitTransitionComplete() {}
-
- /**
- * Called on exit when the shared element has been transferred.
- * @param sharedElementNames The names of all shared elements that were transferred.
- * @param sharedElements All shared elements that will were transferred.
- */
- public void onSharedElementTransferred(List<String> sharedElementNames,
- List<View> sharedElements) {}
-
- /**
- * Called when the exit transition has completed.
- */
- public void onExitTransitionComplete() {}
-
- /**
- * Returns a mapping from a View in the View hierarchy to the shared element name used
- * in the call. This is called twice -- once when the view is
- * entering and again when it exits. A null return value indicates that the
- * View hierachy can be trusted without any remapping.
- * @return A map from a View in the hierarchy to the shared element name used in the
- * call.
- */
- public Pair<View, String>[] getSharedElementsMapping() { return null; }
-
- /**
- * Returns <code>true</code> if the ActivityTransitionListener will handle removing
- * rejected shared elements from the scene. If <code>false</code> is returned, a default
- * animation will be used to remove the rejected shared elements from the scene.
- *
- * @param rejectedSharedElements Views containing visual information of shared elements
- * that are not part of the entering scene. These Views
- * are positioned relative to the Window decor View.
- * @return <code>false</code> if the default animation should be used to remove the
- * rejected shared elements from the scene or <code>true</code> if the listener provides
- * custom handling.
- */
- public boolean handleRejectedSharedElements(List<View> rejectedSharedElements) {
- return false;
- }
- }
-
- private static class SharedElementMappingListener extends ActivityTransitionListener {
- Pair<View, String>[] mSharedElementsMapping = new Pair[1];
-
- public SharedElementMappingListener(View view, String name) {
- mSharedElementsMapping[0] = Pair.create(view, name);
- }
-
- @Override
- public Pair<View, String>[] getSharedElementsMapping() {
- return mSharedElementsMapping;
- }
- }
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b606088..71e4e82 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -47,6 +47,7 @@
import android.net.IConnectivityManager;
import android.net.Proxy;
import android.net.ProxyInfo;
+import android.net.Uri;
import android.opengl.GLUtils;
import android.os.AsyncTask;
import android.os.Binder;
@@ -56,11 +57,11 @@
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
-import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -69,8 +70,6 @@
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
-import android.transition.Scene;
-import android.transition.TransitionManager;
import android.provider.Settings;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
@@ -78,7 +77,6 @@
import android.util.EventLog;
import android.util.Log;
import android.util.LogPrinter;
-import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SuperNotCalledException;
@@ -268,6 +266,7 @@
Intent intent;
IVoiceInteractor voiceInteractor;
Bundle state;
+ PersistableBundle persistentState;
Activity activity;
Window window;
Activity parent;
@@ -295,7 +294,6 @@
boolean isForward;
int pendingConfigChanges;
boolean onlyLocalRequest;
- Bundle activityOptions;
View mPendingRemoveWindow;
WindowManager mPendingRemoveWindowManager;
@@ -317,6 +315,10 @@
return false;
}
+ public boolean isPersistable() {
+ return (activityInfo.flags & ActivityInfo.FLAG_PERSISTABLE) != 0;
+ }
+
public String toString() {
ComponentName componentName = intent != null ? intent.getComponent() : null;
return "ActivityRecord{"
@@ -590,8 +592,7 @@
public final void scheduleResumeActivity(IBinder token, int processState,
boolean isForward, Bundle resumeArgs) {
updateProcessState(processState, false);
- sendMessage(H.RESUME_ACTIVITY, new Pair<IBinder, Bundle>(token, resumeArgs),
- isForward ? 1 : 0);
+ sendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0);
}
public final void scheduleSendResult(IBinder token, List<ResultInfo> results) {
@@ -605,11 +606,10 @@
// activity itself back to the activity manager. (matters more with ipc)
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
- IVoiceInteractor voiceInteractor,
- int procState, Bundle state, List<ResultInfo> pendingResults,
+ IVoiceInteractor voiceInteractor, int procState, Bundle state,
+ PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
- String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
- Bundle resumeArgs) {
+ String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
updateProcessState(procState, false);
@@ -622,6 +622,7 @@
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
+ r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
@@ -632,7 +633,6 @@
r.profileFile = profileName;
r.profileFd = profileFd;
r.autoStopProfiler = autoStopProfiler;
- r.activityOptions = resumeArgs;
updatePendingConfiguration(curConfig);
@@ -835,7 +835,7 @@
InetAddress.clearDnsCache();
}
- public void setHttpProxy(String host, String port, String exclList, String pacFileUrl) {
+ public void setHttpProxy(String host, String port, String exclList, Uri pacFileUrl) {
Proxy.setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
}
@@ -1297,9 +1297,7 @@
break;
case RESUME_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
- final Pair<IBinder, Bundle> resumeArgs = (Pair<IBinder, Bundle>) msg.obj;
- handleResumeActivity(resumeArgs.first, resumeArgs.second, true,
- msg.arg1 != 0, true);
+ handleResumeActivity((IBinder) msg.obj, true, msg.arg1 != 0, true);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SEND_RESULT:
@@ -2079,7 +2077,7 @@
+ ", comp=" + name
+ ", token=" + token);
}
- return performLaunchActivity(r, null, null);
+ return performLaunchActivity(r, null);
}
public final Activity getActivity(IBinder token) {
@@ -2132,8 +2130,7 @@
sendMessage(H.CLEAN_UP_CONTEXT, cci);
}
- private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent,
- Bundle options) {
+ private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
ActivityInfo aInfo = r.activityInfo;
@@ -2191,7 +2188,7 @@
+ r.activityInfo.name + " with config " + config);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
- r.embeddedID, r.lastNonConfigurationInstances, config, options,
+ r.embeddedID, r.lastNonConfigurationInstances, config,
r.voiceInteractor);
if (customIntent != null) {
@@ -2205,7 +2202,11 @@
}
activity.mCalled = false;
- mInstrumentation.callActivityOnCreate(activity, r.state);
+ if (r.isPersistable()) {
+ mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
+ } else {
+ mInstrumentation.callActivityOnCreate(activity, r.state);
+ }
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
@@ -2218,13 +2219,23 @@
r.stopped = false;
}
if (!r.activity.mFinished) {
- if (r.state != null) {
+ if (r.isPersistable()) {
+ if (r.state != null || r.persistentState != null) {
+ mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
+ r.persistentState);
+ }
+ } else if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
- mInstrumentation.callActivityOnPostCreate(activity, r.state);
+ if (r.isPersistable()) {
+ mInstrumentation.callActivityOnPostCreate(activity, r.state,
+ r.persistentState);
+ } else {
+ mInstrumentation.callActivityOnPostCreate(activity, r.state);
+ }
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
@@ -2303,12 +2314,12 @@
if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);
- Activity a = performLaunchActivity(r, customIntent, r.activityOptions);
+ Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
- handleResumeActivity(r.token, r.activityOptions, false, r.isForward,
+ handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);
if (!r.activity.mFinished && r.startsNotResumed) {
@@ -2842,6 +2853,7 @@
r.paused = false;
r.stopped = false;
r.state = null;
+ r.persistentState = null;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
@@ -2867,7 +2879,7 @@
r.mPendingRemoveWindowManager = null;
}
- final void handleResumeActivity(IBinder token, Bundle resumeArgs,
+ final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
@@ -3069,7 +3081,7 @@
// Tell the activity manager we have paused.
try {
- ActivityManagerNative.getDefault().activityPaused(token);
+ ActivityManagerNative.getDefault().activityPaused(token, r.persistentState);
} catch (RemoteException ex) {
}
}
@@ -3099,17 +3111,13 @@
+ r.intent.getComponent().toShortString());
Slog.e(TAG, e.getMessage(), e);
}
- Bundle state = null;
if (finished) {
r.activity.mFinished = true;
}
try {
// Next have the activity save its current state and managed dialogs...
if (!r.activity.mFinished && saveState) {
- state = new Bundle();
- state.setAllowFds(false);
- mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
- r.state = state;
+ callCallActivityOnSaveInstanceState(r);
}
// Now we are idle.
r.activity.mCalled = false;
@@ -3145,7 +3153,7 @@
listeners.get(i).onPaused(r.activity);
}
- return state;
+ return !r.activity.mFinished && saveState ? r.state : null;
}
final void performStopActivity(IBinder token, boolean saveState) {
@@ -3156,7 +3164,7 @@
private static class StopInfo implements Runnable {
ActivityClientRecord activity;
Bundle state;
- Bitmap thumbnail;
+ PersistableBundle persistentState;
CharSequence description;
@Override public void run() {
@@ -3164,7 +3172,7 @@
try {
if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + activity);
ActivityManagerNative.getDefault().activityStopped(
- activity.token, state, thumbnail, description);
+ activity.token, state, persistentState, description);
} catch (RemoteException ex) {
}
}
@@ -3203,7 +3211,6 @@
private void performStopActivityInner(ActivityClientRecord r,
StopInfo info, boolean keepShown, boolean saveState) {
if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
- Bundle state = null;
if (r != null) {
if (!keepShown && r.stopped) {
if (r.activity.mFinished) {
@@ -3223,7 +3230,6 @@
// First create a thumbnail for the activity...
// For now, don't create the thumbnail here; we are
// doing that by doing a screen snapshot.
- info.thumbnail = null; //createThumbnailBitmap(r);
info.description = r.activity.onCreateDescription();
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
@@ -3238,12 +3244,7 @@
// Next have the activity save its current state and managed dialogs...
if (!r.activity.mFinished && saveState) {
if (r.state == null) {
- state = new Bundle();
- state.setAllowFds(false);
- mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
- r.state = state;
- } else {
- state = r.state;
+ callCallActivityOnSaveInstanceState(r);
}
}
@@ -3319,6 +3320,7 @@
// manager to proceed and allow us to go fully into the background.
info.activity = r;
info.state = r.state;
+ info.persistentState = r.persistentState;
mH.post(info);
}
@@ -3775,9 +3777,7 @@
performPauseActivity(r.token, false, r.isPreHoneycomb());
}
if (r.state == null && !r.stopped && !r.isPreHoneycomb()) {
- r.state = new Bundle();
- r.state.setAllowFds(false);
- mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
+ callCallActivityOnSaveInstanceState(r);
}
handleDestroyActivity(r.token, false, configChanges, true);
@@ -3802,11 +3802,22 @@
}
}
r.startsNotResumed = tmp.startsNotResumed;
- r.activityOptions = null;
handleLaunchActivity(r, currentIntent);
}
+ private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
+ r.state = new Bundle();
+ r.state.setAllowFds(false);
+ if (r.isPersistable()) {
+ r.persistentState = new PersistableBundle();
+ mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,
+ r.persistentState);
+ } else {
+ mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
+ }
+ }
+
ArrayList<ComponentCallbacks2> collectComponentCallbacks(
boolean allActivities, Configuration newConfig) {
ArrayList<ComponentCallbacks2> callbacks
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 3eb2fea..6c6a52f 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -15,27 +15,14 @@
*/
package android.app;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
import android.graphics.Rect;
-import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
import android.transition.Transition;
-import android.transition.TransitionManager;
import android.transition.TransitionSet;
import android.util.ArrayMap;
-import android.util.Pair;
-import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewGroupOverlay;
-import android.view.ViewTreeObserver;
import android.view.Window;
import android.widget.ImageView;
@@ -83,14 +70,13 @@
* - onActivityStopped() is called and all exited Views are made VISIBLE.
*
* Typical finishWithTransition goes like this:
- * 1) finishWithTransition() calls startExit()
- * - The Window start transitioning to Translucent
+ * 1) finishWithTransition() creates an ExitTransitionCoordinator and calls startExit()
+ * - The Window start transitioning to Translucent with a new ActivityOptions.
* - If no background exists, a black background is substituted
- * - MSG_PREPARE_RESTORE is sent to the ExitTransitionCoordinator
* - The shared elements in the scene are matched against those shared elements
* that were sent by comparing the names.
* - The exit transition is started by setting Views to INVISIBLE.
- * 2) MSG_PREPARE_RESTORE is received by the EnterTransitionCoordinator
+ * 2) The ActivityOptions is received by the Activity and an EnterTransitionCoordinator is created.
* - All transitioning views are made VISIBLE to reverse what was done when onActivityStopped()
* was called
* 3) The Window is made translucent and a callback is received
@@ -98,21 +84,21 @@
* 4) The background alpha animation completes
* 5) The shared element transition completes
* - After both 4 & 5 complete, MSG_TAKE_SHARED_ELEMENTS is sent to the
- * ExitTransitionCoordinator
- * 6) MSG_TAKE_SHARED_ELEMENTS is received by ExitTransitionCoordinator
+ * EnterTransitionCoordinator
+ * 6) MSG_TAKE_SHARED_ELEMENTS is received by EnterTransitionCoordinator
* - Shared elements are made VISIBLE
* - Shared elements positions and size are set to match the end state of the calling
* Activity.
* - The shared element transition is started
* - If the window allows overlapping transitions, the views transition is started by setting
* the entering Views to VISIBLE.
- * - MSG_HIDE_SHARED_ELEMENTS is sent to the EnterTransitionCoordinator
- * 7) MSG_HIDE_SHARED_ELEMENTS is received by the EnterTransitionCoordinator
+ * - MSG_HIDE_SHARED_ELEMENTS is sent to the ExitTransitionCoordinator
+ * 7) MSG_HIDE_SHARED_ELEMENTS is received by the ExitTransitionCoordinator
* - The shared elements are made INVISIBLE
* 8) The exit transition completes in the finishing Activity.
- * - MSG_EXIT_TRANSITION_COMPLETE is sent to the ExitTransitionCoordinator.
+ * - MSG_EXIT_TRANSITION_COMPLETE is sent to the EnterTransitionCoordinator.
* - finish() is called on the exiting Activity
- * 9) The MSG_EXIT_TRANSITION_COMPLETE is received by the ExitTransitionCoordinator.
+ * 9) The MSG_EXIT_TRANSITION_COMPLETE is received by the EnterTransitionCoordinator.
* - If the window doesn't allow overlapping enter transitions, the enter transition is started
* by setting entering views to VISIBLE.
*/
@@ -120,30 +106,24 @@
private static final String TAG = "ActivityTransitionCoordinator";
/**
- * The names of shared elements that are transitioned to the started Activity.
- * This is also the name of shared elements that the started Activity accepted.
- */
- public static final String KEY_SHARED_ELEMENT_NAMES = "android:shared_element_names";
-
- public static final String KEY_SHARED_ELEMENT_STATE = "android:shared_element_state";
-
- /**
* For Activity transitions, the called Activity's listener to receive calls
* when transitions complete.
*/
- static final String KEY_TRANSITION_RESULTS_RECEIVER = "android:transitionTargetListener";
+ static final String KEY_REMOTE_RECEIVER = "android:remoteReceiver";
- private static final String KEY_SCREEN_X = "shared_element:screenX";
- private static final String KEY_SCREEN_Y = "shared_element:screenY";
- private static final String KEY_TRANSLATION_Z = "shared_element:translationZ";
- private static final String KEY_WIDTH = "shared_element:width";
- private static final String KEY_HEIGHT = "shared_element:height";
- private static final String KEY_NAME = "shared_element:name";
- private static final String KEY_BITMAP = "shared_element:bitmap";
- private static final String KEY_SCALE_TYPE = "shared_element:scaleType";
- private static final String KEY_IMAGE_MATRIX = "shared_element:imageMatrix";
+ protected static final String KEY_SCREEN_X = "shared_element:screenX";
+ protected static final String KEY_SCREEN_Y = "shared_element:screenY";
+ protected static final String KEY_TRANSLATION_Z = "shared_element:translationZ";
+ protected static final String KEY_WIDTH = "shared_element:width";
+ protected static final String KEY_HEIGHT = "shared_element:height";
+ protected static final String KEY_BITMAP = "shared_element:bitmap";
+ protected static final String KEY_SCALE_TYPE = "shared_element:scaleType";
+ protected static final String KEY_IMAGE_MATRIX = "shared_element:imageMatrix";
- private static final ImageView.ScaleType[] SCALE_TYPE_VALUES = ImageView.ScaleType.values();
+ // The background fade in/out duration. 150ms is pretty quick, but not abrupt.
+ public static final int FADE_BACKGROUND_DURATION_MS = 150;
+
+ protected static final ImageView.ScaleType[] SCALE_TYPE_VALUES = ImageView.ScaleType.values();
/**
* Sent by the exiting coordinator (either EnterTransitionCoordinator
@@ -154,7 +134,7 @@
* until this message is received, but may wait for
* MSG_EXIT_TRANSITION_COMPLETE if allowOverlappingTransitions() is true.
*/
- public static final int MSG_SET_LISTENER = 100;
+ public static final int MSG_SET_REMOTE_RECEIVER = 100;
/**
* Sent by the entering coordinator to tell the exiting coordinator
@@ -165,17 +145,10 @@
public static final int MSG_HIDE_SHARED_ELEMENTS = 101;
/**
- * Sent by the EnterTransitionCoordinator to tell the
- * ExitTransitionCoordinator to hide all of its exited views after
- * MSG_ACTIVITY_STOPPED has caused them all to show.
- */
- public static final int MSG_PREPARE_RESTORE = 102;
-
- /**
* Sent by the exiting Activity in ActivityOptions#dispatchActivityStopped
* to leave the Activity in a good state after it has been hidden.
*/
- public static final int MSG_ACTIVITY_STOPPED = 103;
+ public static final int MSG_ACTIVITY_STOPPED = 102;
/**
* Sent by the exiting coordinator (either EnterTransitionCoordinator
@@ -186,7 +159,7 @@
* until this message is received, but may wait for
* MSG_EXIT_TRANSITION_COMPLETE if allowOverlappingTransitions() is true.
*/
- public static final int MSG_TAKE_SHARED_ELEMENTS = 104;
+ public static final int MSG_TAKE_SHARED_ELEMENTS = 103;
/**
* Sent by the exiting coordinator (either
@@ -196,309 +169,41 @@
* remote coordinator. If it is false, it will trigger the enter
* transition to start.
*/
- public static final int MSG_EXIT_TRANSITION_COMPLETE = 105;
+ public static final int MSG_EXIT_TRANSITION_COMPLETE = 104;
/**
* Sent by Activity#startActivity to begin the exit transition.
*/
- public static final int MSG_START_EXIT_TRANSITION = 106;
+ public static final int MSG_START_EXIT_TRANSITION = 105;
- private Window mWindow;
- private ArrayList<View> mSharedElements = new ArrayList<View>();
- private ArrayList<String> mTargetSharedNames = new ArrayList<String>();
- private ActivityOptions.ActivityTransitionListener mListener =
- new ActivityOptions.ActivityTransitionListener();
- private ArrayList<View> mEnteringViews;
- private ResultReceiver mRemoteResultReceiver;
- private boolean mNotifiedSharedElementTransitionComplete;
- private boolean mNotifiedExitTransitionComplete;
- private boolean mSharedElementTransitionStarted;
+ /**
+ * It took too long for a message from the entering Activity, so we canceled the transition.
+ */
+ public static final int MSG_CANCEL = 106;
- private FixedEpicenterCallback mEpicenterCallback = new FixedEpicenterCallback();
+ final private Window mWindow;
+ final protected ArrayList<String> mAllSharedElementNames;
+ final protected ArrayList<View> mSharedElements = new ArrayList<View>();
+ final protected ArrayList<String> mSharedElementNames = new ArrayList<String>();
+ final protected ArrayList<View> mTransitioningViews = new ArrayList<View>();
+ final protected SharedElementListener mListener;
+ protected ResultReceiver mResultReceiver;
+ final private FixedEpicenterCallback mEpicenterCallback = new FixedEpicenterCallback();
- private Transition.TransitionListener mSharedElementListener =
- new Transition.TransitionListenerAdapter() {
- @Override
- public void onTransitionEnd(Transition transition) {
- transition.removeListener(this);
- onSharedElementTransitionEnd();
- }
- };
-
- private Transition.TransitionListener mExitListener =
- new Transition.TransitionListenerAdapter() {
- @Override
- public void onTransitionEnd(Transition transition) {
- transition.removeListener(this);
- onExitTransitionEnd();
- }
- };
-
- public ActivityTransitionCoordinator(Window window)
- {
+ public ActivityTransitionCoordinator(Window window,
+ ArrayList<String> allSharedElementNames,
+ ArrayList<String> accepted, ArrayList<String> localNames,
+ SharedElementListener listener) {
super(new Handler());
mWindow = window;
- }
-
- // -------------------- ResultsReceiver Overrides ----------------------
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- switch (resultCode) {
- case MSG_SET_LISTENER:
- ResultReceiver resultReceiver
- = resultData.getParcelable(KEY_TRANSITION_RESULTS_RECEIVER);
- setRemoteResultReceiver(resultReceiver);
- onSetResultReceiver();
- break;
- case MSG_HIDE_SHARED_ELEMENTS:
- onHideSharedElements();
- break;
- case MSG_PREPARE_RESTORE:
- onPrepareRestore();
- break;
- case MSG_EXIT_TRANSITION_COMPLETE:
- if (!mSharedElementTransitionStarted) {
- send(resultCode, resultData);
- } else {
- onRemoteSceneExitComplete();
- }
- break;
- case MSG_TAKE_SHARED_ELEMENTS:
- ArrayList<String> sharedElementNames
- = resultData.getStringArrayList(KEY_SHARED_ELEMENT_NAMES);
- Bundle sharedElementState = resultData.getBundle(KEY_SHARED_ELEMENT_STATE);
- onTakeSharedElements(sharedElementNames, sharedElementState);
- break;
- case MSG_ACTIVITY_STOPPED:
- onActivityStopped();
- break;
- case MSG_START_EXIT_TRANSITION:
- startExit();
- break;
- }
- }
-
- // -------------------- calls that can be overridden by subclasses --------------------
-
- /**
- * Called when MSG_SET_LISTENER is received. This will only be received by
- * ExitTransitionCoordinator.
- */
- protected void onSetResultReceiver() {}
-
- /**
- * Called when MSG_HIDE_SHARED_ELEMENTS is received
- */
- protected void onHideSharedElements() {
- setViewVisibility(getSharedElements(), View.INVISIBLE);
- mListener.onSharedElementTransferred(getSharedElementNames(), getSharedElements());
- }
-
- /**
- * Called when MSG_PREPARE_RESTORE is called. This will only be received by
- * ExitTransitionCoordinator.
- */
- protected void onPrepareRestore() {
- mListener.onEnterReady();
- }
-
- /**
- * Called when MSG_EXIT_TRANSITION_COMPLETE is received -- the remote coordinator has
- * completed its exit transition. This can be called by the ExitTransitionCoordinator when
- * starting an Activity or EnterTransitionCoordinator when called with finishWithTransition.
- */
- protected void onRemoteSceneExitComplete() {
- if (!allowOverlappingTransitions()) {
- Transition transition = beginTransition(mEnteringViews, false, true, true);
- onStartEnterTransition(transition, mEnteringViews);
- }
- mListener.onRemoteExitComplete();
- }
-
- /**
- * Called when MSG_TAKE_SHARED_ELEMENTS is received. This means that the shared elements are
- * in a stable state and ready to move to the Window.
- * @param sharedElementNames The names of the shared elements to move.
- * @param state Contains the shared element states (size & position)
- */
- protected void onTakeSharedElements(ArrayList<String> sharedElementNames, Bundle state) {
- setSharedElements();
- reconcileSharedElements(sharedElementNames);
- mEnteringViews.removeAll(mSharedElements);
- final ArrayList<View> accepted = new ArrayList<View>();
- final ArrayList<View> rejected = new ArrayList<View>();
- createSharedElementImages(accepted, rejected, sharedElementNames, state);
- ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageViewState =
- setSharedElementState(state, accepted);
- handleRejected(rejected);
-
+ mListener = listener;
+ mAllSharedElementNames = allSharedElementNames;
+ setSharedElements(accepted, localNames);
if (getViewsTransition() != null) {
- setViewVisibility(mEnteringViews, View.INVISIBLE);
+ getDecor().captureTransitioningViews(mTransitioningViews);
+ mTransitioningViews.removeAll(mSharedElements);
}
- setViewVisibility(mSharedElements, View.VISIBLE);
- Transition transition = beginTransition(mEnteringViews, true, allowOverlappingTransitions(),
- true);
- setOriginalImageViewState(originalImageViewState);
-
- if (allowOverlappingTransitions()) {
- onStartEnterTransition(transition, mEnteringViews);
- }
-
- mRemoteResultReceiver.send(MSG_HIDE_SHARED_ELEMENTS, null);
- }
-
- /**
- * Called when MSG_ACTIVITY_STOPPED is received. This is received when Activity.onStop is
- * called after running startActivity* is called using an Activity Transition.
- */
- protected void onActivityStopped() {}
-
- /**
- * Called when the start transition is ready to run. This may be immediately after
- * MSG_TAKE_SHARED_ELEMENTS or MSG_EXIT_TRANSITION_COMPLETE, depending on whether
- * overlapping transitions are allowed.
- * @param transition The transition currently started.
- * @param enteringViews The views entering the scene. This won't include shared elements.
- */
- protected void onStartEnterTransition(Transition transition, ArrayList<View> enteringViews) {
- if (getViewsTransition() != null) {
- setViewVisibility(enteringViews, View.VISIBLE);
- }
- mEnteringViews = null;
- mListener.onStartEnterTransition(getSharedElementNames(), getSharedElements());
- }
-
- /**
- * Called when the exit transition has started.
- * @param exitingViews The views leaving the scene. This won't include shared elements.
- */
- protected void onStartExitTransition(ArrayList<View> exitingViews) {}
-
- /**
- * Called during the exit when the shared element transition has completed.
- */
- protected void onSharedElementTransitionEnd() {
- Bundle bundle = new Bundle();
- int[] tempLoc = new int[2];
- for (int i = 0; i < mSharedElements.size(); i++) {
- View sharedElement = mSharedElements.get(i);
- String name = mTargetSharedNames.get(i);
- captureSharedElementState(sharedElement, name, bundle, tempLoc);
- }
- Bundle allValues = new Bundle();
- allValues.putStringArrayList(KEY_SHARED_ELEMENT_NAMES, getSharedElementNames());
- allValues.putBundle(KEY_SHARED_ELEMENT_STATE, bundle);
- sharedElementTransitionComplete(allValues);
- mListener.onSharedElementExitTransitionComplete();
- }
-
- /**
- * Called after the shared element transition is complete to pass the shared element state
- * to the remote coordinator.
- * @param bundle The Bundle to send to the coordinator containing the shared element state.
- */
- protected abstract void sharedElementTransitionComplete(Bundle bundle);
-
- /**
- * Called when the exit transition finishes.
- */
- protected void onExitTransitionEnd() {
- mListener.onExitTransitionComplete();
- }
-
- /**
- * Called to start the exit transition. Launched from ActivityOptions#dispatchStartExit
- */
- protected abstract void startExit();
-
- /**
- * A non-null transition indicates that the Views of the Window should be made INVISIBLE.
- * @return The Transition used to cause transitioning views to either enter or exit the scene.
- */
- protected abstract Transition getViewsTransition();
-
- /**
- * @return The Transition used to move the shared elements from the start position and size
- * to the end position and size.
- */
- protected abstract Transition getSharedElementTransition();
-
- /**
- * @return When the enter transition should overlap with the exit transition of the
- * remote controller.
- */
- protected abstract boolean allowOverlappingTransitions();
-
- // called by subclasses
-
- protected void notifySharedElementTransitionComplete(Bundle sharedElements) {
- if (!mNotifiedSharedElementTransitionComplete) {
- mNotifiedSharedElementTransitionComplete = true;
- mRemoteResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, sharedElements);
- }
- }
-
- protected void notifyExitTransitionComplete() {
- if (!mNotifiedExitTransitionComplete) {
- mNotifiedExitTransitionComplete = true;
- mRemoteResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
- }
- }
-
- protected void notifyPrepareRestore() {
- mRemoteResultReceiver.send(MSG_PREPARE_RESTORE, null);
- }
-
- protected void setRemoteResultReceiver(ResultReceiver resultReceiver) {
- mRemoteResultReceiver = resultReceiver;
- }
-
- protected void notifySetListener() {
- Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_TRANSITION_RESULTS_RECEIVER, this);
- mRemoteResultReceiver.send(MSG_SET_LISTENER, bundle);
- }
-
- protected void setEnteringViews(ArrayList<View> views) {
- mEnteringViews = views;
- }
-
- protected void setSharedElements() {
- Pair<View, String>[] sharedElements = mListener.getSharedElementsMapping();
- mSharedElements.clear();
- mTargetSharedNames.clear();
- if (sharedElements == null) {
- ArrayMap<String, View> map = new ArrayMap<String, View>();
- if (getViewsTransition() != null) {
- setViewVisibility(mEnteringViews, View.VISIBLE);
- }
- getDecor().findSharedElements(map);
- if (getViewsTransition() != null) {
- setViewVisibility(mEnteringViews, View.INVISIBLE);
- }
- for (int i = 0; i < map.size(); i++) {
- View view = map.valueAt(i);
- String name = map.keyAt(i);
- mSharedElements.add(view);
- mTargetSharedNames.add(name);
- }
- } else {
- for (int i = 0; i < sharedElements.length; i++) {
- Pair<View, String> viewStringPair = sharedElements[i];
- View view = viewStringPair.first;
- String name = viewStringPair.second;
- mSharedElements.add(view);
- mTargetSharedNames.add(name);
- }
- }
- }
-
- protected ArrayList<View> getSharedElements() {
- return mSharedElements;
- }
-
- protected ArrayList<String> getSharedElementNames() {
- return mTargetSharedNames;
+ setEpicenter();
}
protected Window getWindow() {
@@ -509,238 +214,43 @@
return (mWindow == null) ? null : (ViewGroup) mWindow.getDecorView();
}
- protected void startExitTransition(ArrayList<String> sharedElements) {
- setSharedElements();
- reconcileSharedElements(sharedElements);
- ArrayList<View> transitioningViews = captureTransitioningViews();
- beginTransition(transitioningViews, true, true, false);
- onStartExitTransition(transitioningViews);
- if (getViewsTransition() != null) {
- setViewVisibility(transitioningViews, View.INVISIBLE);
+ /**
+ * Sets the transition epicenter to the position of the first shared element.
+ */
+ protected void setEpicenter() {
+ View epicenter = null;
+ if (!mAllSharedElementNames.isEmpty() && !mSharedElementNames.isEmpty() &&
+ mAllSharedElementNames.get(0).equals(mSharedElementNames.get(0))) {
+ epicenter = mSharedElements.get(0);
}
- mListener.onStartExitTransition(getSharedElementNames(), getSharedElements());
+ setEpicenter(epicenter);
}
- protected void clearConnections() {
- mRemoteResultReceiver = null;
- }
-
- // public API
-
- public void setActivityTransitionListener(ActivityOptions.ActivityTransitionListener listener) {
- if (listener == null) {
- mListener = new ActivityOptions.ActivityTransitionListener();
+ private void setEpicenter(View view) {
+ if (view == null) {
+ mEpicenterCallback.setEpicenter(null);
} else {
- mListener = listener;
+ int[] loc = new int[2];
+ view.getLocationOnScreen(loc);
+ int left = loc[0] + Math.round(view.getTranslationX());
+ int top = loc[1] + Math.round(view.getTranslationY());
+ int right = left + view.getWidth();
+ int bottom = top + view.getHeight();
+ Rect epicenter = new Rect(left, top, right, bottom);
+ mEpicenterCallback.setEpicenter(epicenter);
}
}
- // private methods
-
- private Transition configureTransition(Transition transition) {
- if (transition != null) {
- transition = transition.clone();
- transition.setEpicenterCallback(mEpicenterCallback);
- }
- return transition;
+ public ArrayList<String> getAcceptedNames() {
+ return mSharedElementNames;
}
- private void reconcileSharedElements(ArrayList<String> sharedElementNames) {
- // keep only those that are in sharedElementNames.
- int numSharedElements = sharedElementNames.size();
- int targetIndex = 0;
- for (int i = 0; i < numSharedElements; i++) {
- String name = sharedElementNames.get(i);
- int index = mTargetSharedNames.indexOf(name);
- if (index >= 0) {
- // Swap the items at the indexes if necessary.
- if (index != targetIndex) {
- View temp = mSharedElements.get(index);
- mSharedElements.set(index, mSharedElements.get(targetIndex));
- mSharedElements.set(targetIndex, temp);
- mTargetSharedNames.set(index, mTargetSharedNames.get(targetIndex));
- mTargetSharedNames.set(targetIndex, name);
- }
- targetIndex++;
- }
+ public ArrayList<String> getMappedNames() {
+ ArrayList<String> names = new ArrayList<String>(mSharedElements.size());
+ for (int i = 0; i < mSharedElements.size(); i++) {
+ names.add(mSharedElements.get(i).getViewName());
}
- for (int i = mSharedElements.size() - 1; i >= targetIndex; i--) {
- mSharedElements.remove(i);
- mTargetSharedNames.remove(i);
- }
- Rect epicenter = null;
- if (!mTargetSharedNames.isEmpty()
- && mTargetSharedNames.get(0).equals(sharedElementNames.get(0))) {
- epicenter = calcEpicenter(mSharedElements.get(0));
- }
- mEpicenterCallback.setEpicenter(epicenter);
- }
-
- private ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> setSharedElementState(
- Bundle sharedElementState, final ArrayList<View> acceptedOverlayViews) {
- ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageState =
- new ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>>();
- final int[] tempLoc = new int[2];
- if (sharedElementState != null) {
- for (int i = 0; i < mSharedElements.size(); i++) {
- View sharedElement = mSharedElements.get(i);
- String name = mTargetSharedNames.get(i);
- Pair<ImageView.ScaleType, Matrix> originalState = getOldImageState(sharedElement,
- name, sharedElementState);
- if (originalState != null) {
- originalImageState.put((ImageView) sharedElement, originalState);
- }
- View parent = (View) sharedElement.getParent();
- parent.getLocationOnScreen(tempLoc);
- setSharedElementState(sharedElement, name, sharedElementState, tempLoc);
- sharedElement.requestLayout();
- }
- }
- mListener.onCaptureSharedElementStart(mTargetSharedNames, mSharedElements,
- acceptedOverlayViews);
-
- getDecor().getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
- mListener.onCaptureSharedElementEnd(mTargetSharedNames, mSharedElements,
- acceptedOverlayViews);
- mSharedElementTransitionStarted = true;
- return true;
- }
- }
- );
- return originalImageState;
- }
-
- private static Pair<ImageView.ScaleType, Matrix> getOldImageState(View view, String name,
- Bundle transitionArgs) {
- if (!(view instanceof ImageView)) {
- return null;
- }
- Bundle bundle = transitionArgs.getBundle(name);
- int scaleTypeInt = bundle.getInt(KEY_SCALE_TYPE, -1);
- if (scaleTypeInt < 0) {
- return null;
- }
-
- ImageView imageView = (ImageView) view;
- ImageView.ScaleType originalScaleType = imageView.getScaleType();
-
- Matrix originalMatrix = null;
- if (originalScaleType == ImageView.ScaleType.MATRIX) {
- originalMatrix = new Matrix(imageView.getImageMatrix());
- }
-
- return Pair.create(originalScaleType, originalMatrix);
- }
-
- /**
- * Sets the captured values from a previous
- * {@link #captureSharedElementState(android.view.View, String, android.os.Bundle, int[])}
- * @param view The View to apply placement changes to.
- * @param name The shared element name given from the source Activity.
- * @param transitionArgs A <code>Bundle</code> containing all placementinformation for named
- * shared elements in the scene.
- * @param parentLoc The x and y coordinates of the parent's screen position.
- */
- private static void setSharedElementState(View view, String name, Bundle transitionArgs,
- int[] parentLoc) {
- Bundle sharedElementBundle = transitionArgs.getBundle(name);
- if (sharedElementBundle == null) {
- return;
- }
-
- if (view instanceof ImageView) {
- int scaleTypeInt = sharedElementBundle.getInt(KEY_SCALE_TYPE, -1);
- if (scaleTypeInt >= 0) {
- ImageView imageView = (ImageView) view;
- ImageView.ScaleType scaleType = SCALE_TYPE_VALUES[scaleTypeInt];
- imageView.setScaleType(scaleType);
- if (scaleType == ImageView.ScaleType.MATRIX) {
- float[] matrixValues = sharedElementBundle.getFloatArray(KEY_IMAGE_MATRIX);
- Matrix matrix = new Matrix();
- matrix.setValues(matrixValues);
- imageView.setImageMatrix(matrix);
- }
- }
- }
-
- float z = sharedElementBundle.getFloat(KEY_TRANSLATION_Z);
- view.setTranslationZ(z);
-
- int x = sharedElementBundle.getInt(KEY_SCREEN_X);
- int y = sharedElementBundle.getInt(KEY_SCREEN_Y);
- int width = sharedElementBundle.getInt(KEY_WIDTH);
- int height = sharedElementBundle.getInt(KEY_HEIGHT);
-
- int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
- int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
- view.measure(widthSpec, heightSpec);
-
- int left = x - parentLoc[0];
- int top = y - parentLoc[1];
- int right = left + width;
- int bottom = top + height;
- view.layout(left, top, right, bottom);
- }
-
- /**
- * Captures placement information for Views with a shared element name for
- * Activity Transitions.
- * @param view The View to capture the placement information for.
- * @param name The shared element name in the target Activity to apply the placement
- * information for.
- * @param transitionArgs Bundle to store shared element placement information.
- * @param tempLoc A temporary int[2] for capturing the current location of views.
- * @see #setSharedElementState(android.view.View, String, android.os.Bundle, int[])
- */
- private static void captureSharedElementState(View view, String name, Bundle transitionArgs,
- int[] tempLoc) {
- Bundle sharedElementBundle = new Bundle();
- view.getLocationOnScreen(tempLoc);
- float scaleX = view.getScaleX();
- sharedElementBundle.putInt(KEY_SCREEN_X, tempLoc[0]);
- int width = Math.round(view.getWidth() * scaleX);
- sharedElementBundle.putInt(KEY_WIDTH, width);
-
- float scaleY = view.getScaleY();
- sharedElementBundle.putInt(KEY_SCREEN_Y, tempLoc[1]);
- int height= Math.round(view.getHeight() * scaleY);
- sharedElementBundle.putInt(KEY_HEIGHT, height);
-
- sharedElementBundle.putFloat(KEY_TRANSLATION_Z, view.getTranslationZ());
-
- sharedElementBundle.putString(KEY_NAME, view.getSharedElementName());
-
- Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- view.draw(canvas);
- sharedElementBundle.putParcelable(KEY_BITMAP, bitmap);
-
- if (view instanceof ImageView) {
- ImageView imageView = (ImageView) view;
- int scaleTypeInt = scaleTypeToInt(imageView.getScaleType());
- sharedElementBundle.putInt(KEY_SCALE_TYPE, scaleTypeInt);
- if (imageView.getScaleType() == ImageView.ScaleType.MATRIX) {
- float[] matrix = new float[9];
- imageView.getImageMatrix().getValues(matrix);
- sharedElementBundle.putFloatArray(KEY_IMAGE_MATRIX, matrix);
- }
- }
-
- transitionArgs.putBundle(name, sharedElementBundle);
- }
-
- private static Rect calcEpicenter(View view) {
- int[] loc = new int[2];
- view.getLocationOnScreen(loc);
- int left = loc[0] + Math.round(view.getTranslationX());
- int top = loc[1] + Math.round(view.getTranslationY());
- int right = left + view.getWidth();
- int bottom = top + view.getHeight();
- return new Rect(left, top, right, bottom);
+ return names;
}
public static void setViewVisibility(Collection<View> views, int visibility) {
@@ -751,12 +261,12 @@
}
}
- private static Transition addTransitionTargets(Transition transition, Collection<View> views) {
+ protected static Transition addTargets(Transition transition, Collection<View> views) {
if (transition == null || views == null || views.isEmpty()) {
return null;
}
TransitionSet set = new TransitionSet();
- set.addTransition(transition.clone());
+ set.addTransition(transition);
if (views != null) {
for (View view: views) {
set.addTarget(view);
@@ -765,152 +275,62 @@
return set;
}
- private ArrayList<View> captureTransitioningViews() {
- if (getViewsTransition() == null) {
- return null;
- }
- ArrayList<View> transitioningViews = new ArrayList<View>();
- getDecor().captureTransitioningViews(transitioningViews);
- transitioningViews.removeAll(getSharedElements());
- return transitioningViews;
- }
-
- private Transition getSharedElementTransition(boolean isEnter) {
- Transition transition = getSharedElementTransition();
- if (transition == null) {
- return null;
- }
- transition = configureTransition(transition);
- if (!isEnter) {
- transition.addListener(mSharedElementListener);
- }
- return transition;
- }
-
- private Transition getViewsTransition(ArrayList<View> transitioningViews, boolean isEnter) {
- Transition transition = getViewsTransition();
- if (transition == null) {
- return null;
- }
- transition = configureTransition(transition);
- if (!isEnter) {
- transition.addListener(mExitListener);
- }
- return addTransitionTargets(transition, transitioningViews);
- }
-
- private Transition beginTransition(ArrayList<View> transitioningViews,
- boolean transitionSharedElement, boolean transitionViews, boolean isEnter) {
- Transition sharedElementTransition = null;
- if (transitionSharedElement) {
- sharedElementTransition = getSharedElementTransition(isEnter);
- if (!isEnter && sharedElementTransition == null) {
- onSharedElementTransitionEnd();
- }
- }
- Transition viewsTransition = null;
- if (transitionViews) {
- viewsTransition = getViewsTransition(transitioningViews, isEnter);
- if (!isEnter && viewsTransition == null) {
- onExitTransitionEnd();
- }
- }
-
- Transition transition = null;
- if (sharedElementTransition == null) {
- transition = viewsTransition;
- } else if (viewsTransition == null) {
- transition = sharedElementTransition;
- } else {
- TransitionSet set = new TransitionSet();
- set.addTransition(sharedElementTransition);
- set.addTransition(viewsTransition);
- transition = set;
- }
+ protected Transition configureTransition(Transition transition) {
if (transition != null) {
- TransitionManager.beginDelayedTransition(getDecor(), transition);
- if (transitionSharedElement && !mSharedElements.isEmpty()) {
- mSharedElements.get(0).invalidate();
- } else if (transitionViews && !transitioningViews.isEmpty()) {
- transitioningViews.get(0).invalidate();
- }
+ transition = transition.clone();
+ transition.setEpicenterCallback(mEpicenterCallback);
}
return transition;
}
- private void handleRejected(final ArrayList<View> rejected) {
- int numRejected = rejected.size();
- if (numRejected == 0) {
- return;
+ protected static Transition mergeTransitions(Transition transition1, Transition transition2) {
+ if (transition1 == null) {
+ return transition2;
+ } else if (transition2 == null) {
+ return transition1;
+ } else {
+ TransitionSet transitionSet = new TransitionSet();
+ transitionSet.addTransition(transition1);
+ transitionSet.addTransition(transition2);
+ return transitionSet;
}
- boolean rejectionHandled = mListener.handleRejectedSharedElements(rejected);
- if (rejectionHandled) {
- return;
- }
-
- ViewGroupOverlay overlay = getDecor().getOverlay();
- ObjectAnimator animator = null;
- for (int i = 0; i < numRejected; i++) {
- View view = rejected.get(i);
- overlay.add(view);
- animator = ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0);
- animator.start();
- }
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- ViewGroupOverlay overlay = getDecor().getOverlay();
- for (int i = rejected.size() - 1; i >= 0; i--) {
- overlay.remove(rejected.get(i));
- }
- }
- });
}
- private void createSharedElementImages(ArrayList<View> accepted, ArrayList<View> rejected,
- ArrayList<String> sharedElementNames, Bundle state) {
- int numSharedElements = sharedElementNames.size();
- Context context = getWindow().getContext();
- int[] parentLoc = new int[2];
- getDecor().getLocationOnScreen(parentLoc);
- for (int i = 0; i < numSharedElements; i++) {
- String name = sharedElementNames.get(i);
- Bundle sharedElementBundle = state.getBundle(name);
- if (sharedElementBundle != null) {
- Bitmap bitmap = sharedElementBundle.getParcelable(KEY_BITMAP);
- ImageView imageView = new ImageView(context);
- imageView.setId(com.android.internal.R.id.shared_element);
- imageView.setScaleType(ImageView.ScaleType.CENTER);
- imageView.setImageBitmap(bitmap);
- imageView.setSharedElementName(name);
- setSharedElementState(imageView, name, state, parentLoc);
- if (mTargetSharedNames.contains(name)) {
- accepted.add(imageView);
- } else {
- rejected.add(imageView);
+ private void setSharedElements(ArrayList<String> accepted, ArrayList<String> localNames) {
+ if (!mAllSharedElementNames.isEmpty()) {
+ ArrayMap<String, View> sharedElements = new ArrayMap<String, View>();
+ getDecor().findNamedViews(sharedElements);
+ if (accepted != null) {
+ for (int i = 0; i < localNames.size(); i++) {
+ String localName = localNames.get(i);
+ String acceptedName = accepted.get(i);
+ if (!localName.equals(acceptedName)) {
+ View view = sharedElements.remove(localName);
+ if (view != null) {
+ sharedElements.put(acceptedName, view);
+ }
+ }
+ }
+ }
+ sharedElements.retainAll(mAllSharedElementNames);
+ mListener.remapSharedElements(mAllSharedElementNames, sharedElements);
+ sharedElements.retainAll(mAllSharedElementNames);
+ for (int i = 0; i < mAllSharedElementNames.size(); i++) {
+ String name = mAllSharedElementNames.get(i);
+ View sharedElement = sharedElements.get(name);
+ if (sharedElement != null) {
+ mSharedElementNames.add(name);
+ mSharedElements.add(sharedElement);
}
}
}
}
- private static void setOriginalImageViewState(
- ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalState) {
- for (int i = 0; i < originalState.size(); i++) {
- ImageView imageView = originalState.keyAt(i);
- Pair<ImageView.ScaleType, Matrix> state = originalState.valueAt(i);
- imageView.setScaleType(state.first);
- imageView.setImageMatrix(state.second);
- }
+ protected void setResultReceiver(ResultReceiver resultReceiver) {
+ mResultReceiver = resultReceiver;
}
- private static int scaleTypeToInt(ImageView.ScaleType scaleType) {
- for (int i = 0; i < SCALE_TYPE_VALUES.length; i++) {
- if (scaleType == SCALE_TYPE_VALUES[i]) {
- return i;
- }
- }
- return -1;
- }
+ protected abstract Transition getViewsTransition();
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
new file mode 100644
index 0000000..63019b6
--- /dev/null
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app;
+
+import android.os.Bundle;
+import android.os.ResultReceiver;
+import android.util.ArrayMap;
+import android.view.View;
+import android.view.Window;
+
+import java.util.ArrayList;
+
+/**
+ * This class contains all persistence-related functionality for Activity Transitions.
+ * Activities start exit and enter Activity Transitions through this class.
+ */
+class ActivityTransitionState {
+
+ private static final String ENTERING_SHARED_ELEMENTS = "android:enteringSharedElements";
+
+ private static final String ENTERING_MAPPED_FROM = "android:enteringMappedFrom";
+
+ private static final String ENTERING_MAPPED_TO = "android:enteringMappedTo";
+
+ private static final String EXITING_MAPPED_FROM = "android:exitingMappedFrom";
+
+ private static final String EXITING_MAPPED_TO = "android:exitingMappedTo";
+
+ /**
+ * The shared elements that the calling Activity has said that they transferred to this
+ * Activity.
+ */
+ private ArrayList<String> mEnteringNames;
+
+ /**
+ * The shared elements that this Activity as accepted and mapped to local Views.
+ */
+ private ArrayList<String> mEnteringFrom;
+
+ /**
+ * The names of local Views that are mapped to those elements in mEnteringFrom.
+ */
+ private ArrayList<String> mEnteringTo;
+
+ /**
+ * The names of shared elements that were shared to the called Activity.
+ */
+ private ArrayList<String> mExitingFrom;
+
+ /**
+ * The names of local Views that were shared out, mapped to those elements in mExitingFrom.
+ */
+ private ArrayList<String> mExitingTo;
+
+ /**
+ * The ActivityOptions used to call an Activity. Used to make the elements restore
+ * Visibility of exited Views.
+ */
+ private ActivityOptions mCalledActivityOptions;
+
+ /**
+ * We must be able to cancel entering transitions to stop changing the Window to
+ * opaque when we exit before making the Window opaque.
+ */
+ private EnterTransitionCoordinator mEnterTransitionCoordinator;
+
+ /**
+ * ActivityOptions used on entering this Activity.
+ */
+ private ActivityOptions mEnterActivityOptions;
+
+ /**
+ * Has an exit transition been started? If so, we don't want to double-exit.
+ */
+ private boolean mHasExited;
+
+ public ActivityTransitionState() {
+ }
+
+ public void readState(Bundle bundle) {
+ if (bundle != null) {
+ if (mEnterTransitionCoordinator == null || mEnterTransitionCoordinator.isReturning()) {
+ mEnteringNames = bundle.getStringArrayList(ENTERING_SHARED_ELEMENTS);
+ mEnteringFrom = bundle.getStringArrayList(ENTERING_MAPPED_FROM);
+ mEnteringTo = bundle.getStringArrayList(ENTERING_MAPPED_TO);
+ }
+ if (mEnterTransitionCoordinator == null) {
+ mExitingFrom = bundle.getStringArrayList(EXITING_MAPPED_FROM);
+ mExitingTo = bundle.getStringArrayList(EXITING_MAPPED_TO);
+ }
+ }
+ }
+
+ public void saveState(Bundle bundle) {
+ if (mEnteringNames != null) {
+ bundle.putStringArrayList(ENTERING_SHARED_ELEMENTS, mEnteringNames);
+ bundle.putStringArrayList(ENTERING_MAPPED_FROM, mEnteringFrom);
+ bundle.putStringArrayList(ENTERING_MAPPED_TO, mEnteringTo);
+ }
+ if (mExitingFrom != null) {
+ bundle.putStringArrayList(EXITING_MAPPED_FROM, mExitingFrom);
+ bundle.putStringArrayList(EXITING_MAPPED_TO, mExitingTo);
+ }
+ }
+
+ public void setEnterActivityOptions(Activity activity, ActivityOptions options) {
+ if (activity.getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)
+ && options != null && mEnterActivityOptions == null
+ && options.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
+ mEnterActivityOptions = options;
+ if (mEnterActivityOptions.isReturning()) {
+ int result = mEnterActivityOptions.getResultCode();
+ if (result != 0) {
+ activity.onActivityReenter(result, mEnterActivityOptions.getResultData());
+ }
+ }
+ }
+ }
+
+ public void enterReady(Activity activity) {
+ if (mEnterActivityOptions == null) {
+ return;
+ }
+ mHasExited = false;
+ ArrayList<String> sharedElementNames = mEnterActivityOptions.getSharedElementNames();
+ ResultReceiver resultReceiver = mEnterActivityOptions.getResultReceiver();
+ if (mEnterActivityOptions.isReturning()) {
+ if (mCalledActivityOptions != null) {
+ mCalledActivityOptions.dispatchActivityStopped();
+ mCalledActivityOptions = null;
+ }
+ activity.getWindow().getDecorView().setVisibility(View.VISIBLE);
+ mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
+ resultReceiver, sharedElementNames, mExitingFrom, mExitingTo);
+ } else {
+ mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
+ resultReceiver, sharedElementNames, null, null);
+ mEnteringNames = sharedElementNames;
+ mEnteringFrom = mEnterTransitionCoordinator.getAcceptedNames();
+ mEnteringTo = mEnterTransitionCoordinator.getMappedNames();
+ }
+ mExitingFrom = null;
+ mExitingTo = null;
+ mEnterActivityOptions = null;
+ }
+
+ public void onStop() {
+ if (mCalledActivityOptions != null) {
+ mCalledActivityOptions.dispatchActivityStopped();
+ mCalledActivityOptions = null;
+ }
+ if (mEnterTransitionCoordinator != null) {
+ mEnterTransitionCoordinator.stop();
+ mEnterTransitionCoordinator = null;
+ }
+ }
+
+ public boolean startExitBackTransition(Activity activity) {
+ if (mEnteringNames == null) {
+ return false;
+ } else {
+ if (!mHasExited) {
+ mHasExited = true;
+ if (mEnterTransitionCoordinator != null) {
+ mEnterTransitionCoordinator.stop();
+ mEnterTransitionCoordinator = null;
+ }
+ ArrayMap<String, View> sharedElements = new ArrayMap<String, View>();
+ activity.getWindow().getDecorView().findNamedViews(sharedElements);
+
+ ExitTransitionCoordinator exitCoordinator =
+ new ExitTransitionCoordinator(activity, mEnteringNames, mEnteringFrom,
+ mEnteringTo, true);
+ exitCoordinator.startExit(activity.mResultCode, activity.mResultData);
+ }
+ return true;
+ }
+ }
+
+ public void startExitOutTransition(Activity activity, Bundle options) {
+ if (!activity.getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
+ return;
+ }
+ mCalledActivityOptions = new ActivityOptions(options);
+ if (mCalledActivityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
+ mExitingFrom = mCalledActivityOptions.getSharedElementNames();
+ mExitingTo = mCalledActivityOptions.getLocalSharedElementNames();
+ mCalledActivityOptions.dispatchStartExit();
+ }
+ }
+}
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index ab148a9..4ce7835 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -92,6 +92,18 @@
* the device's default alert theme with a light background.
*/
public static final int THEME_DEVICE_DEFAULT_LIGHT = 5;
+
+ /**
+ * No layout hint.
+ * @hide
+ */
+ public static final int LAYOUT_HINT_NONE = 0;
+
+ /**
+ * Hint layout to the side.
+ * @hide
+ */
+ public static final int LAYOUT_HINT_SIDE = 1;
protected AlertDialog(Context context) {
this(context, resolveDialogTheme(context, 0), true);
@@ -208,6 +220,14 @@
}
/**
+ * Internal api to allow hinting for the best button panel layout.
+ * @hide
+ */
+ void setButtonPanelLayoutHint(int layoutHint) {
+ mAlert.setButtonPanelLayoutHint(layoutHint);
+ }
+
+ /**
* Set a message to be sent when a button is pressed.
*
* @param whichButton Which button to set the message for, can be one of
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index efd3d86..2f35160 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -35,6 +35,7 @@
import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
@@ -1127,7 +1128,7 @@
public void installPackage(Uri packageURI, PackageInstallObserver observer,
int flags, String installerPackageName) {
try {
- mPM.installPackageEtc(packageURI, null, observer.mObserver,
+ mPM.installPackageEtc(packageURI, null, observer.getBinder(),
flags, installerPackageName);
} catch (RemoteException e) {
// Should never happen!
@@ -1140,7 +1141,7 @@
Uri verificationURI, ManifestDigest manifestDigest,
ContainerEncryptionParams encryptionParams) {
try {
- mPM.installPackageWithVerificationEtc(packageURI, null, observer.mObserver, flags,
+ mPM.installPackageWithVerificationEtc(packageURI, null, observer.getBinder(), flags,
installerPackageName, verificationURI, manifestDigest, encryptionParams);
} catch (RemoteException e) {
// Should never happen!
@@ -1153,7 +1154,7 @@
VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
try {
mPM.installPackageWithVerificationAndEncryptionEtc(packageURI, null,
- observer.mObserver, flags, installerPackageName, verificationParams,
+ observer.getBinder(), flags, installerPackageName, verificationParams,
encryptionParams);
} catch (RemoteException e) {
// Should never happen!
@@ -1440,6 +1441,16 @@
return null;
}
+ @Override
+ public PackageInstaller getPackageInstaller() {
+ try {
+ return new PackageInstaller(this, mPM.getPackageInstaller(), mContext.getUserId(),
+ mContext.getPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
/**
* @hide
*/
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 7f2fb59..ef4099f 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -25,10 +25,12 @@
import android.content.pm.ServiceInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
+import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
import android.os.Parcelable;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.Parcel;
@@ -141,6 +143,7 @@
data.readStrongBinder());
int procState = data.readInt();
Bundle state = data.readBundle();
+ PersistableBundle persistentState = data.readPersistableBundle();
List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
List<Intent> pi = data.createTypedArrayList(Intent.CREATOR);
boolean notResumed = data.readInt() != 0;
@@ -149,11 +152,10 @@
ParcelFileDescriptor profileFd = data.readInt() != 0
? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
boolean autoStopProfiler = data.readInt() != 0;
- Bundle resumeArgs = data.readBundle();
scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo,
- voiceInteractor, procState, state,
- ri, pi, notResumed, isForward, profileName, profileFd, autoStopProfiler,
- resumeArgs);
+ voiceInteractor, procState, state, persistentState,
+ ri, pi, notResumed, isForward, profileName, profileFd,
+ autoStopProfiler);
return true;
}
@@ -337,7 +339,7 @@
final String proxy = data.readString();
final String port = data.readString();
final String exclList = data.readString();
- final String pacFileUrl = data.readString();
+ final Uri pacFileUrl = Uri.CREATOR.createFromParcel(data);
setHttpProxy(proxy, port, exclList, pacFileUrl);
return true;
}
@@ -731,11 +733,10 @@
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
- IVoiceInteractor voiceInteractor,
- int procState, Bundle state, List<ResultInfo> pendingResults,
+ IVoiceInteractor voiceInteractor, int procState, Bundle state,
+ PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
- String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
- Bundle resumeArgs)
+ String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler)
throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -748,6 +749,7 @@
data.writeStrongBinder(voiceInteractor != null ? voiceInteractor.asBinder() : null);
data.writeInt(procState);
data.writeBundle(state);
+ data.writePersistableBundle(persistentState);
data.writeTypedList(pendingResults);
data.writeTypedList(pendingNewIntents);
data.writeInt(notResumed ? 1 : 0);
@@ -760,7 +762,6 @@
data.writeInt(0);
}
data.writeInt(autoStopProfiler ? 1 : 0);
- data.writeBundle(resumeArgs);
mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
@@ -1005,13 +1006,13 @@
}
public void setHttpProxy(String proxy, String port, String exclList,
- String pacFileUrl) throws RemoteException {
+ Uri pacFileUrl) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeString(proxy);
data.writeString(port);
data.writeString(exclList);
- data.writeString(pacFileUrl);
+ pacFileUrl.writeToParcel(data, 0);
mRemote.transact(SET_HTTP_PROXY_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 801182d..b4d8942 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -26,6 +26,7 @@
import android.bluetooth.BluetoothManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
@@ -1818,8 +1819,8 @@
public void grantUriPermission(String toPackage, Uri uri, int modeFlags) {
try {
ActivityManagerNative.getDefault().grantUriPermission(
- mMainThread.getApplicationThread(), toPackage, uri,
- modeFlags);
+ mMainThread.getApplicationThread(), toPackage,
+ ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
} catch (RemoteException e) {
}
}
@@ -1828,8 +1829,8 @@
public void revokeUriPermission(Uri uri, int modeFlags) {
try {
ActivityManagerNative.getDefault().revokeUriPermission(
- mMainThread.getApplicationThread(), uri,
- modeFlags);
+ mMainThread.getApplicationThread(),
+ ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
} catch (RemoteException e) {
}
}
@@ -1838,12 +1839,17 @@
public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
try {
return ActivityManagerNative.getDefault().checkUriPermission(
- uri, pid, uid, modeFlags);
+ ContentProvider.getUriWithoutUserId(uri), pid, uid, modeFlags,
+ resolveUserId(uri));
} catch (RemoteException e) {
return PackageManager.PERMISSION_DENIED;
}
}
+ private int resolveUserId(Uri uri) {
+ return ContentProvider.getUserIdFromUri(uri, getUserId());
+ }
+
@Override
public int checkCallingUriPermission(Uri uri, int modeFlags) {
int pid = Binder.getCallingPid();
@@ -2280,12 +2286,16 @@
@Override
protected IContentProvider acquireProvider(Context context, String auth) {
- return mMainThread.acquireProvider(context, auth, mUser.getIdentifier(), true);
+ return mMainThread.acquireProvider(context,
+ ContentProvider.getAuthorityWithoutUserId(auth),
+ resolveUserIdFromAuthority(auth), true);
}
@Override
protected IContentProvider acquireExistingProvider(Context context, String auth) {
- return mMainThread.acquireExistingProvider(context, auth, mUser.getIdentifier(), true);
+ return mMainThread.acquireExistingProvider(context,
+ ContentProvider.getAuthorityWithoutUserId(auth),
+ resolveUserIdFromAuthority(auth), true);
}
@Override
@@ -2295,7 +2305,9 @@
@Override
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
- return mMainThread.acquireProvider(c, auth, mUser.getIdentifier(), false);
+ return mMainThread.acquireProvider(c,
+ ContentProvider.getAuthorityWithoutUserId(auth),
+ resolveUserIdFromAuthority(auth), false);
}
@Override
@@ -2312,5 +2324,10 @@
public void appNotRespondingViaProvider(IContentProvider icp) {
mMainThread.appNotRespondingViaProvider(icp.asBinder());
}
+
+ /** @hide */
+ protected int resolveUserIdFromAuthority(String auth) {
+ return ContentProvider.getUserIdFromAuthority(auth, mUser.getIdentifier());
+ }
}
}
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index d168800..26c2c30 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -107,6 +107,7 @@
(LayoutInflater) themeContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.date_picker_dialog, null);
setView(view);
+ setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
mDatePicker.init(year, monthOfYear, dayOfMonth, this);
updateTitle(year, monthOfYear, dayOfMonth);
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index cbb8359..636205b 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -18,270 +18,414 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
-import android.graphics.drawable.ColorDrawable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Matrix;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
import android.os.ResultReceiver;
import android.transition.Transition;
+import android.transition.TransitionManager;
+import android.util.ArrayMap;
+import android.util.Pair;
import android.view.View;
+import android.view.ViewGroupOverlay;
import android.view.ViewTreeObserver;
-import android.view.Window;
+import android.widget.ImageView;
import java.util.ArrayList;
+import java.util.Collection;
/**
* This ActivityTransitionCoordinator is created by the Activity to manage
- * the enter scene and shared element transfer as well as Activity#finishWithTransition
- * exiting the Scene and transferring shared elements back to the called Activity.
+ * the enter scene and shared element transfer into the Scene, either during
+ * launch of an Activity or returning from a launched Activity.
*/
-class EnterTransitionCoordinator extends ActivityTransitionCoordinator
- implements ViewTreeObserver.OnPreDrawListener {
+class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
private static final String TAG = "EnterTransitionCoordinator";
- // The background fade in/out duration. 150ms is pretty quick, but not abrupt.
- private static final int FADE_BACKGROUND_DURATION_MS = 150;
+ private static final long MAX_WAIT_MS = 1500;
- /**
- * The shared element names sent by the ExitTransitionCoordinator and may be
- * shared when exiting back.
- */
- private ArrayList<String> mEnteringSharedElementNames;
-
- /**
- * The Activity that has created this coordinator. This is used solely to make the
- * Window translucent/opaque.
- */
+ private boolean mSharedElementTransitionStarted;
+ private boolean mIsReturning;
private Activity mActivity;
+ private boolean mHasStopped;
+ private Handler mHandler;
+ private boolean mIsCanceled;
- /**
- * True if the Window was opaque at the start and we should make it opaque again after
- * enter transitions have completed.
- */
- private boolean mWasOpaque;
-
- /**
- * During exit, is the background alpha == 0?
- */
- private boolean mBackgroundFadedOut;
-
- /**
- * During exit, has the shared element transition completed?
- */
- private boolean mSharedElementTransitionComplete;
-
- /**
- * Has the exit started? We don't want to accidentally exit multiple times. e.g. when
- * back is hit twice during the exit animation.
- */
- private boolean mExitTransitionStarted;
-
- /**
- * Has the exit transition ended?
- */
- private boolean mExitTransitionComplete;
-
- /**
- * We only want to make the Window transparent and set the background alpha once. After that,
- * the Activity won't want the same enter transition.
- */
- private boolean mMadeReady;
-
- /**
- * True if Window.hasFeature(Window.FEATURE_CONTENT_TRANSITIONS) -- this means that
- * enter and exit transitions should be active.
- */
- private boolean mSupportsTransition;
-
- /**
- * Background alpha animations may complete prior to receiving the callback for
- * onTranslucentConversionComplete. If so, we need to immediately call to make the Window
- * opaque.
- */
- private boolean mMakeOpaque;
-
- public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver) {
- super(activity.getWindow());
+ public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
+ ArrayList<String> sharedElementNames,
+ ArrayList<String> acceptedNames, ArrayList<String> mappedNames) {
+ super(activity.getWindow(), sharedElementNames, acceptedNames, mappedNames,
+ activity.mTransitionListener);
mActivity = activity;
- setRemoteResultReceiver(resultReceiver);
- }
-
- public void readyToEnter() {
- if (!mMadeReady) {
- mMadeReady = true;
- mSupportsTransition = getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS);
- if (mSupportsTransition) {
- Window window = getWindow();
- window.getDecorView().getViewTreeObserver().addOnPreDrawListener(this);
- mActivity.overridePendingTransition(0, 0);
- mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
- @Override
- public void onTranslucentConversionComplete(boolean drawComplete) {
- mWasOpaque = true;
- if (mMakeOpaque) {
- mActivity.convertFromTranslucent();
- }
- }
- });
- Drawable background = getDecor().getBackground();
- if (background != null) {
- window.setBackgroundDrawable(null);
- background.setAlpha(0);
- window.setBackgroundDrawable(background);
+ mIsReturning = acceptedNames != null;
+ setResultReceiver(resultReceiver);
+ prepareEnter();
+ Bundle resultReceiverBundle = new Bundle();
+ resultReceiverBundle.putParcelable(KEY_REMOTE_RECEIVER, this);
+ mResultReceiver.send(MSG_SET_REMOTE_RECEIVER, resultReceiverBundle);
+ if (mIsReturning) {
+ mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ cancel();
}
- }
+ };
+ mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS);
}
}
@Override
- protected void onTakeSharedElements(ArrayList<String> sharedElementNames, Bundle state) {
- mEnteringSharedElementNames = new ArrayList<String>();
- mEnteringSharedElementNames.addAll(sharedElementNames);
- super.onTakeSharedElements(sharedElementNames, state);
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ switch (resultCode) {
+ case MSG_TAKE_SHARED_ELEMENTS:
+ if (!mIsCanceled) {
+ if (mHandler != null) {
+ mHandler.removeMessages(MSG_CANCEL);
+ }
+ onTakeSharedElements(resultData);
+ }
+ break;
+ case MSG_EXIT_TRANSITION_COMPLETE:
+ if (!mIsCanceled) {
+ if (!mSharedElementTransitionStarted) {
+ send(resultCode, resultData);
+ } else {
+ onRemoteExitTransitionComplete();
+ }
+ }
+ break;
+ case MSG_CANCEL:
+ cancel();
+ break;
+ }
}
- @Override
- protected void sharedElementTransitionComplete(Bundle bundle) {
- notifySharedElementTransitionComplete(bundle);
- exitAfterSharedElementTransition();
+ private void cancel() {
+ if (!mIsCanceled) {
+ mIsCanceled = true;
+ if (getViewsTransition() == null) {
+ setViewVisibility(mSharedElements, View.VISIBLE);
+ } else {
+ mTransitioningViews.addAll(mSharedElements);
+ }
+ mSharedElementNames.clear();
+ mSharedElements.clear();
+ mAllSharedElementNames.clear();
+ onTakeSharedElements(null);
+ onRemoteExitTransitionComplete();
+ }
}
- @Override
- public boolean onPreDraw() {
- getWindow().getDecorView().getViewTreeObserver().removeOnPreDrawListener(this);
- setEnteringViews(readyEnteringViews());
- notifySetListener();
- onPrepareRestore();
- return false;
+ public boolean isReturning() {
+ return mIsReturning;
}
- @Override
- public void startExit() {
- if (!mExitTransitionStarted) {
- mExitTransitionStarted = true;
- startExitTransition(mEnteringSharedElementNames);
+ protected void prepareEnter() {
+ setViewVisibility(mSharedElements, View.INVISIBLE);
+ if (getViewsTransition() != null) {
+ setViewVisibility(mTransitioningViews, View.INVISIBLE);
+ }
+ mActivity.overridePendingTransition(0, 0);
+ if (!mIsReturning) {
+ mActivity.convertToTranslucent(null, null);
+ Drawable background = getDecor().getBackground();
+ if (background != null) {
+ getWindow().setBackgroundDrawable(null);
+ background = background.mutate();
+ background.setAlpha(0);
+ getWindow().setBackgroundDrawable(background);
+ }
+ } else {
+ mActivity = null; // all done with it now.
+ }
+ }
+
+ protected void onTakeSharedElements(Bundle sharedElementState) {
+ setEpicenter();
+ // Remove rejected shared elements
+ ArrayList<String> rejectedNames = new ArrayList<String>(mAllSharedElementNames);
+ rejectedNames.removeAll(mSharedElementNames);
+ ArrayList<View> rejectedSnapshots = createSnapshots(sharedElementState, rejectedNames);
+ mListener.handleRejectedSharedElements(rejectedSnapshots);
+ startRejectedAnimations(rejectedSnapshots);
+
+ // Now start shared element transition
+ ArrayList<View> sharedElementSnapshots = createSnapshots(sharedElementState,
+ mSharedElementNames);
+ setViewVisibility(mSharedElements, View.VISIBLE);
+ ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageViewState =
+ setSharedElementState(sharedElementState, sharedElementSnapshots);
+
+ boolean startEnterTransition = allowOverlappingTransitions();
+ boolean startSharedElementTransition = true;
+ Transition transition = beginTransition(startEnterTransition, startSharedElementTransition);
+
+ if (startEnterTransition) {
+ startEnterTransition(transition);
+ }
+
+ setOriginalImageViewState(originalImageViewState);
+
+ if (mResultReceiver != null) {
+ mResultReceiver.send(MSG_HIDE_SHARED_ELEMENTS, null);
+ }
+ mResultReceiver = null; // all done sending messages.
+ }
+
+ private Transition beginTransition(boolean startEnterTransition,
+ boolean startSharedElementTransition) {
+ Transition sharedElementTransition = null;
+ if (startSharedElementTransition && !mSharedElementNames.isEmpty()) {
+ sharedElementTransition = configureTransition(getSharedElementTransition());
+ }
+ Transition viewsTransition = null;
+ if (startEnterTransition && !mTransitioningViews.isEmpty()) {
+ viewsTransition = configureTransition(getViewsTransition());
+ viewsTransition = addTargets(viewsTransition, mTransitioningViews);
+ }
+
+ Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
+ if (transition != null) {
+ TransitionManager.beginDelayedTransition(getDecor(), transition);
+ if (startSharedElementTransition && !mSharedElementNames.isEmpty()) {
+ mSharedElements.get(0).invalidate();
+ } else if (startEnterTransition && !mTransitioningViews.isEmpty()) {
+ mTransitioningViews.get(0).invalidate();
+ }
+ }
+ return transition;
+ }
+
+ private void startEnterTransition(Transition transition) {
+ setViewVisibility(mTransitioningViews, View.VISIBLE);
+ if (!mIsReturning) {
+ Drawable background = getDecor().getBackground();
+ if (background != null) {
+ background = background.mutate();
+ ObjectAnimator animator = ObjectAnimator.ofInt(background, "alpha", 255);
+ animator.setDuration(FADE_BACKGROUND_DURATION_MS);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ makeOpaque();
+ }
+ });
+ animator.start();
+ } else if (transition != null) {
+ transition.addListener(new Transition.TransitionListenerAdapter() {
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ transition.removeListener(this);
+ makeOpaque();
+ }
+ });
+ } else {
+ makeOpaque();
+ }
+ }
+ }
+
+ public void stop() {
+ mHasStopped = true;
+ mActivity = null;
+ mIsCanceled = true;
+ mResultReceiver = null;
+ }
+
+ private void makeOpaque() {
+ if (!mHasStopped) {
+ mActivity.convertFromTranslucent();
+ mActivity = null;
+ }
+ }
+
+ private boolean allowOverlappingTransitions() {
+ return mIsReturning ? getWindow().getAllowExitTransitionOverlap()
+ : getWindow().getAllowEnterTransitionOverlap();
+ }
+
+ private void startRejectedAnimations(final ArrayList<View> rejectedSnapshots) {
+ if (rejectedSnapshots == null || rejectedSnapshots.isEmpty()) {
+ return;
+ }
+ ViewGroupOverlay overlay = getDecor().getOverlay();
+ ObjectAnimator animator = null;
+ int numRejected = rejectedSnapshots.size();
+ for (int i = 0; i < numRejected; i++) {
+ View snapshot = rejectedSnapshots.get(i);
+ overlay.add(snapshot);
+ animator = ObjectAnimator.ofFloat(snapshot, View.ALPHA, 1, 0);
+ animator.start();
+ }
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ ViewGroupOverlay overlay = getDecor().getOverlay();
+ int numRejected = rejectedSnapshots.size();
+ for (int i = 0; i < numRejected; i++) {
+ overlay.remove(rejectedSnapshots.get(i));
+ }
+ }
+ });
+ }
+
+ protected void onRemoteExitTransitionComplete() {
+ if (!allowOverlappingTransitions()) {
+ boolean startEnterTransition = true;
+ boolean startSharedElementTransition = false;
+ Transition transition = beginTransition(startEnterTransition,
+ startSharedElementTransition);
+ startEnterTransition(transition);
+ }
+ }
+
+ private ArrayList<View> createSnapshots(Bundle state, Collection<String> names) {
+ int numSharedElements = names.size();
+ if (numSharedElements == 0) {
+ return null;
+ }
+ ArrayList<View> snapshots = new ArrayList<View>(numSharedElements);
+ Context context = getWindow().getContext();
+ int[] parentLoc = new int[2];
+ getDecor().getLocationOnScreen(parentLoc);
+ for (String name: names) {
+ Bundle sharedElementBundle = state.getBundle(name);
+ if (sharedElementBundle != null) {
+ Bitmap bitmap = sharedElementBundle.getParcelable(KEY_BITMAP);
+ View snapshot = new View(context);
+ snapshot.setId(com.android.internal.R.id.shared_element);
+ Resources resources = getWindow().getContext().getResources();
+ snapshot.setBackground(new BitmapDrawable(resources, bitmap));
+ snapshot.setViewName(name);
+ setSharedElementState(snapshot, name, state, parentLoc);
+ snapshots.add(snapshot);
+ }
+ }
+ return snapshots;
+ }
+
+ private static void setSharedElementState(View view, String name, Bundle transitionArgs,
+ int[] parentLoc) {
+ Bundle sharedElementBundle = transitionArgs.getBundle(name);
+ if (sharedElementBundle == null) {
+ return;
+ }
+
+ if (view instanceof ImageView) {
+ int scaleTypeInt = sharedElementBundle.getInt(KEY_SCALE_TYPE, -1);
+ if (scaleTypeInt >= 0) {
+ ImageView imageView = (ImageView) view;
+ ImageView.ScaleType scaleType = SCALE_TYPE_VALUES[scaleTypeInt];
+ imageView.setScaleType(scaleType);
+ if (scaleType == ImageView.ScaleType.MATRIX) {
+ float[] matrixValues = sharedElementBundle.getFloatArray(KEY_IMAGE_MATRIX);
+ Matrix matrix = new Matrix();
+ matrix.setValues(matrixValues);
+ imageView.setImageMatrix(matrix);
+ }
+ }
+ }
+
+ float z = sharedElementBundle.getFloat(KEY_TRANSLATION_Z);
+ view.setTranslationZ(z);
+
+ int x = sharedElementBundle.getInt(KEY_SCREEN_X);
+ int y = sharedElementBundle.getInt(KEY_SCREEN_Y);
+ int width = sharedElementBundle.getInt(KEY_WIDTH);
+ int height = sharedElementBundle.getInt(KEY_HEIGHT);
+
+ int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
+ int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
+ view.measure(widthSpec, heightSpec);
+
+ int left = x - parentLoc[0];
+ int top = y - parentLoc[1];
+ int right = left + width;
+ int bottom = top + height;
+ view.layout(left, top, right, bottom);
+ }
+
+ private ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> setSharedElementState(
+ Bundle sharedElementState, final ArrayList<View> snapshots) {
+ ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageState =
+ new ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>>();
+ if (sharedElementState != null) {
+ int[] tempLoc = new int[2];
+ for (int i = 0; i < mSharedElementNames.size(); i++) {
+ View sharedElement = mSharedElements.get(i);
+ String name = mSharedElementNames.get(i);
+ Pair<ImageView.ScaleType, Matrix> originalState = getOldImageState(sharedElement,
+ name, sharedElementState);
+ if (originalState != null) {
+ originalImageState.put((ImageView) sharedElement, originalState);
+ }
+ View parent = (View) sharedElement.getParent();
+ parent.getLocationOnScreen(tempLoc);
+ setSharedElementState(sharedElement, name, sharedElementState, tempLoc);
+ sharedElement.requestLayout();
+ }
+ }
+ mListener.setSharedElementStart(mSharedElementNames, mSharedElements, snapshots);
+
+ getDecor().getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+ mListener.setSharedElementEnd(mSharedElementNames, mSharedElements,
+ snapshots);
+ mSharedElementTransitionStarted = true;
+ return true;
+ }
+ }
+ );
+ return originalImageState;
+ }
+
+ private static Pair<ImageView.ScaleType, Matrix> getOldImageState(View view, String name,
+ Bundle transitionArgs) {
+ if (!(view instanceof ImageView)) {
+ return null;
+ }
+ Bundle bundle = transitionArgs.getBundle(name);
+ int scaleTypeInt = bundle.getInt(KEY_SCALE_TYPE, -1);
+ if (scaleTypeInt < 0) {
+ return null;
+ }
+
+ ImageView imageView = (ImageView) view;
+ ImageView.ScaleType originalScaleType = imageView.getScaleType();
+
+ Matrix originalMatrix = null;
+ if (originalScaleType == ImageView.ScaleType.MATRIX) {
+ originalMatrix = new Matrix(imageView.getImageMatrix());
+ }
+
+ return Pair.create(originalScaleType, originalMatrix);
+ }
+
+ private static void setOriginalImageViewState(
+ ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalState) {
+ for (int i = 0; i < originalState.size(); i++) {
+ ImageView imageView = originalState.keyAt(i);
+ Pair<ImageView.ScaleType, Matrix> state = originalState.valueAt(i);
+ imageView.setScaleType(state.first);
+ imageView.setImageMatrix(state.second);
}
}
@Override
protected Transition getViewsTransition() {
- if (!mSupportsTransition) {
- return null;
- }
return getWindow().getEnterTransition();
}
- @Override
protected Transition getSharedElementTransition() {
- if (!mSupportsTransition) {
- return null;
- }
return getWindow().getSharedElementEnterTransition();
}
-
- @Override
- protected void onStartEnterTransition(Transition transition, ArrayList<View> enteringViews) {
- Drawable background = getDecor().getBackground();
- if (background != null) {
- ObjectAnimator animator = ObjectAnimator.ofInt(background, "alpha", 255);
- animator.setDuration(FADE_BACKGROUND_DURATION_MS);
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mMakeOpaque = true;
- if (mWasOpaque) {
- mActivity.convertFromTranslucent();
- }
- }
- });
- animator.start();
- } else if (mWasOpaque) {
- transition.addListener(new Transition.TransitionListenerAdapter() {
- @Override
- public void onTransitionEnd(Transition transition) {
- mMakeOpaque = true;
- mActivity.convertFromTranslucent();
- }
- });
- }
- super.onStartEnterTransition(transition, enteringViews);
- }
-
- public ArrayList<View> readyEnteringViews() {
- ArrayList<View> enteringViews = new ArrayList<View>();
- getDecor().captureTransitioningViews(enteringViews);
- if (getViewsTransition() != null) {
- setViewVisibility(enteringViews, View.INVISIBLE);
- }
- return enteringViews;
- }
-
- @Override
- protected void startExitTransition(ArrayList<String> sharedElements) {
- mMakeOpaque = false;
- notifyPrepareRestore();
-
- if (getDecor().getBackground() == null) {
- ColorDrawable black = new ColorDrawable(0xFF000000);
- getWindow().setBackgroundDrawable(black);
- }
- if (mWasOpaque) {
- mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
- @Override
- public void onTranslucentConversionComplete(boolean drawComplete) {
- fadeOutBackground();
- }
- });
- } else {
- fadeOutBackground();
- }
-
- super.startExitTransition(sharedElements);
- }
-
- private void fadeOutBackground() {
- ObjectAnimator animator = ObjectAnimator.ofInt(getDecor().getBackground(),
- "alpha", 0);
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mBackgroundFadedOut = true;
- if (mSharedElementTransitionComplete) {
- EnterTransitionCoordinator.super.onSharedElementTransitionEnd();
- }
- }
- });
- animator.setDuration(FADE_BACKGROUND_DURATION_MS);
- animator.start();
- }
-
- @Override
- protected void onExitTransitionEnd() {
- mExitTransitionComplete = true;
- exitAfterSharedElementTransition();
- super.onExitTransitionEnd();
- }
-
- @Override
- protected void onSharedElementTransitionEnd() {
- mSharedElementTransitionComplete = true;
- if (mBackgroundFadedOut) {
- super.onSharedElementTransitionEnd();
- }
- }
-
- @Override
- protected boolean allowOverlappingTransitions() {
- return getWindow().getAllowEnterTransitionOverlap();
- }
-
- private void exitAfterSharedElementTransition() {
- if (mSharedElementTransitionComplete && mExitTransitionComplete && mBackgroundFadedOut) {
- mActivity.finish();
- if (mSupportsTransition) {
- mActivity.overridePendingTransition(0, 0);
- }
- notifyExitTransitionComplete();
- clearConnections();
- }
- }
}
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index d920787..43a60a3 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -15,11 +15,20 @@
*/
package android.app;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
import android.transition.Transition;
-import android.util.Pair;
+import android.transition.TransitionManager;
import android.view.View;
-import android.view.Window;
+import android.widget.ImageView;
import java.util.ArrayList;
@@ -30,142 +39,245 @@
*/
class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
private static final String TAG = "ExitTransitionCoordinator";
+ private static final long MAX_WAIT_MS = 1500;
- /**
- * The Views that have exited and need to be restored to VISIBLE when returning to the
- * normal state.
- */
- private ArrayList<View> mTransitioningViews;
-
- /**
- * Has the exit started? We don't want to accidentally exit multiple times.
- */
- private boolean mExitStarted;
-
- /**
- * Has the called Activity's ResultReceiver been set?
- */
- private boolean mIsResultReceiverSet;
-
- /**
- * Has the exit transition completed? If so, we can notify as soon as the ResultReceiver
- * has been set.
- */
private boolean mExitComplete;
- /**
- * Has the shared element transition completed? If so, we can notify as soon as the
- * ResultReceiver has been set.
- */
- private Bundle mSharedElements;
+ private Bundle mSharedElementBundle;
- /**
- * Has the shared element transition completed?
- */
- private boolean mSharedElementsComplete;
+ private boolean mExitNotified;
- public ExitTransitionCoordinator(Window window,
- ActivityOptions.ActivityTransitionListener listener) {
- super(window);
- setActivityTransitionListener(listener);
+ private boolean mSharedElementNotified;
+
+ private Activity mActivity;
+
+ private boolean mIsBackgroundReady;
+
+ private boolean mIsReturning;
+
+ private boolean mIsCanceled;
+
+ private Handler mHandler;
+
+ public ExitTransitionCoordinator(Activity activity, ArrayList<String> names,
+ ArrayList<String> accepted, ArrayList<String> mapped, boolean isReturning) {
+ super(activity.getWindow(), names, accepted, mapped, activity.mTransitionListener);
+ mIsReturning = isReturning;
+ mIsBackgroundReady = !mIsReturning;
+ mActivity = activity;
}
@Override
- protected void onSetResultReceiver() {
- mIsResultReceiverSet = true;
- notifyCompletions();
- }
-
- @Override
- protected void onPrepareRestore() {
- makeTransitioningViewsInvisible();
- setEnteringViews(mTransitioningViews);
- mTransitioningViews = null;
- super.onPrepareRestore();
- }
-
- @Override
- protected void onTakeSharedElements(ArrayList<String> sharedElementNames, Bundle state) {
- super.onTakeSharedElements(sharedElementNames, state);
- clearConnections();
- }
-
- @Override
- protected void onActivityStopped() {
- if (getViewsTransition() != null) {
- setViewVisibility(mTransitioningViews, View.VISIBLE);
- }
- super.onActivityStopped();
- }
-
- @Override
- protected void sharedElementTransitionComplete(Bundle bundle) {
- mSharedElements = bundle;
- mSharedElementsComplete = true;
- notifyCompletions();
- }
-
- @Override
- protected void onExitTransitionEnd() {
- mExitComplete = true;
- notifyCompletions();
- super.onExitTransitionEnd();
- }
-
- private void notifyCompletions() {
- if (mIsResultReceiverSet && mSharedElementsComplete) {
- if (mSharedElements != null) {
- notifySharedElementTransitionComplete(mSharedElements);
- mSharedElements = null;
- }
- if (mExitComplete) {
- notifyExitTransitionComplete();
- }
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ switch (resultCode) {
+ case MSG_SET_REMOTE_RECEIVER:
+ mResultReceiver = resultData.getParcelable(KEY_REMOTE_RECEIVER);
+ if (mIsCanceled) {
+ mResultReceiver.send(MSG_CANCEL, null);
+ mResultReceiver = null;
+ } else {
+ if (mHandler != null) {
+ mHandler.removeMessages(MSG_CANCEL);
+ }
+ notifyComplete();
+ }
+ break;
+ case MSG_HIDE_SHARED_ELEMENTS:
+ if (!mIsCanceled) {
+ hideSharedElements();
+ }
+ break;
+ case MSG_START_EXIT_TRANSITION:
+ startExit();
+ break;
+ case MSG_ACTIVITY_STOPPED:
+ setViewVisibility(mTransitioningViews, View.VISIBLE);
+ setViewVisibility(mSharedElements, View.VISIBLE);
+ break;
}
}
- @Override
+ private void hideSharedElements() {
+ setViewVisibility(mSharedElements, View.INVISIBLE);
+ }
+
public void startExit() {
- if (!mExitStarted) {
- mExitStarted = true;
- setSharedElements();
- startExitTransition(getSharedElementNames());
+ beginTransition();
+ setViewVisibility(mTransitioningViews, View.INVISIBLE);
+ }
+
+ public void startExit(int resultCode, Intent data) {
+ mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ mIsCanceled = true;
+ mActivity.finish();
+ mActivity = null;
+ }
+ };
+ mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS);
+ if (getDecor().getBackground() == null) {
+ ColorDrawable black = new ColorDrawable(0xFF000000);
+ black.setAlpha(0);
+ getWindow().setBackgroundDrawable(black);
+ black.setAlpha(255);
}
+ ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
+ mAllSharedElementNames, resultCode, data);
+ mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
+ @Override
+ public void onTranslucentConversionComplete(boolean drawComplete) {
+ if (!mIsCanceled) {
+ fadeOutBackground();
+ }
+ }
+ }, options);
+ startExit();
+ }
+
+ private void fadeOutBackground() {
+ ObjectAnimator animator = ObjectAnimator.ofInt(getDecor().getBackground(),
+ "alpha", 0);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsBackgroundReady = true;
+ notifyComplete();
+ }
+ });
+ animator.setDuration(FADE_BACKGROUND_DURATION_MS);
+ animator.start();
+ }
+
+ private void beginTransition() {
+ Transition sharedElementTransition = configureTransition(getSharedElementTransition());
+ Transition viewsTransition = configureTransition(getViewsTransition());
+ viewsTransition = addTargets(viewsTransition, mTransitioningViews);
+ if (sharedElementTransition == null) {
+ sharedElementTransitionComplete();
+ } else {
+ sharedElementTransition.addListener(new Transition.TransitionListenerAdapter() {
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ sharedElementTransitionComplete();
+ }
+ });
+ }
+ if (viewsTransition == null) {
+ exitTransitionComplete();
+ } else {
+ viewsTransition.addListener(new Transition.TransitionListenerAdapter() {
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ exitTransitionComplete();
+ }
+ });
+ }
+
+ Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
+ TransitionManager.beginDelayedTransition(getDecor(), transition);
+ }
+
+ private void exitTransitionComplete() {
+ mExitComplete = true;
+ notifyComplete();
+ }
+
+ protected boolean isReadyToNotify() {
+ return mSharedElementBundle != null && mResultReceiver != null && mIsBackgroundReady;
+ }
+
+ private void sharedElementTransitionComplete() {
+ Bundle bundle = new Bundle();
+ int[] tempLoc = new int[2];
+ for (int i = 0; i < mSharedElementNames.size(); i++) {
+ View sharedElement = mSharedElements.get(i);
+ String name = mSharedElementNames.get(i);
+ captureSharedElementState(sharedElement, name, bundle, tempLoc);
+ }
+ mSharedElementBundle = bundle;
+ notifyComplete();
+ }
+
+ protected void notifyComplete() {
+ if (isReadyToNotify()) {
+ if (!mSharedElementNotified) {
+ mSharedElementNotified = true;
+ mResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, mSharedElementBundle);
+ }
+ if (!mExitNotified && mExitComplete) {
+ mExitNotified = true;
+ mResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
+ mResultReceiver = null; // done talking
+ if (mIsReturning) {
+ mActivity.finish();
+ mActivity.overridePendingTransition(0, 0);
+ }
+ mActivity = null;
+ }
+ }
+ }
+
+ /**
+ * Captures placement information for Views with a shared element name for
+ * Activity Transitions.
+ *
+ * @param view The View to capture the placement information for.
+ * @param name The shared element name in the target Activity to apply the placement
+ * information for.
+ * @param transitionArgs Bundle to store shared element placement information.
+ * @param tempLoc A temporary int[2] for capturing the current location of views.
+ */
+ private static void captureSharedElementState(View view, String name, Bundle transitionArgs,
+ int[] tempLoc) {
+ Bundle sharedElementBundle = new Bundle();
+ view.getLocationOnScreen(tempLoc);
+ float scaleX = view.getScaleX();
+ sharedElementBundle.putInt(KEY_SCREEN_X, tempLoc[0]);
+ int width = Math.round(view.getWidth() * scaleX);
+ sharedElementBundle.putInt(KEY_WIDTH, width);
+
+ float scaleY = view.getScaleY();
+ sharedElementBundle.putInt(KEY_SCREEN_Y, tempLoc[1]);
+ int height = Math.round(view.getHeight() * scaleY);
+ sharedElementBundle.putInt(KEY_HEIGHT, height);
+
+ sharedElementBundle.putFloat(KEY_TRANSLATION_Z, view.getTranslationZ());
+
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ view.draw(canvas);
+ sharedElementBundle.putParcelable(KEY_BITMAP, bitmap);
+
+ if (view instanceof ImageView) {
+ ImageView imageView = (ImageView) view;
+ int scaleTypeInt = scaleTypeToInt(imageView.getScaleType());
+ sharedElementBundle.putInt(KEY_SCALE_TYPE, scaleTypeInt);
+ if (imageView.getScaleType() == ImageView.ScaleType.MATRIX) {
+ float[] matrix = new float[9];
+ imageView.getImageMatrix().getValues(matrix);
+ sharedElementBundle.putFloatArray(KEY_IMAGE_MATRIX, matrix);
+ }
+ }
+
+ transitionArgs.putBundle(name, sharedElementBundle);
+ }
+
+ private static int scaleTypeToInt(ImageView.ScaleType scaleType) {
+ for (int i = 0; i < SCALE_TYPE_VALUES.length; i++) {
+ if (scaleType == SCALE_TYPE_VALUES[i]) {
+ return i;
+ }
+ }
+ return -1;
}
@Override
protected Transition getViewsTransition() {
- if (!getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
- return null;
- }
return getWindow().getExitTransition();
}
- @Override
protected Transition getSharedElementTransition() {
- if (!getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
- return null;
- }
return getWindow().getSharedElementExitTransition();
}
-
- private void makeTransitioningViewsInvisible() {
- if (getViewsTransition() != null) {
- setViewVisibility(mTransitioningViews, View.INVISIBLE);
- }
- }
-
- @Override
- protected void onStartExitTransition(ArrayList<View> exitingViews) {
- mTransitioningViews = new ArrayList<View>();
- if (exitingViews != null) {
- mTransitioningViews.addAll(exitingViews);
- }
- mTransitioningViews.addAll(getSharedElements());
- }
-
- @Override
- protected boolean allowOverlappingTransitions() {
- return getWindow().getAllowExitTransitionOverlap();
- }
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 2e9cdf3b7..8753312 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -45,6 +45,7 @@
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.StrictMode;
import android.service.voice.IVoiceInteractionSession;
@@ -104,13 +105,14 @@
public void activityResumed(IBinder token) throws RemoteException;
public void activityIdle(IBinder token, Configuration config,
boolean stopProfiling) throws RemoteException;
- public void activityPaused(IBinder token) throws RemoteException;
+ public void activityPaused(IBinder token, PersistableBundle persistentState) throws RemoteException;
public void activityStopped(IBinder token, Bundle state,
- Bitmap thumbnail, CharSequence description) throws RemoteException;
+ PersistableBundle persistentState, CharSequence description) throws RemoteException;
public void activitySlept(IBinder token) throws RemoteException;
public void activityDestroyed(IBinder token) throws RemoteException;
public String getCallingPackage(IBinder token) throws RemoteException;
public ComponentName getCallingActivity(IBinder token) throws RemoteException;
+ public List<IAppTask> getAppTasks() throws RemoteException;
public List<RunningTaskInfo> getTasks(int maxNum, int flags) throws RemoteException;
public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
int flags, int userId) throws RemoteException;
@@ -209,14 +211,16 @@
public int checkPermission(String permission, int pid, int uid)
throws RemoteException;
- public int checkUriPermission(Uri uri, int pid, int uid, int mode)
+ public int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId)
throws RemoteException;
- public void grantUriPermission(IApplicationThread caller, String targetPkg,
- Uri uri, int mode) throws RemoteException;
- public void revokeUriPermission(IApplicationThread caller, Uri uri,
- int mode) throws RemoteException;
- public void takePersistableUriPermission(Uri uri, int modeFlags) throws RemoteException;
- public void releasePersistableUriPermission(Uri uri, int modeFlags) throws RemoteException;
+ public void grantUriPermission(IApplicationThread caller, String targetPkg, Uri uri,
+ int mode, int userId) throws RemoteException;
+ public void revokeUriPermission(IApplicationThread caller, Uri uri, int mode, int userId)
+ throws RemoteException;
+ public void takePersistableUriPermission(Uri uri, int modeFlags, int userId)
+ throws RemoteException;
+ public void releasePersistableUriPermission(Uri uri, int modeFlags, int userId)
+ throws RemoteException;
public ParceledListSlice<UriPermission> getPersistedUriPermissions(
String packageName, boolean incoming) throws RemoteException;
@@ -308,8 +312,9 @@
public void finishHeavyWeightApp() throws RemoteException;
public boolean convertFromTranslucent(IBinder token) throws RemoteException;
- public boolean convertToTranslucent(IBinder token) throws RemoteException;
+ public boolean convertToTranslucent(IBinder token, ActivityOptions options) throws RemoteException;
public void notifyActivityDrawn(IBinder token) throws RemoteException;
+ public ActivityOptions getActivityOptions(IBinder token) throws RemoteException;
public void setImmersive(IBinder token, boolean immersive) throws RemoteException;
public boolean isImmersive(IBinder token) throws RemoteException;
@@ -322,12 +327,12 @@
public IBinder newUriPermissionOwner(String name) throws RemoteException;
public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
- Uri uri, int mode) throws RemoteException;
+ Uri uri, int mode, int userId) throws RemoteException;
public void revokeUriPermissionFromOwner(IBinder owner, Uri uri,
- int mode) throws RemoteException;
+ int mode, int userId) throws RemoteException;
- public int checkGrantUriPermission(int callingUid, String targetPkg,
- Uri uri, int modeFlags) throws RemoteException;
+ public int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri,
+ int modeFlags, int userId) throws RemoteException;
// Cause the specified process to dump the specified heap.
public boolean dumpHeap(String process, int userId, boolean managed, String path,
@@ -736,4 +741,6 @@
int IS_IN_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+216;
int SET_RECENTS_ACTIVITY_VALUES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
int START_VOICE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
+ int GET_ACTIVITY_OPTIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+219;
+ int GET_APP_TASKS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+220;
}
diff --git a/core/java/android/app/IAppTask.aidl b/core/java/android/app/IAppTask.aidl
new file mode 100644
index 0000000..268b4dd
--- /dev/null
+++ b/core/java/android/app/IAppTask.aidl
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.app.ActivityManager;
+
+/** @hide */
+interface IAppTask {
+ void finishAndRemoveTask();
+ ActivityManager.RecentTaskInfo getTaskInfo();
+}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index fefba8a..d0df7c3 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -25,9 +25,11 @@
import android.content.pm.ServiceInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Debug;
import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.IInterface;
@@ -58,10 +60,9 @@
void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
IVoiceInteractor voiceInteractor, int procState, Bundle state,
- List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed,
- boolean isForward,
- String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
- Bundle resumeArgs)
+ PersistableBundle persistentState, List<ResultInfo> pendingResults,
+ List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
+ String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler)
throws RemoteException;
void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, int configChanges,
@@ -105,7 +106,7 @@
void updateTimeZone() throws RemoteException;
void clearDnsCache() throws RemoteException;
void setHttpProxy(String proxy, String port, String exclList,
- String pacFileUrl) throws RemoteException;
+ Uri pacFileUrl) throws RemoteException;
void processInBackground() throws RemoteException;
void dumpService(FileDescriptor fd, IBinder servicetoken, String[] args)
throws RemoteException;
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index 347de97..8ab9ac3 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -43,4 +43,5 @@
WindowContentFrameStats getWindowContentFrameStats(int windowId);
void clearWindowAnimationFrameStats();
WindowAnimationFrameStats getWindowAnimationFrameStats();
+ void executeShellCommand(String command, in ParcelFileDescriptor fd);
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e58ccb8..b78b9c9 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -30,6 +30,7 @@
import android.os.Looper;
import android.os.MessageQueue;
import android.os.PerformanceCollector;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -1035,10 +1036,10 @@
IllegalAccessException {
Activity activity = (Activity)clazz.newInstance();
ActivityThread aThread = null;
- activity.attach(context, aThread, this, token, application, intent,
+ activity.attach(context, aThread, this, token, 0, application, intent,
info, title, parent, id,
(Activity.NonConfigurationInstances)lastNonConfigurationInstance,
- new Configuration());
+ new Configuration(), null);
return activity;
}
@@ -1061,15 +1062,7 @@
return (Activity)cl.loadClass(className).newInstance();
}
- /**
- * Perform calling of an activity's {@link Activity#onCreate}
- * method. The default implementation simply calls through to that method.
- *
- * @param activity The activity being created.
- * @param icicle The previously frozen state (or null) to pass through to
- * onCreate().
- */
- public void callActivityOnCreate(Activity activity, Bundle icicle) {
+ private void prePerformCreate(Activity activity) {
if (mWaitingActivities != null) {
synchronized (mSync) {
final int N = mWaitingActivities.size();
@@ -1083,9 +1076,9 @@
}
}
}
-
- activity.performCreate(icicle);
-
+ }
+
+ private void postPerformCreate(Activity activity) {
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
@@ -1096,6 +1089,33 @@
}
}
}
+
+ /**
+ * Perform calling of an activity's {@link Activity#onCreate}
+ * method. The default implementation simply calls through to that method.
+ *
+ * @param activity The activity being created.
+ * @param icicle The previously frozen state (or null) to pass through to onCreate().
+ */
+ public void callActivityOnCreate(Activity activity, Bundle icicle) {
+ prePerformCreate(activity);
+ activity.performCreate(icicle);
+ postPerformCreate(activity);
+ }
+
+ /**
+ * Perform calling of an activity's {@link Activity#onCreate}
+ * method. The default implementation simply calls through to that method.
+ * @param activity The activity being created.
+ * @param icicle The previously frozen state (or null) to pass through to
+ * @param persistentState The previously persisted state (or null)
+ */
+ public void callActivityOnCreate(Activity activity, Bundle icicle,
+ PersistableBundle persistentState) {
+ prePerformCreate(activity);
+ activity.performCreate(icicle, persistentState);
+ postPerformCreate(activity);
+ }
public void callActivityOnDestroy(Activity activity) {
// TODO: the following block causes intermittent hangs when using startActivity
@@ -1130,7 +1150,7 @@
/**
* Perform calling of an activity's {@link Activity#onRestoreInstanceState}
* method. The default implementation simply calls through to that method.
- *
+ *
* @param activity The activity being restored.
* @param savedInstanceState The previously saved state being restored.
*/
@@ -1139,9 +1159,22 @@
}
/**
+ * Perform calling of an activity's {@link Activity#onRestoreInstanceState}
+ * method. The default implementation simply calls through to that method.
+ *
+ * @param activity The activity being restored.
+ * @param savedInstanceState The previously saved state being restored.
+ * @param persistentState The previously persisted state (or null)
+ */
+ public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState,
+ PersistableBundle persistentState) {
+ activity.performRestoreInstanceState(savedInstanceState, persistentState);
+ }
+
+ /**
* Perform calling of an activity's {@link Activity#onPostCreate} method.
* The default implementation simply calls through to that method.
- *
+ *
* @param activity The activity being created.
* @param icicle The previously frozen state (or null) to pass through to
* onPostCreate().
@@ -1151,6 +1184,19 @@
}
/**
+ * Perform calling of an activity's {@link Activity#onPostCreate} method.
+ * The default implementation simply calls through to that method.
+ *
+ * @param activity The activity being created.
+ * @param icicle The previously frozen state (or null) to pass through to
+ * onPostCreate().
+ */
+ public void callActivityOnPostCreate(Activity activity, Bundle icicle,
+ PersistableBundle persistentState) {
+ activity.onPostCreate(icicle, persistentState);
+ }
+
+ /**
* Perform calling of an activity's {@link Activity#onNewIntent}
* method. The default implementation simply calls through to that method.
*
@@ -1215,7 +1261,7 @@
/**
* Perform calling of an activity's {@link Activity#onSaveInstanceState}
* method. The default implementation simply calls through to that method.
- *
+ *
* @param activity The activity being saved.
* @param outState The bundle to pass to the call.
*/
@@ -1224,6 +1270,18 @@
}
/**
+ * Perform calling of an activity's {@link Activity#onSaveInstanceState}
+ * method. The default implementation simply calls through to that method.
+ * @param activity The activity being saved.
+ * @param outState The bundle to pass to the call.
+ * @param outPersistentState The persistent bundle to pass to the call.
+ */
+ public void callActivityOnSaveInstanceState(Activity activity, Bundle outState,
+ PersistableBundle outPersistentState) {
+ activity.performSaveInstanceState(outState, outPersistentState);
+ }
+
+ /**
* Perform calling of an activity's {@link Activity#onPause} method. The
* default implementation simply calls through to that method.
*
@@ -1428,7 +1486,7 @@
}
/**
- * Like {@link #execStartActivity},
+ * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)},
* but accepts an array of activities to be started. Note that active
* {@link ActivityMonitor} objects only match against the first activity in
* the array.
@@ -1442,7 +1500,7 @@
}
/**
- * Like {@link #execStartActivity},
+ * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)},
* but accepts an array of activities to be started. Note that active
* {@link ActivityMonitor} objects only match against the first activity in
* the array.
@@ -1545,7 +1603,8 @@
}
/**
- * Like {@link #execStartActivity}, but for starting as a particular user.
+ * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)},
+ * but for starting as a particular user.
*
* @param who The Context from which the activity is being started.
* @param contextThread The main thread of the Context from which the activity
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index aab6ed8..db91742a 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -44,8 +44,8 @@
* you to disable / reenable the keyguard.
*/
public class KeyguardLock {
- private IBinder mToken = new Binder();
- private String mTag;
+ private final IBinder mToken = new Binder();
+ private final String mTag;
KeyguardLock(String tag) {
mTag = tag;
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index 96c7246..9ec7f41 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -340,9 +340,11 @@
super.onCreate(icicle);
mPackageManager = getPackageManager();
-
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- setProgressBarIndeterminateVisibility(true);
+
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ setProgressBarIndeterminateVisibility(true);
+ }
onSetContentView();
mIconResizer = new IconResizer();
@@ -357,7 +359,9 @@
updateAlertTitle();
updateButtonText();
- setProgressBarIndeterminateVisibility(false);
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ setProgressBarIndeterminateVisibility(false);
+ }
}
private void updateAlertTitle() {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index bba6caf..76a6a8e 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -659,8 +659,8 @@
/**
* @hide
- * Extra added by NotificationManagerService to indicate whether a NotificationScorer
- * modified the Notifications's score.
+ * Extra added by NotificationManagerService to indicate whether
+ * the Notifications's score has been modified.
*/
public static final String EXTRA_SCORE_MODIFIED = "android.scoreModified";
diff --git a/core/java/android/app/PackageInstallObserver.java b/core/java/android/app/PackageInstallObserver.java
index dacffb4..941efbd 100644
--- a/core/java/android/app/PackageInstallObserver.java
+++ b/core/java/android/app/PackageInstallObserver.java
@@ -18,32 +18,36 @@
import android.content.pm.IPackageInstallObserver2;
import android.os.Bundle;
-import android.os.RemoteException;
-/**
- * @hide
- *
- * New-style observer for package installers to use.
- */
+/** {@hide} */
public class PackageInstallObserver {
- IPackageInstallObserver2.Stub mObserver = new IPackageInstallObserver2.Stub() {
+ private final IPackageInstallObserver2.Stub mBinder = new IPackageInstallObserver2.Stub() {
@Override
- public void packageInstalled(String pkgName, Bundle extras, int result)
- throws RemoteException {
- PackageInstallObserver.this.packageInstalled(pkgName, extras, result);
+ public void packageInstalled(String basePackageName, Bundle extras, int returnCode) {
+ PackageInstallObserver.this.packageInstalled(basePackageName, extras, returnCode);
}
};
+ /** {@hide} */
+ public IPackageInstallObserver2.Stub getBinder() {
+ return mBinder;
+ }
+
/**
- * This method will be called to report the result of the package installation attempt.
+ * This method will be called to report the result of the package
+ * installation attempt.
*
- * @param pkgName Name of the package whose installation was attempted
- * @param extras If non-null, this Bundle contains extras providing additional information
- * about an install failure. See {@link android.content.pm.PackageManager} for
- * documentation about which extras apply to various failures; in particular the
- * strings named EXTRA_FAILURE_*.
- * @param result The numeric success or failure code indicating the basic outcome
+ * @param basePackageName Name of the package whose installation was
+ * attempted
+ * @param extras If non-null, this Bundle contains extras providing
+ * additional information about an install failure. See
+ * {@link android.content.pm.PackageManager} for documentation
+ * about which extras apply to various failures; in particular
+ * the strings named EXTRA_FAILURE_*.
+ * @param returnCode The numeric success or failure code indicating the
+ * basic outcome
+ * @hide
*/
- public void packageInstalled(String pkgName, Bundle extras, int result) {
+ public void packageInstalled(String basePackageName, Bundle extras, int returnCode) {
}
}
diff --git a/core/java/android/app/PackageUninstallObserver.java b/core/java/android/app/PackageUninstallObserver.java
new file mode 100644
index 0000000..0a960a7
--- /dev/null
+++ b/core/java/android/app/PackageUninstallObserver.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.content.pm.IPackageDeleteObserver;
+
+/** {@hide} */
+public class PackageUninstallObserver {
+ private final IPackageDeleteObserver.Stub mBinder = new IPackageDeleteObserver.Stub() {
+ @Override
+ public void packageDeleted(String basePackageName, int returnCode) {
+ PackageUninstallObserver.this.onUninstallFinished(basePackageName, returnCode);
+ }
+ };
+
+ /** {@hide} */
+ public IPackageDeleteObserver.Stub getBinder() {
+ return mBinder;
+ }
+
+ public void onUninstallFinished(String basePackageName, int returnCode) {
+ }
+}
diff --git a/core/java/android/app/SharedElementListener.java b/core/java/android/app/SharedElementListener.java
new file mode 100644
index 0000000..d4bc019
--- /dev/null
+++ b/core/java/android/app/SharedElementListener.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app;
+
+import android.view.View;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Listener provided in
+ * {@link Activity#setSharedElementListener(SharedElementListener)}
+ * to monitor the Activity transitions. The events can be used to customize or override Activity
+ * Transition behavior.
+ */
+public class SharedElementListener {
+ /**
+ * Called to allow the listener to customize the start state of the shared element for
+ * the shared element entering transition. By default, the shared element is placed in
+ * the position and with the size of the shared element in the calling Activity or Fragment.
+ *
+ * @param sharedElementNames The names of the shared elements that were accepted into
+ * the View hierarchy.
+ * @param sharedElements The shared elements that are part of the View hierarchy.
+ * @param sharedElementSnapshots The Views containing snap shots of the shared element
+ * from the launching Window. These elements will not
+ * be part of the scene, but will be positioned relative
+ * to the Window decor View.
+ */
+ public void setSharedElementStart(List<String> sharedElementNames,
+ List<View> sharedElements, List<View> sharedElementSnapshots) {}
+
+ /**
+ * Called to allow the listener to customize the end state of the shared element for
+ * the shared element entering transition.
+ *
+ * @param sharedElementNames The names of the shared elements that were accepted into
+ * the View hierarchy.
+ * @param sharedElements The shared elements that are part of the View hierarchy.
+ * @param sharedElementSnapshots The Views containing snap shots of the shared element
+ * from the launching Window. These elements will not
+ * be part of the scene, but will be positioned relative
+ * to the Window decor View.
+ */
+ public void setSharedElementEnd(List<String> sharedElementNames,
+ List<View> sharedElements, List<View> sharedElementSnapshots) {}
+
+ /**
+ * If nothing is done, all shared elements that were not accepted by
+ * {@link #remapSharedElements(java.util.List, java.util.Map)} will be Transitioned
+ * out of the entering scene automatically. Any elements removed from
+ * rejectedSharedElements must be handled by the ActivityTransitionListener.
+ * <p>Views in rejectedSharedElements will have their position and size set to the
+ * position of the calling shared element, relative to the Window decor View. This
+ * view may be safely added to the decor View's overlay to remain in position.</p>
+ *
+ * @param rejectedSharedElements Views containing visual information of shared elements
+ * that are not part of the entering scene. These Views
+ * are positioned relative to the Window decor View. A
+ * View removed from this list will not be transitioned
+ * automatically.
+ */
+ public void handleRejectedSharedElements(List<View> rejectedSharedElements) {}
+
+ /**
+ * Lets the ActivityTransitionListener adjust the mapping of shared element names to
+ * Views.
+ * @param names The names of all shared elements transferred from the calling Activity
+ * to the started Activity.
+ * @param sharedElements The mapping of shared element names to Views. The best guess
+ * will be filled into sharedElements based on the View names.
+ */
+ public void remapSharedElements(List<String> names, Map<String, View> sharedElements) {}
+}
diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index a85c61f..8cf8c25 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -110,6 +110,7 @@
(LayoutInflater) themeContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.time_picker_dialog, null);
setView(view);
+ setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
mTimePicker = (TimePicker) view.findViewById(R.id.timePicker);
// Initialize state
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 9405325..64e3484 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -26,6 +26,7 @@
import android.graphics.Point;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Looper;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
@@ -40,7 +41,9 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import android.view.accessibility.IAccessibilityInteractionConnection;
+import libcore.io.IoUtils;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;
@@ -840,6 +843,44 @@
return null;
}
+ /**
+ * Executes a shell command. This method returs a file descriptor that points
+ * to the standard output stream. The command execution is similar to running
+ * "adb shell <command>" from a host connected to the device.
+ * <p>
+ * <strong>Note:</strong> It is your responsibility to close the retunred file
+ * descriptor once you are done reading.
+ * </p>
+ *
+ * @param command The command to execute.
+ * @return A file descriptor to the standard output stream.
+ */
+ public ParcelFileDescriptor executeShellCommand(String command) {
+ synchronized (mLock) {
+ throwIfNotConnectedLocked();
+ }
+
+ ParcelFileDescriptor source = null;
+ ParcelFileDescriptor sink = null;
+
+ try {
+ ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
+ source = pipe[0];
+ sink = pipe[1];
+
+ // Calling out without a lock held.
+ mUiAutomationConnection.executeShellCommand(command, sink);
+ } catch (IOException ioe) {
+ Log.e(LOG_TAG, "Error executing shell command!", ioe);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error executing shell command!", re);
+ } finally {
+ IoUtils.closeQuietly(sink);
+ }
+
+ return source;
+ }
+
private static float getDegreesForRotation(int value) {
switch (value) {
case Surface.ROTATION_90: {
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index fa40286..81bcb39 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -23,6 +23,7 @@
import android.hardware.input.InputManager;
import android.os.Binder;
import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -33,6 +34,12 @@
import android.view.WindowContentFrameStats;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.IAccessibilityManager;
+import libcore.io.IoUtils;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
/**
* This is a remote object that is passed from the shell to an instrumentation
@@ -50,8 +57,8 @@
private final IWindowManager mWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService(Service.WINDOW_SERVICE));
- private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager.Stub.asInterface(
- ServiceManager.getService(Service.ACCESSIBILITY_SERVICE));
+ private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager.Stub
+ .asInterface(ServiceManager.getService(Service.ACCESSIBILITY_SERVICE));
private final Object mLock = new Object();
@@ -220,6 +227,41 @@
}
@Override
+ public void executeShellCommand(String command, ParcelFileDescriptor sink)
+ throws RemoteException {
+ synchronized (mLock) {
+ throwIfCalledByNotTrustedUidLocked();
+ throwIfShutdownLocked();
+ throwIfNotConnectedLocked();
+ }
+
+ InputStream in = null;
+ OutputStream out = null;
+
+ try {
+ java.lang.Process process = Runtime.getRuntime().exec(command);
+
+ in = process.getInputStream();
+ out = new FileOutputStream(sink.getFileDescriptor());
+
+ final byte[] buffer = new byte[8192];
+ while (true) {
+ final int readByteCount = in.read(buffer);
+ if (readByteCount < 0) {
+ break;
+ }
+ out.write(buffer, 0, readByteCount);
+ }
+ } catch (IOException ioe) {
+ throw new RuntimeException("Error running shell command", ioe);
+ } finally {
+ IoUtils.closeQuietly(in);
+ IoUtils.closeQuietly(out);
+ IoUtils.closeQuietly(sink);
+ }
+ }
+
+ @Override
public void shutdown() {
synchronized (mLock) {
if (isConnectedLocked()) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 58049fd..8884446 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2068,28 +2068,6 @@
}
/**
- * Called by a profile owner to disable account management for a specific type of account.
- *
- * <p>The calling device admin must be a profile owner. If it is not, a
- * security exception will be thrown.
- *
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
- * @param accountType For which account management is disabled or enabled.
- * @param disabled The boolean indicating that account management will be disabled (true) or
- * enabled (false).
- */
- public void setAccountManagementDisabled(ComponentName admin, String accountType,
- boolean disabled) {
- if (mService != null) {
- try {
- mService.setAccountManagementDisabled(admin, accountType, disabled);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed talking with device policy service", e);
- }
- }
- }
-
- /**
* Called by profile or device owner to re-enable system apps by intent that were disabled
* by default when the managed profile was created. This should only be called from a profile
* or device owner running within a managed profile.
@@ -2111,6 +2089,31 @@
}
/**
+ * Called by a profile owner to disable account management for a specific type of account.
+ *
+ * <p>The calling device admin must be a profile owner. If it is not, a
+ * security exception will be thrown.
+ *
+ * <p>When account management is disabled for an account type, adding or removing an account
+ * of that type will not be possible.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param accountType For which account management is disabled or enabled.
+ * @param disabled The boolean indicating that account management will be disabled (true) or
+ * enabled (false).
+ */
+ public void setAccountManagementDisabled(ComponentName admin, String accountType,
+ boolean disabled) {
+ if (mService != null) {
+ try {
+ mService.setAccountManagementDisabled(admin, accountType, disabled);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
* Gets the array of accounts for which account management is disabled by the profile owner.
*
* <p> Account management can be disabled/enabled by calling
diff --git a/core/java/android/app/task/TaskParams.java b/core/java/android/app/task/TaskParams.java
index e2eafd8..0351082 100644
--- a/core/java/android/app/task/TaskParams.java
+++ b/core/java/android/app/task/TaskParams.java
@@ -29,7 +29,14 @@
private final int taskId;
private final Bundle extras;
- private final IBinder mCallback;
+ private final IBinder callback;
+
+ /** @hide */
+ public TaskParams(int taskId, Bundle extras, IBinder callback) {
+ this.taskId = taskId;
+ this.extras = extras;
+ this.callback = callback;
+ }
/**
* @return The unique id of this task, specified at creation time.
@@ -47,17 +54,15 @@
return extras;
}
- /**
- * @hide
- */
+ /** @hide */
public ITaskCallback getCallback() {
- return ITaskCallback.Stub.asInterface(mCallback);
+ return ITaskCallback.Stub.asInterface(callback);
}
private TaskParams(Parcel in) {
taskId = in.readInt();
extras = in.readBundle();
- mCallback = in.readStrongBinder();
+ callback = in.readStrongBinder();
}
@Override
@@ -69,7 +74,7 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(taskId);
dest.writeBundle(extras);
- dest.writeStrongBinder(mCallback);
+ dest.writeStrongBinder(callback);
}
public static final Creator<TaskParams> CREATOR = new Creator<TaskParams>() {
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index a0b603e..f0c8299 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -20,7 +20,7 @@
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.DhcpResults;
-import android.net.LinkCapabilities;
+import android.net.NetworkCapabilities;
import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
@@ -75,7 +75,7 @@
private BluetoothTetheringDataTracker() {
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_BLUETOOTH, 0, NETWORKTYPE, "");
mLinkProperties = new LinkProperties();
- mLinkCapabilities = new LinkCapabilities();
+ mNetworkCapabilities = new NetworkCapabilities();
mNetworkInfo.setIsAvailable(false);
setTeardownRequested(false);
@@ -242,16 +242,6 @@
}
}
- /**
- * A capability is an Integer/String pair, the capabilities
- * are defined in the class LinkSocket#Key.
- *
- * @return a copy of this connections capabilities, may be empty but never null.
- */
- public LinkCapabilities getLinkCapabilities() {
- return new LinkCapabilities(mLinkCapabilities);
- }
-
/**
* Fetch default gateway address for the network
*/
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 49b156d..3dd7094 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -31,6 +31,8 @@
void startScan(in int appIf, in boolean isServer);
void startScanWithUuids(in int appIf, in boolean isServer, in ParcelUuid[] ids);
+ void startScanWithUuidsScanParam(in int appIf, in boolean isServer,
+ in ParcelUuid[] ids, int scanWindow, int scanInterval);
void stopScan(in int appIf, in boolean isServer);
void registerClient(in ParcelUuid appId, in IBluetoothGattCallback callback);
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 50c4fed..b44abf9 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -16,6 +16,7 @@
package android.content;
+import static android.content.ContentProvider.maybeAddUserId;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.net.Uri;
@@ -186,7 +187,7 @@
final CharSequence mText;
final String mHtmlText;
final Intent mIntent;
- final Uri mUri;
+ Uri mUri;
/**
* Create an Item consisting of a single block of (possibly styled) text.
@@ -809,6 +810,24 @@
}
}
+ /**
+ * Prepare this {@link ClipData} to leave an app process.
+ *
+ * @hide
+ */
+ public void prepareToLeaveUser(int userId) {
+ final int size = mItems.size();
+ for (int i = 0; i < size; i++) {
+ final Item item = mItems.get(i);
+ if (item.mIntent != null) {
+ item.mIntent.prepareToLeaveUser(userId);
+ }
+ if (item.mUri != null) {
+ item.mUri = maybeAddUserId(item.mUri, userId);
+ }
+ }
+ }
+
@Override
public String toString() {
StringBuilder b = new StringBuilder(128);
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 02c850b..be9782f 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -36,6 +36,7 @@
import android.os.Process;
import android.os.UserHandle;
import android.util.Log;
+import android.text.TextUtils;
import java.io.File;
import java.io.FileDescriptor;
@@ -195,6 +196,7 @@
return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
}
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.query(
@@ -207,6 +209,7 @@
@Override
public String getType(Uri uri) {
+ uri = getUriWithoutUserId(uri);
return ContentProvider.this.getType(uri);
}
@@ -215,9 +218,11 @@
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return rejectInsert(uri, initialValues);
}
+ int userId = getUserIdFromUri(uri);
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
- return ContentProvider.this.insert(uri, initialValues);
+ return maybeAddUserId(ContentProvider.this.insert(uri, initialValues), userId);
} finally {
setCallingPackage(original);
}
@@ -228,6 +233,7 @@
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.bulkInsert(uri, initialValues);
@@ -240,24 +246,39 @@
public ContentProviderResult[] applyBatch(String callingPkg,
ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
- for (ContentProviderOperation operation : operations) {
+ int numOperations = operations.size();
+ final int[] userIds = new int[numOperations];
+ for (int i = 0; i < numOperations; i++) {
+ ContentProviderOperation operation = operations.get(i);
+ userIds[i] = getUserIdFromUri(operation.getUri());
if (operation.isReadOperation()) {
if (enforceReadPermission(callingPkg, operation.getUri())
!= AppOpsManager.MODE_ALLOWED) {
throw new OperationApplicationException("App op not allowed", 0);
}
}
-
if (operation.isWriteOperation()) {
if (enforceWritePermission(callingPkg, operation.getUri())
!= AppOpsManager.MODE_ALLOWED) {
throw new OperationApplicationException("App op not allowed", 0);
}
}
+ if (userIds[i] != UserHandle.USER_CURRENT) {
+ // Removing the user id from the uri.
+ operation = new ContentProviderOperation(operation, true);
+ }
+ operations.set(i, operation);
}
final String original = setCallingPackage(callingPkg);
try {
- return ContentProvider.this.applyBatch(operations);
+ ContentProviderResult[] results = ContentProvider.this.applyBatch(operations);
+ for (int i = 0; i < results.length ; i++) {
+ if (userIds[i] != UserHandle.USER_CURRENT) {
+ // Adding the userId to the uri.
+ results[i] = new ContentProviderResult(results[i], userIds[i]);
+ }
+ }
+ return results;
} finally {
setCallingPackage(original);
}
@@ -268,6 +289,7 @@
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.delete(uri, selection, selectionArgs);
@@ -282,6 +304,7 @@
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.update(uri, values, selection, selectionArgs);
@@ -295,6 +318,7 @@
String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, mode);
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.openFile(
@@ -309,6 +333,7 @@
String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, mode);
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.openAssetFile(
@@ -330,6 +355,7 @@
@Override
public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
+ uri = getUriWithoutUserId(uri);
return ContentProvider.this.getStreamTypes(uri, mimeTypeFilter);
}
@@ -337,6 +363,7 @@
public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, "r");
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.openTypedAssetFile(
@@ -356,9 +383,11 @@
if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return null;
}
+ int userId = getUserIdFromUri(uri);
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
- return ContentProvider.this.canonicalize(uri);
+ return maybeAddUserId(ContentProvider.this.canonicalize(uri), userId);
} finally {
setCallingPackage(original);
}
@@ -369,9 +398,11 @@
if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return null;
}
+ int userId = getUserIdFromUri(uri);
+ uri = getUriWithoutUserId(uri);
final String original = setCallingPackage(callingPkg);
try {
- return ContentProvider.this.uncanonicalize(uri);
+ return maybeAddUserId(ContentProvider.this.uncanonicalize(uri), userId);
} finally {
setCallingPackage(original);
}
@@ -1680,4 +1711,75 @@
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
writer.println("nothing to dump");
}
+
+ /** @hide */
+ public static int getUserIdFromAuthority(String auth, int defaultUserId) {
+ if (auth == null) return defaultUserId;
+ int end = auth.indexOf('@');
+ if (end == -1) return defaultUserId;
+ String userIdString = auth.substring(0, end);
+ try {
+ return Integer.parseInt(userIdString);
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Error parsing userId.", e);
+ return UserHandle.USER_NULL;
+ }
+ }
+
+ /** @hide */
+ public static int getUserIdFromAuthority(String auth) {
+ return getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
+ }
+
+ /** @hide */
+ public static int getUserIdFromUri(Uri uri, int defaultUserId) {
+ if (uri == null) return defaultUserId;
+ return getUserIdFromAuthority(uri.getAuthority(), defaultUserId);
+ }
+
+ /** @hide */
+ public static int getUserIdFromUri(Uri uri) {
+ return getUserIdFromUri(uri, UserHandle.USER_CURRENT);
+ }
+
+ /**
+ * Removes userId part from authority string. Expects format:
+ * userId@some.authority
+ * If there is no userId in the authority, it symply returns the argument
+ * @hide
+ */
+ public static String getAuthorityWithoutUserId(String auth) {
+ if (auth == null) return null;
+ int end = auth.indexOf('@');
+ return auth.substring(end+1);
+ }
+
+ /** @hide */
+ public static Uri getUriWithoutUserId(Uri uri) {
+ if (uri == null) return null;
+ Uri.Builder builder = uri.buildUpon();
+ builder.authority(getAuthorityWithoutUserId(uri.getAuthority()));
+ return builder.build();
+ }
+
+ /** @hide */
+ public static boolean uriHasUserId(Uri uri) {
+ if (uri == null) return false;
+ return !TextUtils.isEmpty(uri.getUserInfo());
+ }
+
+ /** @hide */
+ public static Uri maybeAddUserId(Uri uri, int userId) {
+ if (uri == null) return null;
+ if (userId != UserHandle.USER_CURRENT
+ && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
+ if (!uriHasUserId(uri)) {
+ //We don't add the user Id if there's already one
+ Uri.Builder builder = uri.buildUpon();
+ builder.encodedAuthority("" + userId + "@" + uri.getEncodedAuthority());
+ return builder.build();
+ }
+ }
+ return uri;
+ }
}
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 12e9bab..136e54d 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -16,6 +16,7 @@
package android.content;
+import android.content.ContentProvider;
import android.database.Cursor;
import android.net.Uri;
import android.os.Parcel;
@@ -87,6 +88,31 @@
mYieldAllowed = source.readInt() != 0;
}
+ /** @hide */
+ public ContentProviderOperation(ContentProviderOperation cpo, boolean removeUserIdFromUri) {
+ mType = cpo.mType;
+ if (removeUserIdFromUri) {
+ mUri = ContentProvider.getUriWithoutUserId(cpo.mUri);
+ } else {
+ mUri = cpo.mUri;
+ }
+ mValues = cpo.mValues;
+ mSelection = cpo.mSelection;
+ mSelectionArgs = cpo.mSelectionArgs;
+ mExpectedCount = cpo.mExpectedCount;
+ mSelectionArgsBackReferences = cpo.mSelectionArgsBackReferences;
+ mValuesBackReferences = cpo.mValuesBackReferences;
+ mYieldAllowed = cpo.mYieldAllowed;
+ }
+
+ /** @hide */
+ public ContentProviderOperation getWithoutUserIdInUri() {
+ if (ContentProvider.uriHasUserId(mUri)) {
+ return new ContentProviderOperation(this, true);
+ }
+ return this;
+ }
+
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
Uri.writeToParcel(dest, mUri);
@@ -387,7 +413,6 @@
}
};
-
/**
* Used to add parameters to a {@link ContentProviderOperation}. The {@link Builder} is
* first created by calling {@link ContentProviderOperation#newInsert(android.net.Uri)},
diff --git a/core/java/android/content/ContentProviderResult.java b/core/java/android/content/ContentProviderResult.java
index 5d188ef..ec3d002 100644
--- a/core/java/android/content/ContentProviderResult.java
+++ b/core/java/android/content/ContentProviderResult.java
@@ -16,7 +16,9 @@
package android.content;
+import android.content.ContentProvider;
import android.net.Uri;
+import android.os.UserHandle;
import android.os.Parcelable;
import android.os.Parcel;
@@ -50,6 +52,12 @@
}
}
+ /** @hide */
+ public ContentProviderResult(ContentProviderResult cpr, int userId) {
+ uri = ContentProvider.maybeAddUserId(cpr.uri, userId);
+ count = cpr.count;
+ }
+
public void writeToParcel(Parcel dest, int flags) {
if (uri == null) {
dest.writeInt(1);
@@ -81,4 +89,4 @@
}
return "ContentProviderResult(count=" + count + ")";
}
-}
\ No newline at end of file
+}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 5b41394..7642e13 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1643,7 +1643,8 @@
*/
public void takePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) {
try {
- ActivityManagerNative.getDefault().takePersistableUriPermission(uri, modeFlags);
+ ActivityManagerNative.getDefault().takePersistableUriPermission(
+ ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
} catch (RemoteException e) {
}
}
@@ -1658,7 +1659,8 @@
*/
public void releasePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) {
try {
- ActivityManagerNative.getDefault().releasePersistableUriPermission(uri, modeFlags);
+ ActivityManagerNative.getDefault().releasePersistableUriPermission(
+ ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
} catch (RemoteException e) {
}
}
@@ -2462,4 +2464,9 @@
private final Context mContext;
final String mPackageName;
private static final String TAG = "ContentResolver";
+
+ /** @hide */
+ public int resolveUserId(Uri uri) {
+ return ContentProvider.getUserIdFromUri(uri, mContext.getUserId());
+ }
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 3cfc56c..076f657 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -26,6 +26,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.pm.ActivityInfo;
+import static android.content.ContentProvider.maybeAddUserId;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
@@ -7433,6 +7434,41 @@
}
/**
+ * Prepare this {@link Intent} to be sent to another user
+ *
+ * @hide
+ */
+ public void prepareToLeaveUser(int userId) {
+ Uri data = getData();
+ if (data != null) {
+ mData = maybeAddUserId(data, userId);
+ }
+ if (mSelector != null) {
+ mSelector.prepareToLeaveUser(userId);
+ }
+ if (mClipData != null) {
+ mClipData.prepareToLeaveUser(userId);
+ }
+ String action = getAction();
+ if (ACTION_SEND.equals(action)) {
+ final Uri stream = getParcelableExtra(EXTRA_STREAM);
+ if (stream != null) {
+ putExtra(EXTRA_STREAM, maybeAddUserId(stream, userId));
+ }
+ }
+ if (ACTION_SEND_MULTIPLE.equals(action)) {
+ final ArrayList<Uri> streams = getParcelableArrayListExtra(EXTRA_STREAM);
+ if (streams != null) {
+ ArrayList<Uri> newStreams = new ArrayList<Uri>();
+ for (int i = 0; i < streams.size(); i++) {
+ newStreams.add(maybeAddUserId(streams.get(i), userId));
+ }
+ putParcelableArrayListExtra(EXTRA_STREAM, newStreams);
+ }
+ }
+ }
+
+ /**
* Migrate any {@link #EXTRA_STREAM} in {@link #ACTION_SEND} and
* {@link #ACTION_SEND_MULTIPLE} to {@link ClipData}. Also inspects nested
* intents in {@link #ACTION_CHOOSER}.
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index d4f7f06..6b4404d 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -82,7 +82,7 @@
/**
* Set a set of String values in the preferences editor, to be written
- * back once {@link #commit} is called.
+ * back once {@link #commit} or {@link #apply} is called.
*
* @param key The name of the preference to modify.
* @param values The set of new values for the preference. Passing {@code null}
diff --git a/core/java/android/content/Task.java b/core/java/android/content/Task.java
index ed5ed884..407880f 100644
--- a/core/java/android/content/Task.java
+++ b/core/java/android/content/Task.java
@@ -42,6 +42,20 @@
public final int EXPONENTIAL = 1;
}
+ private final int taskId;
+ // TODO: Change this to use PersistableBundle when that lands in master.
+ private final Bundle extras;
+ private final ComponentName service;
+ private final boolean requireCharging;
+ private final boolean requireDeviceIdle;
+ private final int networkCapabilities;
+ private final long minLatencyMillis;
+ private final long maxExecutionDelayMillis;
+ private final boolean isPeriodic;
+ private final long intervalMillis;
+ private final long initialBackoffMillis;
+ private final int backoffPolicy;
+
/**
* Unique task id associated with this class. This is assigned to your task by the scheduler.
*/
@@ -59,8 +73,8 @@
/**
* Name of the service endpoint that will be called back into by the TaskManager.
*/
- public String getServiceClassName() {
- return serviceClassName;
+ public ComponentName getService() {
+ return service;
}
/**
@@ -132,24 +146,10 @@
return backoffPolicy;
}
- private final int taskId;
- // TODO: Change this to use PersistableBundle when that lands in master.
- private final Bundle extras;
- private final String serviceClassName;
- private final boolean requireCharging;
- private final boolean requireDeviceIdle;
- private final int networkCapabilities;
- private final long minLatencyMillis;
- private final long maxExecutionDelayMillis;
- private final boolean isPeriodic;
- private final long intervalMillis;
- private final long initialBackoffMillis;
- private final int backoffPolicy;
-
private Task(Parcel in) {
taskId = in.readInt();
extras = in.readBundle();
- serviceClassName = in.readString();
+ service = ComponentName.readFromParcel(in);
requireCharging = in.readInt() == 1;
requireDeviceIdle = in.readInt() == 1;
networkCapabilities = in.readInt();
@@ -164,7 +164,7 @@
private Task(Task.Builder b) {
taskId = b.mTaskId;
extras = new Bundle(b.mExtras);
- serviceClassName = b.mTaskServiceClassName;
+ service = b.mTaskService;
requireCharging = b.mRequiresCharging;
requireDeviceIdle = b.mRequiresDeviceIdle;
networkCapabilities = b.mNetworkCapabilities;
@@ -185,7 +185,7 @@
public void writeToParcel(Parcel out, int flags) {
out.writeInt(taskId);
out.writeBundle(extras);
- out.writeString(serviceClassName);
+ ComponentName.writeToParcel(service, out);
out.writeInt(requireCharging ? 1 : 0);
out.writeInt(requireDeviceIdle ? 1 : 0);
out.writeInt(networkCapabilities);
@@ -215,7 +215,7 @@
public final class Builder {
private int mTaskId;
private Bundle mExtras;
- private String mTaskServiceClassName;
+ private ComponentName mTaskService;
// Requirements.
private boolean mRequiresCharging;
private boolean mRequiresDeviceIdle;
@@ -236,11 +236,11 @@
* @param taskId Application-provided id for this task. Subsequent calls to cancel, or
* tasks created with the same taskId, will update the pre-existing task with
* the same id.
- * @param cls The endpoint that you implement that will receive the callback from the
+ * @param taskService The endpoint that you implement that will receive the callback from the
* TaskManager.
*/
- public Builder(int taskId, Class<TaskService> cls) {
- mTaskServiceClassName = cls.getClass().getName();
+ public Builder(int taskId, ComponentName taskService) {
+ mTaskService = taskService;
mTaskId = taskId;
}
@@ -296,7 +296,7 @@
* period. You have no control over when within this interval this task will be executed,
* only the guarantee that it will be executed at most once within this interval.
* A periodic task will be repeated until the phone is turned off, however it will only be
- * persisted if the client app has declared the
+ * persisted beyond boot if the client app has declared the
* {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission. You can schedule
* periodic tasks without this permission, they simply will cease to exist after the phone
* restarts.
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 0d1b262..6b44a11 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -453,7 +453,7 @@
*
* {@hide}
*/
- public String requiredCpuAbi;
+ public String cpuAbi;
/**
* The kernel user-ID that has been assigned to this application;
@@ -592,7 +592,7 @@
sourceDir = orig.sourceDir;
publicSourceDir = orig.publicSourceDir;
nativeLibraryDir = orig.nativeLibraryDir;
- requiredCpuAbi = orig.requiredCpuAbi;
+ cpuAbi = orig.cpuAbi;
resourceDirs = orig.resourceDirs;
seinfo = orig.seinfo;
sharedLibraryFiles = orig.sharedLibraryFiles;
@@ -634,7 +634,7 @@
dest.writeString(sourceDir);
dest.writeString(publicSourceDir);
dest.writeString(nativeLibraryDir);
- dest.writeString(requiredCpuAbi);
+ dest.writeString(cpuAbi);
dest.writeStringArray(resourceDirs);
dest.writeString(seinfo);
dest.writeStringArray(sharedLibraryFiles);
@@ -675,7 +675,7 @@
sourceDir = source.readString();
publicSourceDir = source.readString();
nativeLibraryDir = source.readString();
- requiredCpuAbi = source.readString();
+ cpuAbi = source.readString();
resourceDirs = source.readStringArray();
seinfo = source.readString();
sharedLibraryFiles = source.readStringArray();
diff --git a/core/java/android/content/pm/ContainerEncryptionParams.java b/core/java/android/content/pm/ContainerEncryptionParams.java
index 88112a7..dd1332b 100644
--- a/core/java/android/content/pm/ContainerEncryptionParams.java
+++ b/core/java/android/content/pm/ContainerEncryptionParams.java
@@ -16,6 +16,7 @@
package android.content.pm;
+import android.annotation.PrivateApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -31,8 +32,11 @@
/**
* Represents encryption parameters used to read a container.
*
+ * @deprecated encrypted containers are legacy.
* @hide
*/
+@PrivateApi
+@Deprecated
public class ContainerEncryptionParams implements Parcelable {
protected static final String TAG = "ContainerEncryptionParams";
diff --git a/core/java/android/content/pm/IPackageInstallObserver2.aidl b/core/java/android/content/pm/IPackageInstallObserver2.aidl
index 2602ab5..7205ce7 100644
--- a/core/java/android/content/pm/IPackageInstallObserver2.aidl
+++ b/core/java/android/content/pm/IPackageInstallObserver2.aidl
@@ -1,22 +1,22 @@
/*
-**
-** Copyright 2014, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package android.content.pm;
+import android.content.IntentSender;
import android.os.Bundle;
/**
@@ -40,6 +40,5 @@
* </tr>
* </table>
*/
- void packageInstalled(in String packageName, in Bundle extras, int returnCode);
+ void packageInstalled(String basePackageName, in Bundle extras, int returnCode);
}
-
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
new file mode 100644
index 0000000..68c019b
--- /dev/null
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageInstallerSession;
+import android.content.pm.PackageInstallerParams;
+import android.os.ParcelFileDescriptor;
+
+/** {@hide} */
+interface IPackageInstaller {
+ int createSession(int userId, String installerPackageName, in PackageInstallerParams params);
+ IPackageInstallerSession openSession(int sessionId);
+
+ int[] getSessions(int userId, String installerPackageName);
+
+ void uninstall(int userId, String basePackageName, in IPackageDeleteObserver observer);
+ void uninstallSplit(int userId, String basePackageName, String splitName, in IPackageDeleteObserver observer);
+}
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
new file mode 100644
index 0000000..f881acd
--- /dev/null
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.content.pm.IPackageInstallObserver2;
+import android.os.ParcelFileDescriptor;
+
+/** {@hide} */
+interface IPackageInstallerSession {
+ void updateProgress(int progress);
+
+ ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes);
+
+ void install(in IPackageInstallObserver2 observer);
+ void destroy();
+}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 03eb50f..6cb781f 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -26,6 +26,7 @@
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageInstallObserver;
import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageMoveObserver;
@@ -450,4 +451,6 @@
boolean setApplicationBlockedSettingAsUser(String packageName, boolean blocked, int userId);
boolean getApplicationBlockedSettingAsUser(String packageName, int userId);
+
+ IPackageInstaller getPackageInstaller();
}
diff --git a/core/java/android/content/pm/ManifestDigest.java b/core/java/android/content/pm/ManifestDigest.java
index 409b5ae..943534f 100644
--- a/core/java/android/content/pm/ManifestDigest.java
+++ b/core/java/android/content/pm/ManifestDigest.java
@@ -16,6 +16,7 @@
package android.content.pm;
+import android.annotation.PrivateApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Slog;
@@ -36,6 +37,7 @@
*
* @hide
*/
+@PrivateApi
public class ManifestDigest implements Parcelable {
private static final String TAG = "ManifestDigest";
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
new file mode 100644
index 0000000..d7bd473
--- /dev/null
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.app.PackageInstallObserver;
+import android.app.PackageUninstallObserver;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+
+/** {@hide} */
+public class PackageInstaller {
+ private final PackageManager mPm;
+ private final IPackageInstaller mInstaller;
+ private final int mUserId;
+ private final String mInstallerPackageName;
+
+ /** {@hide} */
+ public PackageInstaller(PackageManager pm, IPackageInstaller installer, int userId,
+ String installerPackageName) {
+ mPm = pm;
+ mInstaller = installer;
+ mUserId = userId;
+ mInstallerPackageName = installerPackageName;
+ }
+
+ public boolean isPackageAvailable(String basePackageName) {
+ try {
+ final ApplicationInfo info = mPm.getApplicationInfo(basePackageName,
+ PackageManager.GET_UNINSTALLED_PACKAGES);
+ return ((info.flags & ApplicationInfo.FLAG_INSTALLED) != 0);
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ public void installAvailablePackage(String basePackageName, PackageInstallObserver observer) {
+ int returnCode;
+ try {
+ returnCode = mPm.installExistingPackage(basePackageName);
+ } catch (NameNotFoundException e) {
+ returnCode = PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
+ }
+ observer.packageInstalled(basePackageName, null, returnCode);
+ }
+
+ public int createSession(PackageInstallerParams params) {
+ try {
+ return mInstaller.createSession(mUserId, mInstallerPackageName, params);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ public Session openSession(int sessionId) {
+ try {
+ return new Session(mInstaller.openSession(sessionId));
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ public int[] getSessions() {
+ try {
+ return mInstaller.getSessions(mUserId, mInstallerPackageName);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ public void uninstall(String basePackageName, PackageUninstallObserver observer) {
+ try {
+ mInstaller.uninstall(mUserId, basePackageName, observer.getBinder());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ public void uninstall(String basePackageName, String splitName,
+ PackageUninstallObserver observer) {
+ try {
+ mInstaller.uninstallSplit(mUserId, basePackageName, splitName, observer.getBinder());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * An installation that is being actively staged. For an install to succeed,
+ * all existing and new packages must have identical package names, version
+ * codes, and signing certificates.
+ * <p>
+ * A session may contain any number of split packages. If the application
+ * does not yet exist, this session must include a base package.
+ * <p>
+ * If a package included in this session is already defined by the existing
+ * installation (for example, the same split name), the package in this
+ * session will replace the existing package.
+ */
+ public class Session {
+ private IPackageInstallerSession mSession;
+
+ /** {@hide} */
+ public Session(IPackageInstallerSession session) {
+ mSession = session;
+ }
+
+ public void updateProgress(int progress) {
+ try {
+ mSession.updateProgress(progress);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ public ParcelFileDescriptor openWrite(String overlayName, long offsetBytes,
+ long lengthBytes) {
+ try {
+ return mSession.openWrite(overlayName, offsetBytes, lengthBytes);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ public void install(PackageInstallObserver observer) {
+ try {
+ mSession.install(observer.getBinder());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ public void close() {
+ // No resources to release at the moment
+ }
+
+ public void destroy() {
+ try {
+ mSession.destroy();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+ }
+}
diff --git a/core/java/android/content/pm/PackageInstallerParams.aidl b/core/java/android/content/pm/PackageInstallerParams.aidl
new file mode 100644
index 0000000..b3dde21
--- /dev/null
+++ b/core/java/android/content/pm/PackageInstallerParams.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+parcelable PackageInstallerParams;
diff --git a/core/java/android/content/pm/PackageInstallerParams.java b/core/java/android/content/pm/PackageInstallerParams.java
new file mode 100644
index 0000000..67cf276
--- /dev/null
+++ b/core/java/android/content/pm/PackageInstallerParams.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Parameters that define an installation session.
+ *
+ * {@hide}
+ */
+public class PackageInstallerParams implements Parcelable {
+
+ // TODO: extend to support remaining VerificationParams
+
+ /** {@hide} */
+ public boolean fullInstall;
+ /** {@hide} */
+ public int installFlags;
+ /** {@hide} */
+ public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
+ /** {@hide} */
+ public Signature[] signatures;
+ /** {@hide} */
+ public long deltaSize = -1;
+ /** {@hide} */
+ public Bitmap icon;
+ /** {@hide} */
+ public String title;
+ /** {@hide} */
+ public Uri originatingUri;
+ /** {@hide} */
+ public Uri referrerUri;
+
+ public PackageInstallerParams() {
+ }
+
+ /** {@hide} */
+ public PackageInstallerParams(Parcel source) {
+ this.fullInstall = source.readInt() != 0;
+ this.installFlags = source.readInt();
+ this.installLocation = source.readInt();
+ this.signatures = (Signature[]) source.readParcelableArray(null);
+ deltaSize = source.readLong();
+ if (source.readInt() != 0) {
+ icon = Bitmap.CREATOR.createFromParcel(source);
+ }
+ title = source.readString();
+ originatingUri = Uri.CREATOR.createFromParcel(source);
+ referrerUri = Uri.CREATOR.createFromParcel(source);
+ }
+
+ public void setFullInstall(boolean fullInstall) {
+ this.fullInstall = fullInstall;
+ }
+
+ public void setInstallFlags(int installFlags) {
+ this.installFlags = installFlags;
+ }
+
+ public void setInstallLocation(int installLocation) {
+ this.installLocation = installLocation;
+ }
+
+ public void setSignatures(Signature[] signatures) {
+ this.signatures = signatures;
+ }
+
+ public void setDeltaSize(long deltaSize) {
+ this.deltaSize = deltaSize;
+ }
+
+ public void setIcon(Bitmap icon) {
+ this.icon = icon;
+ }
+
+ public void setTitle(CharSequence title) {
+ this.title = (title != null) ? title.toString() : null;
+ }
+
+ public void setOriginatingUri(Uri originatingUri) {
+ this.originatingUri = originatingUri;
+ }
+
+ public void setReferrerUri(Uri referrerUri) {
+ this.referrerUri = referrerUri;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(fullInstall ? 1 : 0);
+ dest.writeInt(installFlags);
+ dest.writeInt(installLocation);
+ dest.writeParcelableArray(signatures, flags);
+ dest.writeLong(deltaSize);
+ if (icon != null) {
+ dest.writeInt(1);
+ icon.writeToParcel(dest, flags);
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeString(title);
+ dest.writeParcelable(originatingUri, flags);
+ dest.writeParcelable(referrerUri, flags);
+ }
+
+ public static final Parcelable.Creator<PackageInstallerParams>
+ CREATOR = new Parcelable.Creator<PackageInstallerParams>() {
+ @Override
+ public PackageInstallerParams createFromParcel(Parcel p) {
+ return new PackageInstallerParams(p);
+ }
+
+ @Override
+ public PackageInstallerParams[] newArray(int size) {
+ return new PackageInstallerParams[size];
+ }
+ };
+}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index eb2c11f..0e2eab7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -17,6 +17,7 @@
package android.content.pm;
import android.annotation.IntDef;
+import android.annotation.PrivateApi;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.PackageInstallObserver;
@@ -369,6 +370,7 @@
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} on success.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_SUCCEEDED = 1;
/**
@@ -377,6 +379,7 @@
* already installed.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_ALREADY_EXISTS = -1;
/**
@@ -385,6 +388,7 @@
* file is invalid.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_INVALID_APK = -2;
/**
@@ -393,6 +397,7 @@
* is invalid.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_INVALID_URI = -3;
/**
@@ -401,6 +406,7 @@
* service found that the device didn't have enough storage space to install the app.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_INSUFFICIENT_STORAGE = -4;
/**
@@ -409,6 +415,7 @@
* package is already installed with the same name.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_DUPLICATE_PACKAGE = -5;
/**
@@ -417,6 +424,7 @@
* the requested shared user does not exist.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_NO_SHARED_USER = -6;
/**
@@ -426,6 +434,7 @@
* than the new package (and the old package's data was not removed).
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_UPDATE_INCOMPATIBLE = -7;
/**
@@ -435,6 +444,7 @@
* device and does not have matching signature.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8;
/**
@@ -443,6 +453,7 @@
* the new package uses a shared library that is not available.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_MISSING_SHARED_LIBRARY = -9;
/**
@@ -451,6 +462,7 @@
* the new package uses a shared library that is not available.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10;
/**
@@ -460,6 +472,7 @@
* either because there was not enough storage or the validation failed.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_DEXOPT = -11;
/**
@@ -469,6 +482,7 @@
* that required by the package.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_OLDER_SDK = -12;
/**
@@ -478,6 +492,7 @@
* same authority as a provider already installed in the system.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13;
/**
@@ -487,6 +502,7 @@
* that required by the package.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_NEWER_SDK = -14;
/**
@@ -497,6 +513,7 @@
* flag.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_TEST_ONLY = -15;
/**
@@ -506,6 +523,7 @@
* compatible with the the device's CPU_ABI.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_CPU_ABI_INCOMPATIBLE = -16;
/**
@@ -514,6 +532,7 @@
* the new package uses a feature that is not available.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_MISSING_FEATURE = -17;
// ------ Errors related to sdcard
@@ -523,6 +542,7 @@
* a secure container mount point couldn't be accessed on external media.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_CONTAINER_ERROR = -18;
/**
@@ -532,6 +552,7 @@
* location.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19;
/**
@@ -541,6 +562,7 @@
* location because the media is not available.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_MEDIA_UNAVAILABLE = -20;
/**
@@ -549,6 +571,7 @@
* the new package couldn't be installed because the verification timed out.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_VERIFICATION_TIMEOUT = -21;
/**
@@ -557,6 +580,7 @@
* the new package couldn't be installed because the verification did not succeed.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_VERIFICATION_FAILURE = -22;
/**
@@ -565,6 +589,7 @@
* the package changed from what the calling program expected.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23;
/**
@@ -590,6 +615,7 @@
* '.apk' extension.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_PARSE_FAILED_NOT_APK = -100;
/**
@@ -598,6 +624,7 @@
* if the parser was unable to retrieve the AndroidManifest.xml file.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_PARSE_FAILED_BAD_MANIFEST = -101;
/**
@@ -606,6 +633,7 @@
* if the parser encountered an unexpected exception.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102;
/**
@@ -614,6 +642,7 @@
* if the parser did not find any certificates in the .apk.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103;
/**
@@ -622,6 +651,7 @@
* if the parser found inconsistent certificates on the files in the .apk.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES = -104;
/**
@@ -631,6 +661,7 @@
* files in the .apk.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING = -105;
/**
@@ -639,6 +670,7 @@
* if the parser encountered a bad or missing package name in the manifest.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME = -106;
/**
@@ -647,6 +679,7 @@
* if the parser encountered a bad shared user id name in the manifest.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID = -107;
/**
@@ -655,6 +688,7 @@
* if the parser encountered some structural problem in the manifest.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_PARSE_FAILED_MANIFEST_MALFORMED = -108;
/**
@@ -664,6 +698,7 @@
* in the manifest.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_PARSE_FAILED_MANIFEST_EMPTY = -109;
/**
@@ -672,6 +707,7 @@
* if the system failed to install the package because of system issues.
* @hide
*/
+ @PrivateApi
public static final int INSTALL_FAILED_INTERNAL_ERROR = -110;
/**
@@ -2863,6 +2899,7 @@
* instead. This method will continue to be supported but the older observer interface
* will not get additional failure details.
*/
+ // @PrivateApi
public abstract void installPackage(
Uri packageURI, IPackageInstallObserver observer, int flags,
String installerPackageName);
@@ -2897,6 +2934,7 @@
* continue to be supported but the older observer interface will not get additional failure
* details.
*/
+ // @PrivateApi
public abstract void installPackageWithVerification(Uri packageURI,
IPackageInstallObserver observer, int flags, String installerPackageName,
Uri verificationURI, ManifestDigest manifestDigest,
@@ -3025,6 +3063,7 @@
* on the system for other users, also install it for the calling user.
* @hide
*/
+ // @PrivateApi
public abstract int installExistingPackage(String packageName)
throws NameNotFoundException;
@@ -3114,6 +3153,7 @@
*
* @hide
*/
+ // @PrivateApi
public abstract void deletePackage(
String packageName, IPackageDeleteObserver observer, int flags);
@@ -3182,6 +3222,7 @@
*
* @hide
*/
+ // @PrivateApi
public abstract void freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer);
/**
@@ -3510,6 +3551,9 @@
*/
public abstract VerifierDeviceIdentity getVerifierDeviceIdentity();
+ /** {@hide} */
+ public abstract PackageInstaller getPackageInstaller();
+
/**
* Returns the data directory for a particular user and package, given the uid of the package.
* @param uid uid of the package, including the userId and appId
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ff96c51..1c838c3 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -16,6 +16,9 @@
package android.content.pm;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -32,6 +35,7 @@
import android.util.Base64;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.util.TypedValue;
@@ -41,6 +45,7 @@
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
+import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
@@ -51,7 +56,6 @@
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -61,6 +65,7 @@
import java.util.jar.StrictJarFile;
import java.util.zip.ZipEntry;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -207,16 +212,20 @@
*/
public static class PackageLite {
public final String packageName;
+ public final String splitName;
public final int versionCode;
public final int installLocation;
public final VerifierInfo[] verifiers;
+ public final Signature[] signatures;
- public PackageLite(String packageName, int versionCode,
- int installLocation, List<VerifierInfo> verifiers) {
+ public PackageLite(String packageName, String splitName, int versionCode,
+ int installLocation, List<VerifierInfo> verifiers, Signature[] signatures) {
this.packageName = packageName;
+ this.splitName = splitName;
this.versionCode = versionCode;
this.installLocation = installLocation;
this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
+ this.signatures = signatures;
}
}
@@ -459,7 +468,7 @@
return pi;
}
- private Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry je,
+ private static Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry je,
byte[] readBuffer) {
try {
// We must read the stream for the JarEntry to retrieve
@@ -486,6 +495,7 @@
public final static int PARSE_ON_SDCARD = 1<<5;
public final static int PARSE_IS_SYSTEM_DIR = 1<<6;
public final static int PARSE_IS_PRIVILEGED = 1<<7;
+ public final static int PARSE_GET_SIGNATURES = 1<<8;
public int getParseError() {
return mParseError;
@@ -722,12 +732,8 @@
mReadBuffer = readBufferRef;
}
- if (certs != null && certs.length > 0) {
- final int N = certs.length;
- pkg.mSignatures = new Signature[certs.length];
- for (int i=0; i<N; i++) {
- pkg.mSignatures[i] = new Signature(certs[i]);
- }
+ if (!ArrayUtils.isEmpty(certs)) {
+ pkg.mSignatures = convertToSignatures(certs);
} else {
Slog.e(TAG, "Package " + pkg.packageName
+ " has no certificates; ignoring!");
@@ -762,6 +768,39 @@
return true;
}
+ /**
+ * Only collect certificates on the manifest; does not validate signatures
+ * across remainder of package.
+ */
+ private static Signature[] collectCertificates(String packageFilePath) {
+ try {
+ final StrictJarFile jarFile = new StrictJarFile(packageFilePath);
+ try {
+ final ZipEntry jarEntry = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
+ if (jarEntry != null) {
+ final Certificate[][] certs = loadCertificates(jarFile, jarEntry, null);
+ return convertToSignatures(certs);
+ }
+ } finally {
+ jarFile.close();
+ }
+ } catch (GeneralSecurityException e) {
+ Slog.w(TAG, "Failed to collect certs from " + packageFilePath + ": " + e);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to collect certs from " + packageFilePath + ": " + e);
+ }
+ return null;
+ }
+
+ private static Signature[] convertToSignatures(Certificate[][] certs)
+ throws CertificateEncodingException {
+ final Signature[] res = new Signature[certs.length];
+ for (int i = 0; i < certs.length; i++) {
+ res[i] = new Signature(certs[i]);
+ }
+ return res;
+ }
+
/*
* Utility method that retrieves just the package name and install
* location from the apk location at the given file path.
@@ -794,11 +833,22 @@
return null;
}
+ // Only collect certificates on the manifest; does not validate
+ // signatures across remainder of package.
+ final Signature[] signatures;
+ if ((flags & PARSE_GET_SIGNATURES) != 0) {
+ signatures = collectCertificates(packageFilePath);
+ } else {
+ signatures = null;
+ }
+
final AttributeSet attrs = parser;
final String errors[] = new String[1];
PackageLite packageLite = null;
try {
- packageLite = parsePackageLite(res, parser, attrs, flags, errors);
+ packageLite = parsePackageLite(res, parser, attrs, flags, signatures, errors);
+ } catch (PackageParserException e) {
+ Slog.w(TAG, packageFilePath, e);
} catch (IOException e) {
Slog.w(TAG, packageFilePath, e);
} catch (XmlPullParserException e) {
@@ -840,72 +890,51 @@
? null : "must have at least one '.' separator";
}
- private static String parsePackageName(XmlPullParser parser,
- AttributeSet attrs, int flags, String[] outError)
- throws IOException, XmlPullParserException {
+ private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser,
+ AttributeSet attrs, int flags) throws IOException, XmlPullParserException,
+ PackageParserException {
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
- ;
}
if (type != XmlPullParser.START_TAG) {
- outError[0] = "No start tag found";
- return null;
+ throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "No start tag found");
}
- if (DEBUG_PARSER)
- Slog.v(TAG, "Root element name: '" + parser.getName() + "'");
if (!parser.getName().equals("manifest")) {
- outError[0] = "No <manifest> tag";
- return null;
- }
- String pkgName = attrs.getAttributeValue(null, "package");
- if (pkgName == null || pkgName.length() == 0) {
- outError[0] = "<manifest> does not specify package";
- return null;
- }
- String nameError = validateName(pkgName, true);
- if (nameError != null && !"android".equals(pkgName)) {
- outError[0] = "<manifest> specifies bad package name \""
- + pkgName + "\": " + nameError;
- return null;
+ throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "No <manifest> tag");
}
- return pkgName.intern();
+ final String packageName = attrs.getAttributeValue(null, "package");
+ if (!"android".equals(packageName)) {
+ final String error = validateName(packageName, true);
+ if (error != null) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+ "Invalid manifest package: " + error);
+ }
+ }
+
+ final String splitName = attrs.getAttributeValue(null, "split");
+ if (splitName != null) {
+ final String error = validateName(splitName, true);
+ if (error != null) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
+ "Invalid manifest split: " + error);
+ }
+ }
+
+ return Pair.create(packageName.intern(),
+ (splitName != null) ? splitName.intern() : splitName);
}
private static PackageLite parsePackageLite(Resources res, XmlPullParser parser,
- AttributeSet attrs, int flags, String[] outError) throws IOException,
- XmlPullParserException {
+ AttributeSet attrs, int flags, Signature[] signatures, String[] outError)
+ throws IOException, XmlPullParserException, PackageParserException {
+ final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs, flags);
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- ;
- }
-
- if (type != XmlPullParser.START_TAG) {
- outError[0] = "No start tag found";
- return null;
- }
- if (DEBUG_PARSER)
- Slog.v(TAG, "Root element name: '" + parser.getName() + "'");
- if (!parser.getName().equals("manifest")) {
- outError[0] = "No <manifest> tag";
- return null;
- }
- String pkgName = attrs.getAttributeValue(null, "package");
- if (pkgName == null || pkgName.length() == 0) {
- outError[0] = "<manifest> does not specify package";
- return null;
- }
- String nameError = validateName(pkgName, true);
- if (nameError != null && !"android".equals(pkgName)) {
- outError[0] = "<manifest> specifies bad package name \""
- + pkgName + "\": " + nameError;
- return null;
- }
int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
int versionCode = 0;
int numFound = 0;
@@ -925,6 +954,7 @@
}
// Only search the tree when the tag is directly below <manifest>
+ int type;
final int searchDepth = parser.getDepth() + 1;
final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>();
@@ -942,7 +972,8 @@
}
}
- return new PackageLite(pkgName.intern(), versionCode, installLocation, verifiers);
+ return new PackageLite(packageSplit.first, packageSplit.second, versionCode,
+ installLocation, verifiers, signatures);
}
/**
@@ -966,12 +997,18 @@
mParseActivityArgs = null;
mParseServiceArgs = null;
mParseProviderArgs = null;
-
- String pkgName = parsePackageName(parser, attrs, flags, outError);
- if (pkgName == null) {
+
+ final String pkgName;
+ final String splitName;
+ try {
+ Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs, flags);
+ pkgName = packageSplit.first;
+ splitName = packageSplit.second;
+ } catch (PackageParserException e) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
return null;
}
+
int type;
if (mOnlyCoreApps) {
@@ -982,9 +1019,9 @@
}
}
- final Package pkg = new Package(pkgName);
+ final Package pkg = new Package(pkgName, splitName);
boolean foundApp = false;
-
+
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifest);
pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
@@ -3544,6 +3581,7 @@
public final static class Package {
public String packageName;
+ public String splitName;
// For now we only support one application per package.
public final ApplicationInfo applicationInfo = new ApplicationInfo();
@@ -3660,9 +3698,10 @@
public Set<PublicKey> mSigningKeys;
public Map<String, Set<PublicKey>> mKeySetMapping;
- public Package(String _name) {
- packageName = _name;
- applicationInfo.packageName = _name;
+ public Package(String packageName, String splitName) {
+ this.packageName = packageName;
+ this.splitName = splitName;
+ applicationInfo.packageName = packageName;
applicationInfo.uid = -1;
}
@@ -4267,4 +4306,13 @@
public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) {
sCompatibilityModeEnabled = compatibilityModeEnabled;
}
+
+ public static class PackageParserException extends Exception {
+ public final int error;
+
+ public PackageParserException(int error, String detailMessage) {
+ super(detailMessage);
+ this.error = error;
+ }
+ }
}
diff --git a/core/java/android/content/pm/Signature.java b/core/java/android/content/pm/Signature.java
index f4e7dc3..96aa083 100644
--- a/core/java/android/content/pm/Signature.java
+++ b/core/java/android/content/pm/Signature.java
@@ -31,8 +31,10 @@
import java.util.Arrays;
/**
- * Opaque, immutable representation of a signature associated with an
+ * Opaque, immutable representation of a signing certificate associated with an
* application package.
+ * <p>
+ * This class name is slightly misleading, since it's not actually a signature.
*/
public class Signature implements Parcelable {
private final byte[] mSignature;
diff --git a/core/java/android/content/pm/VerificationParams.java b/core/java/android/content/pm/VerificationParams.java
index 22e1a85..bf1f77f 100644
--- a/core/java/android/content/pm/VerificationParams.java
+++ b/core/java/android/content/pm/VerificationParams.java
@@ -24,8 +24,10 @@
/**
* Represents verification parameters used to verify packages to be installed.
*
+ * @deprecated callers should migrate to {@link PackageInstallerParams}.
* @hide
*/
+@Deprecated
public class VerificationParams implements Parcelable {
/** A constant used to indicate that a uid value is not present. */
public static final int NO_UID = -1;
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 4bea9ee..86208fc 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -397,6 +397,32 @@
public static final String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
/**
+ * A constant describing a wake gesture sensor.
+ * <p>
+ * Wake gesture sensors enable waking up the device based on a device specific motion.
+ * <p>
+ * When this sensor triggers, the device behaves as if the power button was pressed, turning the
+ * screen on. This behavior (turning on the screen when this sensor triggers) might be
+ * deactivated by the user in the device settings. Changes in settings do not impact the
+ * behavior of the sensor: only whether the framework turns the screen on when it triggers.
+ * <p>
+ * The actual gesture to be detected is not specified, and can be chosen by the manufacturer of
+ * the device. This sensor must be low power, as it is likely to be activated 24/7.
+ * Values of events created by this sensors should not be used.
+ *
+ * @hide This sensor is expected to only be used by the power manager
+ */
+ public static final int TYPE_WAKE_GESTURE = 42;
+
+ /**
+ * A constant string describing a wake gesture sensor.
+ *
+ * @hide This sensor is expected to only be used by the power manager
+ * @see #TYPE_WAKE_GESTURE
+ */
+ public static final String STRING_TYPE_WAKE_GESTURE = "android.sensor.wake_gesture";
+
+ /**
* A constant describing all sensor types.
*/
public static final int TYPE_ALL = -1;
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 5f2af8cf..b1c1005 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -307,16 +307,14 @@
* <li>The sizes will be sorted by increasing pixel area (width x height).
* If several resolutions have the same area, they will be sorted by increasing width.</li>
* <li>The aspect ratio of the largest thumbnail size will be same as the
- * aspect ratio of largest JPEG output size in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations}.
+ * aspect ratio of largest JPEG output size in android.scaler.availableStreamConfigurations.
* The largest size is defined as the size that has the largest pixel area
* in a given size list.</li>
- * <li>Each output JPEG size in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations} will have at least
+ * <li>Each output JPEG size in android.scaler.availableStreamConfigurations will have at least
* one corresponding size that has the same aspect ratio in availableThumbnailSizes,
* and vice versa.</li>
* <li>All non (0, 0) sizes will have non-zero widths and heights.</li>
* </ul>
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
*/
public static final Key<android.hardware.camera2.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES =
new Key<android.hardware.camera2.Size[]>("android.jpeg.availableThumbnailSizes", android.hardware.camera2.Size[].class);
@@ -445,8 +443,10 @@
* working at that point; DO NOT USE without careful
* consideration of future support.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * @deprecated
* @hide
*/
+ @Deprecated
public static final Key<Byte> QUIRKS_USE_PARTIAL_RESULT =
new Key<Byte>("android.quirks.usePartialResult", byte.class);
@@ -461,8 +461,8 @@
* <p>This lists the upper bound of the number of output streams supported by
* the camera device. Using more streams simultaneously may require more hardware and
* CPU resources that will consume more power. The image format for a output stream can
- * be any supported format provided by {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations}.
- * The formats defined in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations} can be catergorized
+ * be any supported format provided by android.scaler.availableStreamConfigurations.
+ * The formats defined in android.scaler.availableStreamConfigurations can be catergorized
* into the 3 stream types as below:</p>
* <ul>
* <li>Processed (but stalling): any non-RAW format with a stallDurations > 0.
@@ -471,8 +471,6 @@
* <li>Processed (but not-stalling): any non-RAW format without a stall duration.
* Typically ImageFormat#YUV_420_888, ImageFormat#NV21, ImageFormat#YV12.</li>
* </ul>
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
*/
public static final Key<int[]> REQUEST_MAX_NUM_OUTPUT_STREAMS =
new Key<int[]>("android.request.maxNumOutputStreams", int[].class);
@@ -483,14 +481,12 @@
* <p>When set to 0, it means no input stream is supported.</p>
* <p>The image format for a input stream can be any supported
* format provided by
- * {@link CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP android.scaler.availableInputOutputFormatsMap}. When using an
+ * android.scaler.availableInputOutputFormatsMap. When using an
* input stream, there must be at least one output stream
* configured to to receive the reprocessed images.</p>
* <p>For example, for Zero Shutter Lag (ZSL) still capture use case, the input
* stream image format will be RAW_OPAQUE, the associated output stream image format
* should be JPEG.</p>
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP
*/
public static final Key<Integer> REQUEST_MAX_NUM_INPUT_STREAMS =
new Key<Integer>("android.request.maxNumInputStreams", int.class);
@@ -629,22 +625,26 @@
* camera device for output streams.</p>
* <p>All camera devices will support JPEG and YUV_420_888 formats.</p>
* <p>When set to YUV_420_888, application can access the YUV420 data directly.</p>
+ * @deprecated
+ * @hide
*/
+ @Deprecated
public static final Key<int[]> SCALER_AVAILABLE_FORMATS =
new Key<int[]>("android.scaler.availableFormats", int[].class);
/**
* <p>The minimum frame duration that is supported
- * for each resolution in {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_SIZES android.scaler.availableJpegSizes}.</p>
+ * for each resolution in android.scaler.availableJpegSizes.</p>
* <p>This corresponds to the minimum steady-state frame duration when only
* that JPEG stream is active and captured in a burst, with all
* processing (typically in android.*.mode) set to FAST.</p>
* <p>When multiple streams are configured, the minimum
* frame duration will be >= max(individual stream min
* durations)</p>
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_JPEG_SIZES
+ * @deprecated
+ * @hide
*/
+ @Deprecated
public static final Key<long[]> SCALER_AVAILABLE_JPEG_MIN_DURATIONS =
new Key<long[]>("android.scaler.availableJpegMinDurations", long[].class);
@@ -654,7 +654,10 @@
* sensor maximum resolution (defined by {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}).</p>
*
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @deprecated
+ * @hide
*/
+ @Deprecated
public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_JPEG_SIZES =
new Key<android.hardware.camera2.Size[]>("android.scaler.availableJpegSizes", android.hardware.camera2.Size[].class);
@@ -669,16 +672,17 @@
/**
* <p>For each available processed output size (defined in
- * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES android.scaler.availableProcessedSizes}), this property lists the
+ * android.scaler.availableProcessedSizes), this property lists the
* minimum supportable frame duration for that size.</p>
* <p>This should correspond to the frame duration when only that processed
* stream is active, with all processing (typically in android.*.mode)
* set to FAST.</p>
* <p>When multiple streams are configured, the minimum frame duration will
* be >= max(individual stream min durations).</p>
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES
+ * @deprecated
+ * @hide
*/
+ @Deprecated
public static final Key<long[]> SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS =
new Key<long[]>("android.scaler.availableProcessedMinDurations", long[].class);
@@ -696,7 +700,10 @@
* can provide.</p>
* <p>Please reference the documentation for the image data destination to
* check if it limits the maximum size for image data.</p>
+ * @deprecated
+ * @hide
*/
+ @Deprecated
public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_PROCESSED_SIZES =
new Key<android.hardware.camera2.Size[]>("android.scaler.availableProcessedSizes", android.hardware.camera2.Size[].class);
@@ -746,13 +753,14 @@
* </table>
* <p>For ZSL-capable camera devices, using the RAW_OPAQUE format
* as either input or output will never hurt maximum frame rate (i.e.
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations} will not have RAW_OPAQUE).</p>
+ * StreamConfigurationMap#getOutputStallDuration(int,Size)
+ * for a <code>format =</code> RAW_OPAQUE is always 0).</p>
* <p>Attempting to configure an input stream with output streams not
* listed as available in this map is not valid.</p>
- * <p>TODO: Add java type mapping for this property.</p>
+ * <p>TODO: typedef to ReprocessFormatMap</p>
*
* @see CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS
- * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
+ * @hide
*/
public static final Key<int[]> SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP =
new Key<int[]>("android.scaler.availableInputOutputFormatsMap", int[].class);
@@ -775,7 +783,7 @@
* check if it limits the maximum size for image data.</p>
* <p>Not all output formats may be supported in a configuration with
* an input stream of a particular format. For more details, see
- * {@link CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP android.scaler.availableInputOutputFormatsMap}.</p>
+ * android.scaler.availableInputOutputFormatsMap.</p>
* <p>The following table describes the minimum required output stream
* configurations based on the hardware level
* ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}):</p>
@@ -844,13 +852,11 @@
*
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
- * @see CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
- * @see #SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT
- * @see #SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT
+ * @hide
*/
- public static final Key<int[]> SCALER_AVAILABLE_STREAM_CONFIGURATIONS =
- new Key<int[]>("android.scaler.availableStreamConfigurations", int[].class);
+ public static final Key<android.hardware.camera2.params.StreamConfiguration[]> SCALER_AVAILABLE_STREAM_CONFIGURATIONS =
+ new Key<android.hardware.camera2.params.StreamConfiguration[]>("android.scaler.availableStreamConfigurations", android.hardware.camera2.params.StreamConfiguration[].class);
/**
* <p>This lists the minimum frame duration for each
@@ -863,14 +869,16 @@
* <p>The minimum frame duration of a stream (of a particular format, size)
* is the same regardless of whether the stream is input or output.</p>
* <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} and
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations} for more details about
+ * android.scaler.availableStallDurations for more details about
* calculating the max frame rate.</p>
+ * <p>(Keep in sync with
+ * StreamConfigurationMap#getOutputMinFrameDuration)</p>
*
- * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
* @see CaptureRequest#SENSOR_FRAME_DURATION
+ * @hide
*/
- public static final Key<long[]> SCALER_AVAILABLE_MIN_FRAME_DURATIONS =
- new Key<long[]>("android.scaler.availableMinFrameDurations", long[].class);
+ public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> SCALER_AVAILABLE_MIN_FRAME_DURATIONS =
+ new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.scaler.availableMinFrameDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class);
/**
* <p>This lists the maximum stall duration for each
@@ -929,12 +937,105 @@
* for more details.</p>
* <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} for more information about
* calculating the max frame rate (absent stalls).</p>
+ * <p>(Keep up to date with
+ * StreamConfigurationMap#getOutputStallDuration(int, Size) )</p>
*
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
* @see CaptureRequest#SENSOR_FRAME_DURATION
+ * @hide
*/
- public static final Key<long[]> SCALER_AVAILABLE_STALL_DURATIONS =
- new Key<long[]>("android.scaler.availableStallDurations", long[].class);
+ public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> SCALER_AVAILABLE_STALL_DURATIONS =
+ new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.scaler.availableStallDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class);
+
+ /**
+ * <p>The available stream configurations that this
+ * camera device supports; also includes the minimum frame durations
+ * and the stall durations for each format/size combination.</p>
+ * <p>All camera devices will support sensor maximum resolution (defined by
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}) for the JPEG format.</p>
+ * <p>For a given use case, the actual maximum supported resolution
+ * may be lower than what is listed here, depending on the destination
+ * Surface for the image data. For example, for recording video,
+ * the video encoder chosen may have a maximum size limit (e.g. 1080p)
+ * smaller than what the camera (e.g. maximum resolution is 3264x2448)
+ * can provide.</p>
+ * <p>Please reference the documentation for the image data destination to
+ * check if it limits the maximum size for image data.</p>
+ * <p>Not all output formats may be supported in a configuration with
+ * an input stream of a particular format. For more details, see
+ * android.scaler.availableInputOutputFormatsMap.</p>
+ * <p>The following table describes the minimum required output stream
+ * configurations based on the hardware level
+ * ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}):</p>
+ * <table>
+ * <thead>
+ * <tr>
+ * <th align="center">Format</th>
+ * <th align="center">Size</th>
+ * <th align="center">Hardware Level</th>
+ * <th align="center">Notes</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td align="center">JPEG</td>
+ * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
+ * <td align="center">Any</td>
+ * <td align="center"></td>
+ * </tr>
+ * <tr>
+ * <td align="center">JPEG</td>
+ * <td align="center">1920x1080 (1080p)</td>
+ * <td align="center">Any</td>
+ * <td align="center">if 1080p <= activeArraySize</td>
+ * </tr>
+ * <tr>
+ * <td align="center">JPEG</td>
+ * <td align="center">1280x720 (720)</td>
+ * <td align="center">Any</td>
+ * <td align="center">if 720p <= activeArraySize</td>
+ * </tr>
+ * <tr>
+ * <td align="center">JPEG</td>
+ * <td align="center">640x480 (480p)</td>
+ * <td align="center">Any</td>
+ * <td align="center">if 480p <= activeArraySize</td>
+ * </tr>
+ * <tr>
+ * <td align="center">JPEG</td>
+ * <td align="center">320x240 (240p)</td>
+ * <td align="center">Any</td>
+ * <td align="center">if 240p <= activeArraySize</td>
+ * </tr>
+ * <tr>
+ * <td align="center">YUV_420_888</td>
+ * <td align="center">all output sizes available for JPEG</td>
+ * <td align="center">FULL</td>
+ * <td align="center"></td>
+ * </tr>
+ * <tr>
+ * <td align="center">YUV_420_888</td>
+ * <td align="center">all output sizes available for JPEG, up to the maximum video size</td>
+ * <td align="center">LIMITED</td>
+ * <td align="center"></td>
+ * </tr>
+ * <tr>
+ * <td align="center">IMPLEMENTATION_DEFINED</td>
+ * <td align="center">same as YUV_420_888</td>
+ * <td align="center">Any</td>
+ * <td align="center"></td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * <p>Refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} for additional
+ * mandatory stream configurations on a per-capability basis.</p>
+ *
+ * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ */
+ public static final Key<android.hardware.camera2.params.StreamConfigurationMap> SCALER_STREAM_CONFIGURATION_MAP =
+ new Key<android.hardware.camera2.params.StreamConfigurationMap>("android.scaler.streamConfigurationMap", android.hardware.camera2.params.StreamConfigurationMap.class);
/**
* <p>Area of raw data which corresponds to only
@@ -982,13 +1083,9 @@
* being clipped to the maximum. See that control
* for a full definition of frame durations.</p>
* <p>Refer to
- * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS android.scaler.availableProcessedMinDurations},
- * {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS android.scaler.availableJpegMinDurations}, and
- * android.scaler.availableRawMinDurations for the minimum
- * frame duration values.</p>
+ * StreamConfigurationMap#getOutputMinFrameDuration(int,Size)
+ * for the minimum frame duration values.</p>
*
- * @see CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS
- * @see CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS
* @see CaptureRequest#SENSOR_FRAME_DURATION
*/
public static final Key<Long> SENSOR_INFO_MAX_FRAME_DURATION =
@@ -1007,9 +1104,7 @@
* including black calibration pixels.</p>
* <p>Maximum output resolution for raw format must
* match this in
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations}.</p>
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ * android.scaler.availableStreamConfigurations.</p>
*/
public static final Key<android.hardware.camera2.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE =
new Key<android.hardware.camera2.Size>("android.sensor.info.pixelArraySize", android.hardware.camera2.Size.class);
@@ -1420,4 +1515,13 @@
/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* End generated code
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
+
+
+
+
+
+
+
+
+
}
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 9d0e0e1..ca03dae 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -16,6 +16,8 @@
package android.hardware.camera2;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.graphics.ImageFormat;
import android.os.Handler;
import android.view.Surface;
@@ -147,7 +149,7 @@
* the size of the Surface with
* {@link android.view.SurfaceHolder#setFixedSize} to be one of the
* supported
- * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed sizes}
+ * {@link StreamConfigurationMap#getOutputSizes(Class) processed sizes}
* before calling {@link android.view.SurfaceHolder#getSurface}.</li>
*
* <li>For accessing through an OpenGL texture via a
@@ -155,14 +157,14 @@
* the SurfaceTexture with
* {@link android.graphics.SurfaceTexture#setDefaultBufferSize} to be one
* of the supported
- * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed sizes}
+ * {@link StreamConfigurationMap#getOutputSizes(Class) processed sizes}
* before creating a Surface from the SurfaceTexture with
* {@link Surface#Surface}.</li>
*
* <li>For recording with {@link android.media.MediaCodec}: Call
* {@link android.media.MediaCodec#createInputSurface} after configuring
* the media codec to use one of the
- * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed sizes}
+ * {@link StreamConfigurationMap#getOutputSizes(Class) processed sizes}
* </li>
*
* <li>For recording with {@link android.media.MediaRecorder}: TODO</li>
@@ -171,18 +173,15 @@
* Create a RenderScript
* {@link android.renderscript.Allocation Allocation} with a supported YUV
* type, the IO_INPUT flag, and one of the supported
- * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed sizes}. Then
+ * {@link StreamConfigurationMap#getOutputSizes(int) processed sizes}. Then
* obtain the Surface with
* {@link android.renderscript.Allocation#getSurface}.</li>
*
- * <li>For access to uncompressed or JPEG data in the application: Create a
- * {@link android.media.ImageReader} object with the desired
- * {@link CameraCharacteristics#SCALER_AVAILABLE_FORMATS image format}, and a
- * size from the matching
- * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed},
- * {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_SIZES jpeg}. Then obtain
- * a Surface from it.</li>
- *
+ * <li>For access to uncompressed or {@link ImageFormat#JPEG JPEG} data in the application:
+ * Create a {@link android.media.ImageReader} object with the desired
+ * {@link StreamConfigurationMap#getOutputFormats() image format}, and a size from the matching
+ * {@link StreamConfigurationMap#getOutputSizes(int) processed size} and {@code format}.
+ * Then obtain a {@link Surface} from it.</li>
* </ul>
*
* </p>
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 6e38a22f..a11390d 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -17,6 +17,7 @@
package android.hardware.camera2;
import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.utils.TypeReference;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
@@ -126,11 +127,13 @@
return keyList;
}
+ // TODO: make final or abstract
public static class Key<T> {
private boolean mHasTag;
private int mTag;
private final Class<T> mType;
+ private final TypeReference<T> mTypeReference;
private final String mName;
/**
@@ -144,6 +147,22 @@
}
mName = name;
mType = type;
+ mTypeReference = TypeReference.createSpecializedTypeReference(type);
+ }
+
+ /**
+ * @hide
+ */
+ @SuppressWarnings("unchecked")
+ public Key(String name, TypeReference<T> typeReference) {
+ if (name == null) {
+ throw new NullPointerException("Key needs a valid name");
+ } else if (typeReference == null) {
+ throw new NullPointerException("TypeReference needs to be non-null");
+ }
+ mName = name;
+ mType = (Class<T>)typeReference.getRawType();
+ mTypeReference = typeReference;
}
public final String getName() {
@@ -152,11 +171,10 @@
@Override
public final int hashCode() {
- return mName.hashCode();
+ return mName.hashCode() ^ mTypeReference.hashCode();
}
@Override
- @SuppressWarnings("unchecked")
public final boolean equals(Object o) {
if (this == o) {
return true;
@@ -166,9 +184,8 @@
return false;
}
- Key lhs = (Key) o;
-
- return mName.equals(lhs.mName) && mType.equals(lhs.mType);
+ Key<?> lhs = (Key<?>)o;
+ return mName.equals(lhs.mName) && mTypeReference.equals(lhs.mTypeReference);
}
/**
@@ -192,11 +209,29 @@
}
/**
+ * Get the raw class backing the type {@code T} for this key.
+ *
+ * <p>The distinction is only important if {@code T} is a generic, e.g.
+ * {@code Range<Integer>} since the nested type will be erased.</p>
+ *
* @hide
*/
public final Class<T> getType() {
+ // TODO: remove this; other places should use #getTypeReference() instead
return mType;
}
+
+ /**
+ * Get the type reference backing the type {@code T} for this key.
+ *
+ * <p>The distinction is only important if {@code T} is a generic, e.g.
+ * {@code Range<Integer>} since the nested type will be retained.</p>
+ *
+ * @hide
+ */
+ public final TypeReference<T> getTypeReference() {
+ return mTypeReference;
+ }
}
/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
@@ -411,20 +446,6 @@
public static final int REQUEST_AVAILABLE_CAPABILITIES_DNG = 5;
//
- // Enumeration values for CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
- //
-
- /**
- * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
- */
- public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT = 0;
-
- /**
- * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
- */
- public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT = 1;
-
- //
// Enumeration values for CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
//
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index f161f3a..8ae21f3 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -458,7 +458,19 @@
* brightness</p>
* <p>For example, if EV step is 0.333, '6' will mean an
* exposure compensation of +2 EV; -3 will mean an exposure
- * compensation of -1</p>
+ * compensation of -1 EV. Note that this control will only be effective
+ * if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF. This control will take effect even when
+ * {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} <code>== true</code>.</p>
+ * <p>In the event of exposure compensation value being changed, camera device
+ * may take several frames to reach the newly requested exposure target.
+ * During that time, {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} field will be in the SEARCHING
+ * state. Once the new exposure target is reached, {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} will
+ * change from SEARCHING to either CONVERGED, LOCKED (if AE lock is enabled), or
+ * FLASH_REQUIRED (if the scene is too dark for still capture).</p>
+ *
+ * @see CaptureRequest#CONTROL_AE_LOCK
+ * @see CaptureRequest#CONTROL_AE_MODE
+ * @see CaptureResult#CONTROL_AE_STATE
*/
public static final Key<Integer> CONTROL_AE_EXPOSURE_COMPENSATION =
new Key<Integer>("android.control.aeExposureCompensation", int.class);
@@ -469,6 +481,8 @@
* <p>Note that even when AE is locked, the flash may be
* fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_AUTO_FLASH / ON_ALWAYS_FLASH /
* ON_AUTO_FLASH_REDEYE.</p>
+ * <p>When {@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION android.control.aeExposureCompensation} is changed, even if the AE lock
+ * is ON, the camera device will still adjust its exposure value.</p>
* <p>If AE precapture is triggered (see {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger})
* when AE is already locked, the camera device will not change the exposure time
* ({@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}) and sensitivity ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity})
@@ -477,6 +491,7 @@
* {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_ALWAYS_FLASH, the scene may become overexposed.</p>
* <p>See {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE lock related state transition details.</p>
*
+ * @see CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
* @see CaptureResult#CONTROL_AE_STATE
@@ -1170,7 +1185,8 @@
* cannot process more than 1 capture at a time.</li>
* </ul>
* <p>The necessary information for the application, given the model above,
- * is provided via the {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} field.
+ * is provided via the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} field
+ * using StreamConfigurationMap#getOutputMinFrameDuration(int, Size).
* These are used to determine the maximum frame rate / minimum frame
* duration that is possible for a given stream configuration.</p>
* <p>Specifically, the application can use the following rules to
@@ -1180,7 +1196,8 @@
* <li>Let the set of currently configured input/output streams
* be called <code>S</code>.</li>
* <li>Find the minimum frame durations for each stream in <code>S</code>, by
- * looking it up in {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} (with
+ * looking it up in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} using
+ * StreamConfigurationMap#getOutputMinFrameDuration(int, Size) (with
* its respective size/format). Let this set of frame durations be called
* <code>F</code>.</li>
* <li>For any given request <code>R</code>, the minimum frame duration allowed
@@ -1188,7 +1205,8 @@
* used in <code>R</code> be called <code>S_r</code>.</li>
* </ol>
* <p>If none of the streams in <code>S_r</code> have a stall time (listed in
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}), then the frame duration in
+ * StreamConfigurationMap#getOutputStallDuration(int,Size) using its
+ * respective size/format), then the frame duration in
* <code>F</code> determines the steady state frame rate that the application will
* get if it uses <code>R</code> as a repeating request. Let this special kind
* of request be called <code>Rsimple</code>.</p>
@@ -1199,10 +1217,9 @@
* if all buffers from the previous <code>Rstall</code> have already been
* delivered.</p>
* <p>For more details about stalling, see
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}.</p>
+ * StreamConfigurationMap#getOutputStallDuration(int,Size).</p>
*
- * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
- * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
+ * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
*/
public static final Key<Long> SENSOR_FRAME_DURATION =
new Key<Long>("android.sensor.frameDuration", long.class);
@@ -1501,4 +1518,12 @@
/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* End generated code
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
+
+
+
+
+
+
+
+
}
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 51ea447..0160622 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -216,18 +216,6 @@
new Key<float[]>("android.colorCorrection.gains", float[].class);
/**
- * <p>The ID sent with the latest
- * CAMERA2_TRIGGER_PRECAPTURE_METERING call</p>
- * <p>Must be 0 if no
- * CAMERA2_TRIGGER_PRECAPTURE_METERING trigger received yet
- * by HAL. Always updated even if AE algorithm ignores the
- * trigger</p>
- * @hide
- */
- public static final Key<Integer> CONTROL_AE_PRECAPTURE_ID =
- new Key<Integer>("android.control.aePrecaptureId", int.class);
-
- /**
* <p>The desired setting for the camera device's auto-exposure
* algorithm's antibanding compensation.</p>
* <p>Some kinds of lighting fixtures, such as some fluorescent
@@ -275,7 +263,19 @@
* brightness</p>
* <p>For example, if EV step is 0.333, '6' will mean an
* exposure compensation of +2 EV; -3 will mean an exposure
- * compensation of -1</p>
+ * compensation of -1 EV. Note that this control will only be effective
+ * if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF. This control will take effect even when
+ * {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} <code>== true</code>.</p>
+ * <p>In the event of exposure compensation value being changed, camera device
+ * may take several frames to reach the newly requested exposure target.
+ * During that time, {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} field will be in the SEARCHING
+ * state. Once the new exposure target is reached, {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} will
+ * change from SEARCHING to either CONVERGED, LOCKED (if AE lock is enabled), or
+ * FLASH_REQUIRED (if the scene is too dark for still capture).</p>
+ *
+ * @see CaptureRequest#CONTROL_AE_LOCK
+ * @see CaptureRequest#CONTROL_AE_MODE
+ * @see CaptureResult#CONTROL_AE_STATE
*/
public static final Key<Integer> CONTROL_AE_EXPOSURE_COMPENSATION =
new Key<Integer>("android.control.aeExposureCompensation", int.class);
@@ -286,6 +286,8 @@
* <p>Note that even when AE is locked, the flash may be
* fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_AUTO_FLASH / ON_ALWAYS_FLASH /
* ON_AUTO_FLASH_REDEYE.</p>
+ * <p>When {@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION android.control.aeExposureCompensation} is changed, even if the AE lock
+ * is ON, the camera device will still adjust its exposure value.</p>
* <p>If AE precapture is triggered (see {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger})
* when AE is already locked, the camera device will not change the exposure time
* ({@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}) and sensitivity ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity})
@@ -294,6 +296,7 @@
* {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_ALWAYS_FLASH, the scene may become overexposed.</p>
* <p>See {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE lock related state transition details.</p>
*
+ * @see CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
* @see CaptureResult#CONTROL_AE_STATE
@@ -1053,17 +1056,6 @@
new Key<Integer>("android.control.afState", int.class);
/**
- * <p>The ID sent with the latest
- * CAMERA2_TRIGGER_AUTOFOCUS call</p>
- * <p>Must be 0 if no CAMERA2_TRIGGER_AUTOFOCUS trigger
- * received yet by HAL. Always updated even if AF algorithm
- * ignores the trigger</p>
- * @hide
- */
- public static final Key<Integer> CONTROL_AF_TRIGGER_ID =
- new Key<Integer>("android.control.afTriggerId", int.class);
-
- /**
* <p>Whether AWB is currently locked to its
* latest calculated values.</p>
* <p>Note that AWB lock is only meaningful for AUTO
@@ -1698,8 +1690,10 @@
* capture must arrive before the FINAL buffer for that capture. This entry may
* only be used by the camera device if quirks.usePartialResult is set to 1.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * @deprecated
* @hide
*/
+ @Deprecated
public static final Key<Boolean> QUIRKS_PARTIAL_RESULT =
new Key<Boolean>("android.quirks.partialResult", boolean.class);
@@ -1819,7 +1813,8 @@
* cannot process more than 1 capture at a time.</li>
* </ul>
* <p>The necessary information for the application, given the model above,
- * is provided via the {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} field.
+ * is provided via the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} field
+ * using StreamConfigurationMap#getOutputMinFrameDuration(int, Size).
* These are used to determine the maximum frame rate / minimum frame
* duration that is possible for a given stream configuration.</p>
* <p>Specifically, the application can use the following rules to
@@ -1829,7 +1824,8 @@
* <li>Let the set of currently configured input/output streams
* be called <code>S</code>.</li>
* <li>Find the minimum frame durations for each stream in <code>S</code>, by
- * looking it up in {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} (with
+ * looking it up in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} using
+ * StreamConfigurationMap#getOutputMinFrameDuration(int, Size) (with
* its respective size/format). Let this set of frame durations be called
* <code>F</code>.</li>
* <li>For any given request <code>R</code>, the minimum frame duration allowed
@@ -1837,7 +1833,8 @@
* used in <code>R</code> be called <code>S_r</code>.</li>
* </ol>
* <p>If none of the streams in <code>S_r</code> have a stall time (listed in
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}), then the frame duration in
+ * StreamConfigurationMap#getOutputStallDuration(int,Size) using its
+ * respective size/format), then the frame duration in
* <code>F</code> determines the steady state frame rate that the application will
* get if it uses <code>R</code> as a repeating request. Let this special kind
* of request be called <code>Rsimple</code>.</p>
@@ -1848,10 +1845,9 @@
* if all buffers from the previous <code>Rstall</code> have already been
* delivered.</p>
* <p>For more details about stalling, see
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}.</p>
+ * StreamConfigurationMap#getOutputStallDuration(int,Size).</p>
*
- * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
- * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
+ * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
*/
public static final Key<Long> SENSOR_FRAME_DURATION =
new Key<Long>("android.sensor.frameDuration", long.class);
@@ -2126,8 +2122,10 @@
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @deprecated
* @hide
*/
+ @Deprecated
public static final Key<float[]> STATISTICS_PREDICTED_COLOR_GAINS =
new Key<float[]>("android.statistics.predictedColorGains", float[].class);
@@ -2148,8 +2146,10 @@
* <p>This value should always be calculated by the AWB block,
* regardless of the android.control.* current values.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * @deprecated
* @hide
*/
+ @Deprecated
public static final Key<Rational[]> STATISTICS_PREDICTED_COLOR_TRANSFORM =
new Key<Rational[]>("android.statistics.predictedColorTransform", Rational[].class);
@@ -2426,6 +2426,14 @@
* End generated code
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
+
+
+
+
+
+
+
+
/**
* <p>
* List of the {@link Face Faces} detected through camera face detection
diff --git a/core/java/android/hardware/camera2/ColorSpaceTransform.java b/core/java/android/hardware/camera2/ColorSpaceTransform.java
index 9912e4b..5e4c0a2 100644
--- a/core/java/android/hardware/camera2/ColorSpaceTransform.java
+++ b/core/java/android/hardware/camera2/ColorSpaceTransform.java
@@ -17,7 +17,8 @@
package android.hardware.camera2;
import static com.android.internal.util.Preconditions.*;
-import android.hardware.camera2.impl.HashCodeHelpers;
+
+import android.hardware.camera2.utils.HashCodeHelpers;
import java.util.Arrays;
diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
index d77f3d1..0815170 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -20,7 +20,7 @@
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.LongParcelable;
+import android.hardware.camera2.utils.LongParcelable;
/** @hide */
interface ICameraDeviceUser
diff --git a/core/java/android/hardware/camera2/LensShadingMap.java b/core/java/android/hardware/camera2/LensShadingMap.java
index 2c224f6..2b0108c 100644
--- a/core/java/android/hardware/camera2/LensShadingMap.java
+++ b/core/java/android/hardware/camera2/LensShadingMap.java
@@ -19,7 +19,7 @@
import static com.android.internal.util.Preconditions.*;
import static android.hardware.camera2.RggbChannelVector.*;
-import android.hardware.camera2.impl.HashCodeHelpers;
+import android.hardware.camera2.utils.HashCodeHelpers;
import java.util.Arrays;
diff --git a/core/java/android/hardware/camera2/LongParcelable.aidl b/core/java/android/hardware/camera2/LongParcelable.aidl
deleted file mode 100644
index 7d7e51b..0000000
--- a/core/java/android/hardware/camera2/LongParcelable.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2;
-
-/** @hide */
-parcelable LongParcelable;
\ No newline at end of file
diff --git a/core/java/android/hardware/camera2/LongParcelable.java b/core/java/android/hardware/camera2/LongParcelable.java
deleted file mode 100644
index 97b0631..0000000
--- a/core/java/android/hardware/camera2/LongParcelable.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.camera2;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * @hide
- */
-public class LongParcelable implements Parcelable {
- private long number;
-
- public LongParcelable() {
- this.number = 0;
- }
-
- public LongParcelable(long number) {
- this.number = number;
- }
-
- public static final Parcelable.Creator<LongParcelable> CREATOR =
- new Parcelable.Creator<LongParcelable>() {
- @Override
- public LongParcelable createFromParcel(Parcel in) {
- return new LongParcelable(in);
- }
-
- @Override
- public LongParcelable[] newArray(int size) {
- return new LongParcelable[size];
- }
- };
-
- private LongParcelable(Parcel in) {
- readFromParcel(in);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeLong(number);
- }
-
- public void readFromParcel(Parcel in) {
- number = in.readLong();
- }
-
- public long getNumber() {
- return number;
- }
-
- public void setNumber(long number) {
- this.number = number;
- }
-
-}
diff --git a/core/java/android/hardware/camera2/MeteringRectangle.java b/core/java/android/hardware/camera2/MeteringRectangle.java
index ff7a745..bb8e5b1 100644
--- a/core/java/android/hardware/camera2/MeteringRectangle.java
+++ b/core/java/android/hardware/camera2/MeteringRectangle.java
@@ -20,7 +20,7 @@
import android.graphics.Point;
import android.graphics.Rect;
-import android.hardware.camera2.impl.HashCodeHelpers;
+import android.hardware.camera2.utils.HashCodeHelpers;
/**
* An immutable class to represent a rectangle {@code (x,y, width, height)} with an
@@ -186,10 +186,7 @@
*/
@Override
public boolean equals(final Object other) {
- if (other instanceof MeteringRectangle) {
- return equals(other);
- }
- return false;
+ return other instanceof MeteringRectangle && equals((MeteringRectangle)other);
}
/**
diff --git a/core/java/android/hardware/camera2/Rational.java b/core/java/android/hardware/camera2/Rational.java
index 77b8c26..693ee2b 100644
--- a/core/java/android/hardware/camera2/Rational.java
+++ b/core/java/android/hardware/camera2/Rational.java
@@ -91,14 +91,14 @@
* <p>A reduced form of a Rational is calculated by dividing both the numerator and the
* denominator by their greatest common divisor.</p>
*
- * <pre>
+ * <pre>{@code
* (new Rational(1, 2)).equals(new Rational(1, 2)) == true // trivially true
* (new Rational(2, 3)).equals(new Rational(1, 2)) == false // trivially false
* (new Rational(1, 2)).equals(new Rational(2, 4)) == true // true after reduction
* (new Rational(0, 0)).equals(new Rational(0, 0)) == true // NaN.equals(NaN)
* (new Rational(1, 0)).equals(new Rational(5, 0)) == true // both are +infinity
* (new Rational(1, 0)).equals(new Rational(-1, 0)) == false // +infinity != -infinity
- * </pre>
+ * }</pre>
*
* @param obj a reference to another object
*
@@ -159,16 +159,15 @@
return (float) mNumerator / (float) mDenominator;
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public int hashCode() {
- final long INT_MASK = 0xffffffffL;
+ // Bias the hash code for the first (2^16) values for both numerator and denominator
+ int numeratorFlipped = mNumerator << 16 | mNumerator >>> 16;
- long asLong = INT_MASK & mNumerator;
- asLong <<= 32;
-
- asLong |= (INT_MASK & mDenominator);
-
- return ((Long)asLong).hashCode();
+ return mDenominator ^ numeratorFlipped;
}
/**
diff --git a/core/java/android/hardware/camera2/ReprocessFormatsMap.java b/core/java/android/hardware/camera2/ReprocessFormatsMap.java
deleted file mode 100644
index c6c59d4..0000000
--- a/core/java/android/hardware/camera2/ReprocessFormatsMap.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2;
-
-import static com.android.internal.util.Preconditions.*;
-
-import android.hardware.camera2.impl.HashCodeHelpers;
-
-import java.util.Arrays;
-
-/**
- * Immutable class to store the input to output formats
- * {@link CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP map} to be used for with
- * camera image reprocessing.
- *
- * <p>
- * The mapping of image formats that are supported by this camera device for input streams,
- * to their corresponding output formats.</p>
- *
- * <p>
- * Attempting to configure an input stream with output streams not listed as available in this map
- * is not valid.
- * </p>
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP
- * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
- *
- * <!-- hide this until we expose input streams through public API -->
- * @hide
- */
-public final class ReprocessFormatsMap {
- /**
- * Create a new {@link ReprocessFormatsMap}
- *
- * <p>This value is encoded as a variable-size array-of-arrays.
- * The inner array always contains {@code [format, length, ...]} where ... has length elements.
- * An inner array is followed by another inner array if the total metadata entry size hasn't
- * yet been exceeded.</p>
- *
- * <p>Entry must not be {@code null}. Empty array is acceptable.</p>
- *
- * <p>The entry array ownership is passed to this instance after construction; do not
- * write to it afterwards.</p>
- *
- * @param entry Array of ints, not yet deserialized (not-null)
- *
- * @throws IllegalArgumentException
- * if the data was poorly formatted
- * (missing output format length or too few output formats)
- * @throws NullPointerException
- * if entry was null
- *
- * @hide
- */
- public ReprocessFormatsMap(final int[] entry) {
- checkNotNull(entry, "entry must not be null");
-
- int numInputs = 0;
- int left = entry.length;
- for (int i = 0; i < entry.length; ) {
- final int format = entry[i];
-
- left--;
- i++;
-
- if (left < 1) {
- throw new IllegalArgumentException(
- String.format("Input %x had no output format length listed", format));
- }
-
- final int length = entry[i];
- left--;
- i++;
-
- if (length > 0) {
- if (left < length) {
- throw new IllegalArgumentException(
- String.format(
- "Input %x had too few output formats listed (actual: %d, " +
- "expected: %d)", format, left, length));
- }
-
- i += length;
- left -= length;
- }
-
- numInputs++;
- }
-
- mEntry = entry;
- mInputCount = numInputs;
- }
-
- /**
- * Get a list of all input image formats that can be used to reprocess an input
- * stream into an output stream.
- *
- * <p>Use this input format to look up the available output formats with {@link #getOutputs}.
- * </p>
- *
- * @return an array of inputs (possibly empty, but never {@code null})
- *
- * @see ImageFormat
- * @see #getOutputs
- */
- public int[] getInputs() {
- final int[] inputs = new int[mInputCount];
-
- int left = mEntry.length;
- for (int i = 0, j = 0; i < mEntry.length; j++) {
- final int format = mEntry[i];
-
- left--;
- i++;
-
- if (left < 1) {
- throw new AssertionError(
- String.format("Input %x had no output format length listed", format));
- }
- // TODO: check format is a valid input format
-
- final int length = mEntry[i];
- left--;
- i++;
-
- if (length > 0) {
- if (left < length) {
- throw new AssertionError(
- String.format(
- "Input %x had too few output formats listed (actual: %d, " +
- "expected: %d)", format, left, length));
- }
-
- i += length;
- left -= length;
- }
-
- // TODO: check output format is a valid output format
-
- inputs[j] = format;
- }
-
- return inputs;
- }
-
- /**
- * Get the list of output formats that can be reprocessed into from the input {@code format}.
- *
- * <p>The input {@code format} must be one of the formats returned by {@link #getInputs}.</p>
- *
- * @param format an input format
- *
- * @return list of output image formats
- *
- * @see ImageFormat
- * @see #getInputs
- */
- public int[] getOutputs(final int format) {
-
- int left = mEntry.length;
- for (int i = 0; i < mEntry.length; ) {
- final int inputFormat = mEntry[i];
-
- left--;
- i++;
-
- if (left < 1) {
- throw new AssertionError(
- String.format("Input %x had no output format length listed", format));
- }
-
- final int length = mEntry[i];
- left--;
- i++;
-
- if (length > 0) {
- if (left < length) {
- throw new AssertionError(
- String.format(
- "Input %x had too few output formats listed (actual: %d, " +
- "expected: %d)", format, left, length));
- }
- }
-
- if (inputFormat == format) {
- int[] outputs = new int[length];
-
- // Copying manually faster than System.arraycopy for small arrays
- for (int k = 0; k < length; ++k) {
- outputs[k] = mEntry[i + k];
- }
-
- return outputs;
- }
-
- i += length;
- left -= length;
-
- }
-
- throw new IllegalArgumentException(
- String.format("Input format %x was not one in #getInputs", format));
- }
-
- /**
- * Check if this {@link ReprocessFormatsMap} is equal to another
- * {@link ReprocessFormatsMap}.
- *
- * <p>These two objects are only equal if and only if each of the respective elements is equal.
- * </p>
- *
- * @return {@code true} if the objects were equal, {@code false} otherwise
- */
- @Override
- public boolean equals(final Object obj) {
- if (obj == null) {
- return false;
- }
- if (this == obj) {
- return true;
- }
- if (obj instanceof ReprocessFormatsMap) {
- final ReprocessFormatsMap other = (ReprocessFormatsMap) obj;
- // Do not compare anything besides mEntry, since the rest of the values are derived
- return Arrays.equals(mEntry, other.mEntry);
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- // Do not hash anything besides mEntry since the rest of the values are derived
- return HashCodeHelpers.hashCode(mEntry);
- }
-
- private final int[] mEntry;
- /*
- * Dependent fields: values are derived from mEntry
- */
- private final int mInputCount;
-}
diff --git a/core/java/android/hardware/camera2/StreamConfiguration.java b/core/java/android/hardware/camera2/StreamConfiguration.java
deleted file mode 100644
index c53dd7c..0000000
--- a/core/java/android/hardware/camera2/StreamConfiguration.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2;
-
-import static com.android.internal.util.Preconditions.*;
-import static android.hardware.camera2.StreamConfigurationMap.checkArgumentFormatInternal;
-
-import android.graphics.ImageFormat;
-import android.hardware.camera2.impl.HashCodeHelpers;
-import android.util.Size;
-
-/**
- * Immutable class to store the available stream
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS configurations} to be used
- * when configuring streams with {@link CameraDevice#configureOutputs}.
- * <!-- TODO: link to input stream configuration -->
- *
- * <p>This is the authoritative list for all input/output formats (and sizes respectively
- * for that format) that are supported by a camera device.</p>
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
- *
- * @hide
- */
-public final class StreamConfiguration {
-
- /**
- * Create a new {@link StreamConfiguration}.
- *
- * @param format image format
- * @param width image width, in pixels (positive)
- * @param height image height, in pixels (positive)
- * @param input true if this is an input configuration, false for output configurations
- *
- * @throws IllegalArgumentException
- * if width/height were not positive
- * or if the format was not user-defined in ImageFormat/PixelFormat
- * (IMPL_DEFINED is ok)
- *
- * @hide
- */
- public StreamConfiguration(
- final int format, final int width, final int height, final boolean input) {
- mFormat = checkArgumentFormatInternal(format);
- mWidth = checkArgumentPositive(width, "width must be positive");
- mHeight = checkArgumentPositive(width, "height must be positive");
- mInput = input;
- }
-
- /**
- * Get the image {@code format} in this stream configuration.
- *
- * @return an integer format
- *
- * @see ImageFormat
- */
- public final int getFormat() {
- return mFormat;
- }
-
-
- /**
- * Return the width of the stream configuration.
- *
- * @return width > 0
- */
- public int getWidth() {
- return mWidth;
- }
-
- /**
- * Return the height of the stream configuration.
- *
- * @return height > 0
- */
- public int getHeight() {
- return mHeight;
- }
-
- /**
- * Convenience method to return the size of this stream configuration.
- *
- * @return a Size with positive width and height
- */
- public Size getSize() {
- return new Size(mWidth, mHeight);
- }
-
- /**
- * Determines if this configuration is usable for input streams.
- *
- * <p>Input and output stream configurations are not interchangeable;
- * input stream configurations must be used when configuring inputs.</p>
- *
- * @return {@code true} if input configuration, {@code false} otherwise
- */
- public boolean isInput() {
- return mInput;
- }
-
- /**
- * Determines if this configuration is usable for output streams.
- *
- * <p>Input and output stream configurations are not interchangeable;
- * out stream configurations must be used when configuring outputs.</p>
- *
- * @return {@code true} if output configuration, {@code false} otherwise
- *
- * @see CameraDevice#configureOutputs
- */
- public boolean isOutput() {
- return !mInput;
- }
-
- /**
- * Check if this {@link StreamConfiguration} is equal to another {@link StreamConfiguration}.
- *
- * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
- *
- * @return {@code true} if the objects were equal, {@code false} otherwise
- */
- @Override
- public boolean equals(final Object obj) {
- if (obj == null) {
- return false;
- }
- if (this == obj) {
- return true;
- }
- if (obj instanceof StreamConfiguration) {
- final StreamConfiguration other = (StreamConfiguration) obj;
- return mFormat == other.mFormat &&
- mWidth == other.mWidth &&
- mHeight == other.mHeight &&
- mInput == other.mInput;
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight, mInput ? 1 : 0);
- }
-
- private final int mFormat;
- private final int mWidth;
- private final int mHeight;
- private final boolean mInput;
-}
diff --git a/core/java/android/hardware/camera2/StreamConfigurationDuration.java b/core/java/android/hardware/camera2/StreamConfigurationDuration.java
deleted file mode 100644
index 189ae62..0000000
--- a/core/java/android/hardware/camera2/StreamConfigurationDuration.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2;
-
-import static com.android.internal.util.Preconditions.*;
-import static android.hardware.camera2.StreamConfigurationMap.checkArgumentFormatInternal;
-
-import android.graphics.ImageFormat;
-import android.hardware.camera2.impl.HashCodeHelpers;
-import android.util.Size;
-
-/**
- * Immutable class to store a time duration for any given format/size combination.
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
- * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
- * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
- *
- * @hide
- */
-public final class StreamConfigurationDuration {
-
- /**
- * Create a new {@link StreamConfigurationDuration}.
- *
- * @param format image format
- * @param width image width, in pixels (positive)
- * @param height image height, in pixels (positive)
- * @param durationNs duration in nanoseconds (non-negative)
- *
- * @throws IllegalArgumentException
- * if width/height were not positive, or durationNs was negative
- * or if the format was not user-defined in ImageFormat/PixelFormat
- * (IMPL_DEFINED is OK)
- *
- *
- * @hide
- */
- public StreamConfigurationDuration(
- final int format, final int width, final int height, final long durationNs) {
- mFormat = checkArgumentFormatInternal(format);
- mWidth = checkArgumentPositive(width, "width must be positive");
- mHeight = checkArgumentPositive(width, "height must be positive");
- mDurationNs = checkArgumentNonnegative(durationNs, "durationNs must be non-negative");
- }
-
- /**
- * Get the image {@code format} in this stream configuration duration
- *
- * @return an integer format
- *
- * @see ImageFormat
- */
- public final int getFormat() {
- return mFormat;
- }
-
-
- /**
- * Return the width of the stream configuration duration.
- *
- * @return width > 0
- */
- public int getWidth() {
- return mWidth;
- }
-
- /**
- * Return the height of the stream configuration duration
- *
- * @return height > 0
- */
- public int getHeight() {
- return mHeight;
- }
-
- /**
- * Convenience method to return the size of this stream configuration duration.
- *
- * @return a Size with positive width and height
- */
- public Size getSize() {
- return new Size(mWidth, mHeight);
- }
-
- /**
- * Get the time duration (in nanoseconds).
- *
- * @return long >= 0
- */
- public long getDuration() {
- return mDurationNs;
- }
-
- /**
- * Check if this {@link StreamConfigurationDuration} is equal to another
- * {@link StreamConfigurationDuration}.
- *
- * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
- *
- * @return {@code true} if the objects were equal, {@code false} otherwise
- */
- @Override
- public boolean equals(final Object obj) {
- if (obj == null) {
- return false;
- }
- if (this == obj) {
- return true;
- }
- if (obj instanceof StreamConfigurationDuration) {
- final StreamConfigurationDuration other = (StreamConfigurationDuration) obj;
- return mFormat == other.mFormat &&
- mWidth == other.mWidth &&
- mHeight == other.mHeight &&
- mDurationNs == other.mDurationNs;
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight,
- (int) mDurationNs, (int)(mDurationNs >>> Integer.SIZE));
- }
-
- private final int mFormat;
- private final int mWidth;
- private final int mHeight;
- private final long mDurationNs;
-}
diff --git a/core/java/android/hardware/camera2/StreamConfigurationMap.java b/core/java/android/hardware/camera2/StreamConfigurationMap.java
deleted file mode 100644
index e24fd1b..0000000
--- a/core/java/android/hardware/camera2/StreamConfigurationMap.java
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2;
-
-import android.graphics.ImageFormat;
-import android.graphics.PixelFormat;
-import android.hardware.camera2.impl.HashCodeHelpers;
-import android.view.Surface;
-import android.util.Size;
-
-import java.util.Arrays;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Immutable class to store the available stream
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS configurations} to be used
- * when configuring streams with {@link CameraDevice#configureOutputs}.
- * <!-- TODO: link to input stream configuration -->
- *
- * <p>This is the authoritative list for all <!-- input/ -->output formats (and sizes respectively
- * for that format) that are supported by a camera device.</p>
- *
- * <p>This also contains the minimum frame durations and stall durations for each format/size
- * combination that can be used to calculate effective frame rate when submitting multiple captures.
- * </p>
- *
- * <p>An instance of this object is available from {@link CameraCharacteristics} using
- * the {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS} key and the
- * {@link CameraCharacteristics#get} method.</p.
- *
- * <pre>{@code
- * CameraCharacteristics characteristics = ...;
- * StreamConfigurationMap configs = characteristics.get(
- * CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
- * }</pre>
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
- * @see CameraDevice#configureOutputs
- */
-public final class StreamConfigurationMap {
-
- /**
- * Create a new {@link StreamConfigurationMap}.
- *
- * <p>The array parameters ownership is passed to this object after creation; do not
- * write to them after this constructor is invoked.</p>
- *
- * @param configurations a non-{@code null} array of {@link StreamConfiguration}
- * @param durations a non-{@code null} array of {@link StreamConfigurationDuration}
- *
- * @throws NullPointerException if any of the arguments or subelements were {@code null}
- *
- * @hide
- */
- public StreamConfigurationMap(
- StreamConfiguration[] configurations,
- StreamConfigurationDuration[] durations) {
- // TODO: format check against ImageFormat/PixelFormat ?
-
- mConfigurations = checkArrayElementsNotNull(configurations, "configurations");
- mDurations = checkArrayElementsNotNull(durations, "durations");
-
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get the image {@code format} output formats in this stream configuration.
- *
- * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
- * or in {@link PixelFormat} (and there is no possibility of collision).</p>
- *
- * <p>Formats listed in this array are guaranteed to return true if queried with
- * {@link #isOutputSupportedFor(int).</p>
- *
- * @return an array of integer format
- *
- * @see ImageFormat
- * @see PixelFormat
- */
- public final int[] getOutputFormats() {
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get the image {@code format} input formats in this stream configuration.
- *
- * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
- * or in {@link PixelFormat} (and there is no possibility of collision).</p>
- *
- * @return an array of integer format
- *
- * @see ImageFormat
- * @see PixelFormat
- *
- * @hide
- */
- public final int[] getInputFormats() {
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get the supported input sizes for this input format.
- *
- * <p>The format must have come from {@link #getInputFormats}; otherwise
- * {@code null} is returned.</p>
- *
- * @param format a format from {@link #getInputFormats}
- * @return a non-empty array of sizes, or {@code null} if the format was not available.
- *
- * @hide
- */
- public Size[] getInputSizes(final int format) {
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Determine whether or not output streams can be
- * {@link CameraDevice#configureOutputs configured} with a particular user-defined format.
- *
- * <p>This method determines that the output {@code format} is supported by the camera device;
- * each output {@code surface} target may or may not itself support that {@code format}.
- * Refer to the class which provides the surface for additional documentation.</p>
- *
- * <p>Formats for which this returns {@code true} are guaranteed to exist in the result
- * returned by {@link #getOutputSizes}.</p>
- *
- * @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
- * @return
- * {@code true} iff using a {@code surface} with this {@code format} will be
- * supported with {@link CameraDevice#configureOutputs}
- *
- * @throws IllegalArgumentException
- * if the image format was not a defined named constant
- * from either {@link ImageFormat} or {@link PixelFormat}
- *
- * @see ImageFormat
- * @see PixelFormat
- * @see CameraDevice#configureOutputs
- */
- public boolean isOutputSupportedFor(int format) {
- checkArgumentFormat(format);
-
- final int[] formats = getOutputFormats();
- for (int i = 0; i < formats.length; ++i) {
- if (format == formats[i]) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Determine whether or not output streams can be configured with a particular class
- * as a consumer.
- *
- * <p>The following list is generally usable for outputs:
- * <ul>
- * <li>{@link android.media.ImageReader} -
- * Recommended for image processing or streaming to external resources (such as a file or
- * network)
- * <li>{@link android.media.MediaRecorder} -
- * Recommended for recording video (simple to use)
- * <li>{@link android.media.MediaCodec} -
- * Recommended for recording video (more complicated to use, with more flexibility)
- * <li>{@link android.renderscript.Allocation} -
- * Recommended for image processing with {@link android.renderscript RenderScript}
- * <li>{@link android.view.SurfaceHolder} -
- * Recommended for low-power camera preview with {@link android.view.SurfaceView}
- * <li>{@link android.graphics.SurfaceTexture} -
- * Recommended for OpenGL-accelerated preview processing or compositing with
- * {@link android.view.TextureView}
- * </ul>
- * </p>
- *
- * <p>Generally speaking this means that creating a {@link Surface} from that class <i>may</i>
- * provide a producer endpoint that is suitable to be used with
- * {@link CameraDevice#configureOutputs}.</p>
- *
- * <p>Since not all of the above classes support output of all format and size combinations,
- * the particular combination should be queried with {@link #isOutputSupportedFor(Surface)}.</p>
- *
- * @param klass a non-{@code null} {@link Class} object reference
- * @return {@code true} if this class is supported as an output, {@code false} otherwise
- *
- * @throws NullPointerException if {@code klass} was {@code null}
- *
- * @see CameraDevice#configureOutputs
- * @see #isOutputSupportedFor(Surface)
- */
- public static <T> boolean isOutputSupportedFor(final Class<T> klass) {
- checkNotNull(klass, "klass must not be null");
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Determine whether or not the {@code surface} in its current state is suitable to be
- * {@link CameraDevice#configureOutputs configured} as an output.
- *
- * <p>Not all surfaces are usable with the {@link CameraDevice}, and not all configurations
- * of that {@code surface} are compatible. Some classes that provide the {@code surface} are
- * compatible with the {@link CameraDevice} in general
- * (see {@link #isOutputSupportedFor(Class)}, but it is the caller's responsibility to put the
- * {@code surface} into a state that will be compatible with the {@link CameraDevice}.</p>
- *
- * <p>Reasons for a {@code surface} being specifically incompatible might be:
- * <ul>
- * <li>Using a format that's not listed by {@link #getOutputFormats}
- * <li>Using a format/size combination that's not listed by {@link #getOutputSizes}
- * <li>The {@code surface} itself is not in a state where it can service a new producer.</p>
- * </li>
- * </ul>
- *
- * This is not an exhaustive list; see the particular class's documentation for further
- * possible reasons of incompatibility.</p>
- *
- * @param surface a non-{@code null} {@link Surface} object reference
- * @return {@code true} if this is supported, {@code false} otherwise
- *
- * @throws NullPointerException if {@code surface} was {@code null}
- *
- * @see CameraDevice#configureOutputs
- * @see #isOutputSupportedFor(Class)
- */
- public boolean isOutputSupportedFor(final Surface surface) {
- checkNotNull(surface, "surface must not be null");
-
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get a list of sizes compatible with {@code klass} to use as an output.
- *
- * <p>Since some of the supported classes may support additional formats beyond
- * an opaque/implementation-defined (under-the-hood) format; this function only returns
- * sizes for the implementation-defined format.</p>
- *
- * <p>Some classes such as {@link android.media.ImageReader} may only support user-defined
- * formats; in particular {@link #isOutputSupportedFor(Class)} will return {@code true} for
- * that class and this method will return an empty array (but not {@code null}).</p>
- *
- * <p>If a well-defined format such as {@code NV21} is required, use
- * {@link #getOutputSizes(int)} instead.</p>
- *
- * <p>The {@code klass} should be a supported output, that querying
- * {@code #isOutputSupportedFor(Class)} should return {@code true}.</p>
- *
- * @param klass
- * a non-{@code null} {@link Class} object reference
- * @return
- * an array of supported sizes for implementation-defined formats,
- * or {@code null} iff the {@code klass} is not a supported output
- *
- * @throws NullPointerException if {@code klass} was {@code null}
- *
- * @see #isOutputSupportedFor(Class)
- */
- public <T> Size[] getOutputSizes(final Class<T> klass) {
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get a list of sizes compatible with the requested image {@code format}.
- *
- * <p>The {@code format} should be a supported format (one of the formats returned by
- * {@link #getOutputFormats}).</p>
- *
- * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
- * @return
- * an array of supported sizes,
- * or {@code null} if the {@code format} is not a supported output
- *
- * @see ImageFormat
- * @see PixelFormat
- * @see #getOutputFormats
- */
- public Size[] getOutputSizes(final int format) {
- try {
- checkArgumentFormatSupported(format, /*output*/true);
- } catch (IllegalArgumentException e) {
- return null;
- }
-
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
- * for the format/size combination (in nanoseconds).
- *
- * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p>
- * <p>{@code size} should be one of the ones returned by
- * {@link #getOutputSizes(int)}.</p>
- *
- * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
- * @param size an output-compatible size
- * @return a minimum frame duration {@code >=} 0 in nanoseconds
- *
- * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
- * @throws NullPointerException if {@code size} was {@code null}
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
- * @see CaptureRequest#SENSOR_FRAME_DURATION
- * @see ImageFormat
- * @see PixelFormat
- */
- public long getOutputMinFrameDuration(final int format, final Size size) {
- checkArgumentFormatSupported(format, /*output*/true);
-
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
- * for the class/size combination (in nanoseconds).
- *
- * <p>This assumes a the {@code klass} is set up to use an implementation-defined format.
- * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
- *
- * <p>{@code klass} should be one of the ones which is supported by
- * {@link #isOutputSupportedFor(Class)}.</p>
- *
- * <p>{@code size} should be one of the ones returned by
- * {@link #getOutputSizes(int)}.</p>
- *
- * @param klass
- * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a
- * non-empty array returned by {@link #getOutputSizes(Class)}
- * @param size an output-compatible size
- * @return a minimum frame duration {@code >=} 0 in nanoseconds
- *
- * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
- * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
- * @see CaptureRequest#SENSOR_FRAME_DURATION
- * @see ImageFormat
- * @see PixelFormat
- */
- public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) {
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get the {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS stall duration}
- * for the format/size combination (in nanoseconds).
- *
- * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p>
- * <p>{@code size} should be one of the ones returned by
- * {@link #getOutputSizes(int)}.</p>
- *
- * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
- * @param size an output-compatible size
- * @return a stall duration {@code >=} 0 in nanoseconds
- *
- * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
- * @throws NullPointerException if {@code size} was {@code null}
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
- * @see ImageFormat
- * @see PixelFormat
- */
- public long getOutputStallDuration(final int format, final Size size) {
- checkArgumentFormatSupported(format, /*output*/true);
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Get the {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS stall duration}
- * for the class/size combination (in nanoseconds).
- *
- * <p>This assumes a the {@code klass} is set up to use an implementation-defined format.
- * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
- *
- * <p>{@code klass} should be one of the ones with a non-empty array returned by
- * {@link #getOutputSizes(Class)}.</p>
- *
- * <p>{@code size} should be one of the ones returned by
- * {@link #getOutputSizes(Class)}.</p>
- *
- * @param klass
- * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a
- * non-empty array returned by {@link #getOutputSizes(Class)}
- * @param size an output-compatible size
- * @return a minimum frame duration {@code >=} 0 in nanoseconds
- *
- * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
- * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
- *
- * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
- * @see CaptureRequest#SENSOR_FRAME_DURATION
- * @see ImageFormat
- * @see PixelFormat
- */
- public <T> long getOutputStallDuration(final Class<T> klass, final Size size) {
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- /**
- * Check if this {@link StreamConfigurationMap} is equal to another
- * {@link StreamConfigurationMap}.
- *
- * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
- *
- * @return {@code true} if the objects were equal, {@code false} otherwise
- */
- @Override
- public boolean equals(final Object obj) {
- if (obj == null) {
- return false;
- }
- if (this == obj) {
- return true;
- }
- if (obj instanceof StreamConfigurationMap) {
- final StreamConfigurationMap other = (StreamConfigurationMap) obj;
- // TODO: do we care about order?
- return Arrays.equals(mConfigurations, other.mConfigurations) &&
- Arrays.equals(mDurations, other.mDurations);
- }
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- // TODO: do we care about order?
- return HashCodeHelpers.hashCode(mConfigurations) ^ HashCodeHelpers.hashCode(mDurations);
- }
-
- // Check that the argument is supported by #getOutputFormats or #getInputFormats
- private int checkArgumentFormatSupported(int format, boolean output) {
- checkArgumentFormat(format);
-
- int[] formats = output ? getOutputFormats() : getInputFormats();
- for (int i = 0; i < formats.length; ++i) {
- if (format == formats[i]) {
- return format;
- }
- }
-
- throw new IllegalArgumentException(String.format(
- "format %x is not supported by this stream configuration map", format));
- }
-
- /**
- * Ensures that the format is either user-defined or implementation defined.
- *
- * <p>Any invalid/undefined formats will raise an exception.</p>
- *
- * @param format image format
- * @return the format
- *
- * @throws IllegalArgumentException if the format was invalid
- */
- static int checkArgumentFormatInternal(int format) {
- if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
- return format;
- }
-
- return checkArgumentFormat(format);
- }
-
- /**
- * Ensures that the format is user-defined in either ImageFormat or PixelFormat.
- *
- * <p>Any invalid/undefined formats will raise an exception, including implementation-defined.
- * </p>
- *
- * <p>Note that {@code @hide} and deprecated formats will not pass this check.</p>
- *
- * @param format image format
- * @return the format
- *
- * @throws IllegalArgumentException if the format was not user-defined
- */
- static int checkArgumentFormat(int format) {
- if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
- throw new IllegalArgumentException(String.format(
- "format %x was not defined in either ImageFormat or PixelFormat", format));
- }
-
- return format;
- }
-
- private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
-
- private final StreamConfiguration[] mConfigurations;
- private final StreamConfigurationDuration[] mDurations;
-
-}
diff --git a/core/java/android/hardware/camera2/TonemapCurve.java b/core/java/android/hardware/camera2/TonemapCurve.java
index ee20d68..2958ebf 100644
--- a/core/java/android/hardware/camera2/TonemapCurve.java
+++ b/core/java/android/hardware/camera2/TonemapCurve.java
@@ -19,7 +19,7 @@
import static com.android.internal.util.Preconditions.*;
import android.graphics.PointF;
-import android.hardware.camera2.impl.HashCodeHelpers;
+import android.hardware.camera2.utils.HashCodeHelpers;
import java.util.Arrays;
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index 988f8f9..628d1c3 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -24,9 +24,9 @@
import android.hardware.camera2.CaptureResultExtras;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
-import android.hardware.camera2.LongParcelable;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.hardware.camera2.utils.CameraRuntimeException;
+import android.hardware.camera2.utils.LongParcelable;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index c5e5753..d28f7bd 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -23,16 +23,36 @@
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.Face;
-import android.hardware.camera2.Rational;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.marshal.MarshalRegistry;
+import android.hardware.camera2.marshal.impl.MarshalQueryableArray;
+import android.hardware.camera2.marshal.impl.MarshalQueryableBoolean;
+import android.hardware.camera2.marshal.impl.MarshalQueryableColorSpaceTransform;
+import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
+import android.hardware.camera2.marshal.impl.MarshalQueryableMeteringRectangle;
+import android.hardware.camera2.marshal.impl.MarshalQueryableNativeByteToInteger;
+import android.hardware.camera2.marshal.impl.MarshalQueryableParcelable;
+import android.hardware.camera2.marshal.impl.MarshalQueryablePrimitive;
+import android.hardware.camera2.marshal.impl.MarshalQueryableRange;
+import android.hardware.camera2.marshal.impl.MarshalQueryableRect;
+import android.hardware.camera2.marshal.impl.MarshalQueryableReprocessFormatsMap;
+import android.hardware.camera2.marshal.impl.MarshalQueryableRggbChannelVector;
+import android.hardware.camera2.marshal.impl.MarshalQueryableSize;
+import android.hardware.camera2.marshal.impl.MarshalQueryableSizeF;
+import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration;
+import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
+import android.hardware.camera2.marshal.impl.MarshalQueryableString;
+import android.hardware.camera2.params.StreamConfiguration;
+import android.hardware.camera2.params.StreamConfigurationDuration;
+import android.hardware.camera2.params.StreamConfigurationMap;
import android.os.Parcelable;
import android.os.Parcel;
import android.util.Log;
-import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
-import java.util.HashMap;
/**
* Implementation of camera metadata marshal/unmarshal across Binder to
@@ -89,7 +109,6 @@
nativeWriteToParcel(dest);
}
- @SuppressWarnings("unchecked")
@Override
public <T> T get(Key<T> key) {
T value = getOverride(key);
@@ -169,275 +188,6 @@
mMetadataPtr = 0; // set it to 0 again to prevent eclipse from making this field final
}
- private static int getTypeSize(int nativeType) {
- switch(nativeType) {
- case TYPE_BYTE:
- return 1;
- case TYPE_INT32:
- case TYPE_FLOAT:
- return 4;
- case TYPE_INT64:
- case TYPE_DOUBLE:
- case TYPE_RATIONAL:
- return 8;
- }
-
- throw new UnsupportedOperationException("Unknown type, can't get size "
- + nativeType);
- }
-
- private static Class<?> getExpectedType(int nativeType) {
- switch(nativeType) {
- case TYPE_BYTE:
- return Byte.TYPE;
- case TYPE_INT32:
- return Integer.TYPE;
- case TYPE_FLOAT:
- return Float.TYPE;
- case TYPE_INT64:
- return Long.TYPE;
- case TYPE_DOUBLE:
- return Double.TYPE;
- case TYPE_RATIONAL:
- return Rational.class;
- }
-
- throw new UnsupportedOperationException("Unknown type, can't map to Java type "
- + nativeType);
- }
-
- @SuppressWarnings("unchecked")
- private static <T> int packSingleNative(T value, ByteBuffer buffer, Class<T> type,
- int nativeType, boolean sizeOnly) {
-
- if (!sizeOnly) {
- /**
- * Rewrite types when the native type doesn't match the managed type
- * - Boolean -> Byte
- * - Integer -> Byte
- */
-
- if (nativeType == TYPE_BYTE && type == Boolean.TYPE) {
- // Since a boolean can't be cast to byte, and we don't want to use putBoolean
- boolean asBool = (Boolean) value;
- byte asByte = (byte) (asBool ? 1 : 0);
- value = (T) (Byte) asByte;
- } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) {
- int asInt = (Integer) value;
- byte asByte = (byte) asInt;
- value = (T) (Byte) asByte;
- } else if (type != getExpectedType(nativeType)) {
- throw new UnsupportedOperationException("Tried to pack a type of " + type +
- " but we expected the type to be " + getExpectedType(nativeType));
- }
-
- if (nativeType == TYPE_BYTE) {
- buffer.put((Byte) value);
- } else if (nativeType == TYPE_INT32) {
- buffer.putInt((Integer) value);
- } else if (nativeType == TYPE_FLOAT) {
- buffer.putFloat((Float) value);
- } else if (nativeType == TYPE_INT64) {
- buffer.putLong((Long) value);
- } else if (nativeType == TYPE_DOUBLE) {
- buffer.putDouble((Double) value);
- } else if (nativeType == TYPE_RATIONAL) {
- Rational r = (Rational) value;
- buffer.putInt(r.getNumerator());
- buffer.putInt(r.getDenominator());
- }
-
- }
-
- return getTypeSize(nativeType);
- }
-
- @SuppressWarnings({"unchecked", "rawtypes"})
- private static <T> int packSingle(T value, ByteBuffer buffer, Class<T> type, int nativeType,
- boolean sizeOnly) {
-
- int size = 0;
-
- if (type.isPrimitive() || type == Rational.class) {
- size = packSingleNative(value, buffer, type, nativeType, sizeOnly);
- } else if (type.isEnum()) {
- size = packEnum((Enum)value, buffer, (Class<Enum>)type, nativeType, sizeOnly);
- } else if (type.isArray()) {
- size = packArray(value, buffer, type, nativeType, sizeOnly);
- } else {
- size = packClass(value, buffer, type, nativeType, sizeOnly);
- }
-
- return size;
- }
-
- private static <T extends Enum<T>> int packEnum(T value, ByteBuffer buffer, Class<T> type,
- int nativeType, boolean sizeOnly) {
-
- // TODO: add support for enums with their own values.
- return packSingleNative(getEnumValue(value), buffer, Integer.TYPE, nativeType, sizeOnly);
- }
-
- @SuppressWarnings("unchecked")
- private static <T> int packClass(T value, ByteBuffer buffer, Class<T> type, int nativeType,
- boolean sizeOnly) {
-
- MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
- if (marshaler == null) {
- throw new IllegalArgumentException(String.format("Unknown Key type: %s", type));
- }
-
- return marshaler.marshal(value, buffer, nativeType, sizeOnly);
- }
-
- private static <T> int packArray(T value, ByteBuffer buffer, Class<T> type, int nativeType,
- boolean sizeOnly) {
-
- int size = 0;
- int arrayLength = Array.getLength(value);
-
- @SuppressWarnings("unchecked")
- Class<Object> componentType = (Class<Object>)type.getComponentType();
-
- for (int i = 0; i < arrayLength; ++i) {
- size += packSingle(Array.get(value, i), buffer, componentType, nativeType, sizeOnly);
- }
-
- return size;
- }
-
- @SuppressWarnings("unchecked")
- private static <T> T unpackSingleNative(ByteBuffer buffer, Class<T> type, int nativeType) {
-
- T val;
-
- if (nativeType == TYPE_BYTE) {
- val = (T) (Byte) buffer.get();
- } else if (nativeType == TYPE_INT32) {
- val = (T) (Integer) buffer.getInt();
- } else if (nativeType == TYPE_FLOAT) {
- val = (T) (Float) buffer.getFloat();
- } else if (nativeType == TYPE_INT64) {
- val = (T) (Long) buffer.getLong();
- } else if (nativeType == TYPE_DOUBLE) {
- val = (T) (Double) buffer.getDouble();
- } else if (nativeType == TYPE_RATIONAL) {
- val = (T) new Rational(buffer.getInt(), buffer.getInt());
- } else {
- throw new UnsupportedOperationException("Unknown type, can't unpack a native type "
- + nativeType);
- }
-
- /**
- * Rewrite types when the native type doesn't match the managed type
- * - Byte -> Boolean
- * - Byte -> Integer
- */
-
- if (nativeType == TYPE_BYTE && type == Boolean.TYPE) {
- // Since a boolean can't be cast to byte, and we don't want to use getBoolean
- byte asByte = (Byte) val;
- boolean asBool = asByte != 0;
- val = (T) (Boolean) asBool;
- } else if (nativeType == TYPE_BYTE && type == Integer.TYPE) {
- byte asByte = (Byte) val;
- int asInt = asByte;
- val = (T) (Integer) asInt;
- } else if (type != getExpectedType(nativeType)) {
- throw new UnsupportedOperationException("Tried to unpack a type of " + type +
- " but we expected the type to be " + getExpectedType(nativeType));
- }
-
- return val;
- }
-
- @SuppressWarnings({"unchecked", "rawtypes"})
- private static <T> T unpackSingle(ByteBuffer buffer, Class<T> type, int nativeType) {
-
- if (type.isPrimitive() || type == Rational.class) {
- return unpackSingleNative(buffer, type, nativeType);
- }
-
- if (type.isEnum()) {
- return (T) unpackEnum(buffer, (Class<Enum>)type, nativeType);
- }
-
- if (type.isArray()) {
- return unpackArray(buffer, type, nativeType);
- }
-
- T instance = unpackClass(buffer, type, nativeType);
-
- return instance;
- }
-
- private static <T extends Enum<T>> T unpackEnum(ByteBuffer buffer, Class<T> type,
- int nativeType) {
- int ordinal = unpackSingleNative(buffer, Integer.TYPE, nativeType);
- return getEnumFromValue(type, ordinal);
- }
-
- private static <T> T unpackClass(ByteBuffer buffer, Class<T> type, int nativeType) {
-
- MetadataMarshalClass<T> marshaler = getMarshaler(type, nativeType);
- if (marshaler == null) {
- throw new IllegalArgumentException("Unknown class type: " + type);
- }
-
- return marshaler.unmarshal(buffer, nativeType);
- }
-
- @SuppressWarnings("unchecked")
- private static <T> T unpackArray(ByteBuffer buffer, Class<T> type, int nativeType) {
-
- Class<?> componentType = type.getComponentType();
- Object array;
-
- int elementSize = getTypeSize(nativeType);
-
- MetadataMarshalClass<?> marshaler = getMarshaler(componentType, nativeType);
- if (marshaler != null) {
- elementSize = marshaler.getNativeSize(nativeType);
- }
-
- if (elementSize != MetadataMarshalClass.NATIVE_SIZE_DYNAMIC) {
- int remaining = buffer.remaining();
- int arraySize = remaining / elementSize;
-
- if (VERBOSE) {
- Log.v(TAG,
- String.format(
- "Attempting to unpack array (count = %d, element size = %d, bytes " +
- "remaining = %d) for type %s",
- arraySize, elementSize, remaining, type));
- }
-
- array = Array.newInstance(componentType, arraySize);
- for (int i = 0; i < arraySize; ++i) {
- Object elem = unpackSingle(buffer, componentType, nativeType);
- Array.set(array, i, elem);
- }
- } else {
- // Dynamic size, use an array list.
- ArrayList<Object> arrayList = new ArrayList<Object>();
-
- int primitiveSize = getTypeSize(nativeType);
- while (buffer.remaining() >= primitiveSize) {
- Object elem = unpackSingle(buffer, componentType, nativeType);
- arrayList.add(elem);
- }
-
- array = arrayList.toArray((T[]) Array.newInstance(componentType, 0));
- }
-
- if (buffer.remaining() != 0) {
- Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking "
- + type);
- }
-
- return (T) array;
- }
-
private <T> T getBase(Key<T> key) {
int tag = key.getTag();
byte[] values = readValues(tag);
@@ -445,10 +195,9 @@
return null;
}
- int nativeType = getNativeType(tag);
-
+ Marshaler<T> marshaler = getMarshalerForKey(key);
ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
- return unpackSingle(buffer, key.getType(), nativeType);
+ return marshaler.unmarshal(buffer);
}
// Need overwrite some metadata that has different definitions between native
@@ -461,10 +210,8 @@
return (T) getFaces();
} else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) {
return (T) getFaceRectangles();
- } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS)) {
- return (T) getAvailableStreamConfigurations();
- } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS)) {
- return (T) getAvailableMinFrameDurations();
+ } else if (key.equals(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)) {
+ return (T) getStreamConfigurationMap();
}
// For other keys, get() falls back to getBase()
@@ -485,50 +232,6 @@
return availableFormats;
}
- private int[] getAvailableStreamConfigurations() {
- final int NUM_ELEMENTS_IN_CONFIG = 4;
- int[] availableConfigs =
- getBase(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
- if (availableConfigs != null) {
- if (availableConfigs.length % NUM_ELEMENTS_IN_CONFIG != 0) {
- Log.w(TAG, "availableStreamConfigurations is malformed, length must be multiple"
- + " of " + NUM_ELEMENTS_IN_CONFIG);
- return availableConfigs;
- }
-
- for (int i = 0; i < availableConfigs.length; i += NUM_ELEMENTS_IN_CONFIG) {
- // JPEG has different value between native and managed side, need override.
- if (availableConfigs[i] == NATIVE_JPEG_FORMAT) {
- availableConfigs[i] = ImageFormat.JPEG;
- }
- }
- }
-
- return availableConfigs;
- }
-
- private long[] getAvailableMinFrameDurations() {
- final int NUM_ELEMENTS_IN_DURATION = 4;
- long[] availableMinDurations =
- getBase(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
- if (availableMinDurations != null) {
- if (availableMinDurations.length % NUM_ELEMENTS_IN_DURATION != 0) {
- Log.w(TAG, "availableStreamConfigurations is malformed, length must be multiple"
- + " of " + NUM_ELEMENTS_IN_DURATION);
- return availableMinDurations;
- }
-
- for (int i = 0; i < availableMinDurations.length; i += NUM_ELEMENTS_IN_DURATION) {
- // JPEG has different value between native and managed side, need override.
- if (availableMinDurations[i] == NATIVE_JPEG_FORMAT) {
- availableMinDurations[i] = ImageFormat.JPEG;
- }
- }
- }
-
- return availableMinDurations;
- }
-
private Face[] getFaces() {
final int FACE_LANDMARK_SIZE = 6;
@@ -628,23 +331,34 @@
return fixedFaceRectangles;
}
+ private StreamConfigurationMap getStreamConfigurationMap() {
+ StreamConfiguration[] configurations = getBase(
+ CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ StreamConfigurationDuration[] minFrameDurations = getBase(
+ CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
+ StreamConfigurationDuration[] stallDurations = getBase(
+ CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS);
+
+ return new StreamConfigurationMap(configurations, minFrameDurations, stallDurations);
+ }
+
private <T> void setBase(Key<T> key, T value) {
int tag = key.getTag();
if (value == null) {
- writeValues(tag, null);
+ // Erase the entry
+ writeValues(tag, /*src*/null);
return;
- }
+ } // else update the entry to a new value
- int nativeType = getNativeType(tag);
-
- int size = packSingle(value, null, key.getType(), nativeType, /* sizeOnly */true);
+ Marshaler<T> marshaler = getMarshalerForKey(key);
+ int size = marshaler.calculateMarshalSize(value);
// TODO: Optimization. Cache the byte[] and reuse if the size is big enough.
byte[] values = new byte[size];
ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder());
- packSingle(value, buffer, key.getType(), nativeType, /*sizeOnly*/false);
+ marshaler.marshal(value, buffer);
writeValues(tag, values);
}
@@ -655,56 +369,12 @@
return setAvailableFormats((int[]) value);
} else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) {
return setFaceRectangles((Rect[]) value);
- } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS)) {
- return setAvailableStreamConfigurations((int[])value);
- } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS)) {
- return setAvailableMinFrameDurations((long[])value);
}
// For other keys, set() falls back to setBase().
return false;
}
- private boolean setAvailableStreamConfigurations(int[] value) {
- final int NUM_ELEMENTS_IN_CONFIG = 4;
- int[] availableConfigs = value;
- if (value == null) {
- // Let setBase() to handle the null value case.
- return false;
- }
-
- int[] newValues = new int[availableConfigs.length];
- for (int i = 0; i < availableConfigs.length; i++) {
- newValues[i] = availableConfigs[i];
- if (i % NUM_ELEMENTS_IN_CONFIG == 0 && availableConfigs[i] == ImageFormat.JPEG) {
- newValues[i] = NATIVE_JPEG_FORMAT;
- }
- }
-
- setBase(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS, newValues);
- return true;
- }
-
- private boolean setAvailableMinFrameDurations(long[] value) {
- final int NUM_ELEMENTS_IN_DURATION = 4;
- long[] availableDurations = value;
- if (value == null) {
- // Let setBase() to handle the null value case.
- return false;
- }
-
- long[] newValues = new long[availableDurations.length];
- for (int i = 0; i < availableDurations.length; i++) {
- newValues[i] = availableDurations[i];
- if (i % NUM_ELEMENTS_IN_DURATION == 0 && availableDurations[i] == ImageFormat.JPEG) {
- newValues[i] = NATIVE_JPEG_FORMAT;
- }
- }
-
- setBase(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS, newValues);
- return true;
- }
-
private boolean setAvailableFormats(int[] value) {
int[] availableFormat = value;
if (value == null) {
@@ -870,125 +540,64 @@
}
}
- private static final HashMap<Class<? extends Enum>, int[]> sEnumValues =
- new HashMap<Class<? extends Enum>, int[]>();
/**
- * Register a non-sequential set of values to be used with the pack/unpack functions.
- * This enables get/set to correctly marshal the enum into a value that is C-compatible.
+ * Get the marshaler compatible with the {@code key} and type {@code T}.
*
- * @param enumType The class for an enum
- * @param values A list of values mapping to the ordinals of the enum
- *
- * @hide
+ * @throws UnsupportedOperationException
+ * if the native/managed type combination for {@code key} is not supported
*/
- public static <T extends Enum<T>> void registerEnumValues(Class<T> enumType, int[] values) {
- if (enumType.getEnumConstants().length != values.length) {
- throw new IllegalArgumentException(
- "Expected values array to be the same size as the enumTypes values "
- + values.length + " for type " + enumType);
- }
- if (VERBOSE) {
- Log.v(TAG, "Registered enum values for type " + enumType + " values");
- }
-
- sEnumValues.put(enumType, values);
+ private static <T> Marshaler<T> getMarshalerForKey(Key<T> key) {
+ return MarshalRegistry.getMarshaler(key.getTypeReference(),
+ getNativeType(key.getTag()));
}
- /**
- * Get the numeric value from an enum. This is usually the same as the ordinal value for
- * enums that have fully sequential values, although for C-style enums the range of values
- * may not map 1:1.
- *
- * @param enumValue Enum instance
- * @return Int guaranteed to be ABI-compatible with the C enum equivalent
- */
- private static <T extends Enum<T>> int getEnumValue(T enumValue) {
- int[] values;
- values = sEnumValues.get(enumValue.getClass());
-
- int ordinal = enumValue.ordinal();
- if (values != null) {
- return values[ordinal];
- }
-
- return ordinal;
- }
-
- /**
- * Finds the enum corresponding to it's numeric value. Opposite of {@link #getEnumValue} method.
- *
- * @param enumType Class of the enum we want to find
- * @param value The numeric value of the enum
- * @return An instance of the enum
- */
- private static <T extends Enum<T>> T getEnumFromValue(Class<T> enumType, int value) {
- int ordinal;
-
- int[] registeredValues = sEnumValues.get(enumType);
- if (registeredValues != null) {
- ordinal = -1;
-
- for (int i = 0; i < registeredValues.length; ++i) {
- if (registeredValues[i] == value) {
- ordinal = i;
- break;
- }
- }
- } else {
- ordinal = value;
- }
-
- T[] values = enumType.getEnumConstants();
-
- if (ordinal < 0 || ordinal >= values.length) {
- throw new IllegalArgumentException(
- String.format(
- "Argument 'value' (%d) was not a valid enum value for type %s "
- + "(registered? %b)",
- value,
- enumType, (registeredValues != null)));
- }
-
- return values[ordinal];
- }
-
- static HashMap<Class<?>, MetadataMarshalClass<?>> sMarshalerMap = new
- HashMap<Class<?>, MetadataMarshalClass<?>>();
-
- private static <T> void registerMarshaler(MetadataMarshalClass<T> marshaler) {
- sMarshalerMap.put(marshaler.getMarshalingClass(), marshaler);
- }
-
- @SuppressWarnings("unchecked")
- private static <T> MetadataMarshalClass<T> getMarshaler(Class<T> type, int nativeType) {
- MetadataMarshalClass<T> marshaler = (MetadataMarshalClass<T>) sMarshalerMap.get(type);
-
- if (marshaler != null && !marshaler.isNativeTypeSupported(nativeType)) {
- throw new UnsupportedOperationException("Unsupported type " + nativeType +
- " to be marshalled to/from a " + type);
- }
-
- return marshaler;
- }
-
- /**
- * We use a class initializer to allow the native code to cache some field offsets
- */
- static {
- nativeClassInit();
-
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private static void registerAllMarshalers() {
if (VERBOSE) {
Log.v(TAG, "Shall register metadata marshalers");
}
- // load built-in marshallers
- registerMarshaler(new MetadataMarshalRect());
- registerMarshaler(new MetadataMarshalSize());
- registerMarshaler(new MetadataMarshalString());
+ MarshalQueryable[] queryList = new MarshalQueryable[] {
+ // marshalers for standard types
+ new MarshalQueryablePrimitive(),
+ new MarshalQueryableEnum(),
+ new MarshalQueryableArray(),
+ // pseudo standard types, that expand/narrow the native type into a managed type
+ new MarshalQueryableBoolean(),
+ new MarshalQueryableNativeByteToInteger(),
+
+ // marshalers for custom types
+ new MarshalQueryableRect(),
+ new MarshalQueryableSize(),
+ new MarshalQueryableSizeF(),
+ new MarshalQueryableString(),
+ new MarshalQueryableReprocessFormatsMap(),
+ new MarshalQueryableRange(),
+ new MarshalQueryableMeteringRectangle(),
+ new MarshalQueryableColorSpaceTransform(),
+ new MarshalQueryableStreamConfiguration(),
+ new MarshalQueryableStreamConfigurationDuration(),
+ new MarshalQueryableRggbChannelVector(),
+
+ // generic parcelable marshaler (MUST BE LAST since it has lowest priority)
+ new MarshalQueryableParcelable(),
+ };
+
+ for (MarshalQueryable query : queryList) {
+ MarshalRegistry.registerMarshalQueryable(query);
+ }
if (VERBOSE) {
Log.v(TAG, "Registered metadata marshalers");
}
}
+ static {
+ /*
+ * We use a class initializer to allow the native code to cache some field offsets
+ */
+ nativeClassInit();
+ registerAllMarshalers();
+ }
+
}
diff --git a/core/java/android/hardware/camera2/impl/HashCodeHelpers.java b/core/java/android/hardware/camera2/impl/HashCodeHelpers.java
deleted file mode 100644
index 2d63827..0000000
--- a/core/java/android/hardware/camera2/impl/HashCodeHelpers.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.impl;
-
-/**
- * Provide hashing functions using the Modified Bernstein hash
- */
-public final class HashCodeHelpers {
-
- /**
- * Hash every element uniformly using the Modified Bernstein hash.
- *
- * <p>Useful to implement a {@link Object#hashCode} for uniformly distributed data.</p>
- *
- * @param array a non-{@code null} array of integers
- *
- * @return the numeric hash code
- */
- public static int hashCode(int[] array) {
- if (array == null) {
- return 0;
- }
-
- /*
- * Note that we use 31 here instead of 33 since it's preferred in Effective Java
- * and used elsewhere in the runtime (e.g. Arrays#hashCode)
- *
- * That being said 33 and 31 are nearly identical in terms of their usefulness
- * according to http://svn.apache.org/repos/asf/apr/apr/trunk/tables/apr_hash.c
- */
- int h = 1;
- for (int x : array) {
- // Strength reduction; in case the compiler has illusions about divisions being faster
- h = ((h << 5) - h) ^ x; // (h * 31) XOR x
- }
-
- return h;
- }
-
- /**
- * Hash every element uniformly using the Modified Bernstein hash.
- *
- * <p>Useful to implement a {@link Object#hashCode} for uniformly distributed data.</p>
- *
- * @param array a non-{@code null} array of floats
- *
- * @return the numeric hash code
- */
- public static int hashCode(float[] array) {
- if (array == null) {
- return 0;
- }
-
- int h = 1;
- for (float f : array) {
- int x = Float.floatToIntBits(f);
- h = ((h << 5) - h) ^ x; // (h * 31) XOR x
- }
-
- return h;
- }
-
- /**
- * Hash every element uniformly using the Modified Bernstein hash.
- *
- * <p>Useful to implement a {@link Object#hashCode} for uniformly distributed data.</p>
- *
- * @param array a non-{@code null} array of objects
- *
- * @return the numeric hash code
- */
- public static <T> int hashCode(T[] array) {
- if (array == null) {
- return 0;
- }
-
- int h = 1;
- for (T o : array) {
- int x = (o == null) ? 0 : o.hashCode();
- h = ((h << 5) - h) ^ x; // (h * 31) XOR x
- }
-
- return h;
- }
-
- public static <T> int hashCode(T a) {
- return (a == null) ? 0 : a.hashCode();
- }
-
- public static <T> int hashCode(T a, T b) {
- int h = hashCode(a);
-
- int x = (b == null) ? 0 : b.hashCode();
- h = ((h << 5) - h) ^ x; // (h * 31) XOR x
-
- return h;
- }
-
- public static <T> int hashCode(T a, T b, T c) {
- int h = hashCode(a, b);
-
- int x = (a == null) ? 0 : a.hashCode();
- h = ((h << 5) - h) ^ x; // (h * 31) XOR x
-
- return h;
- }
-
- public static int hashCode(int x) {
- return hashCode(new int[] { x } );
- }
-
- public static int hashCode(int x, int y) {
- return hashCode(new int[] { x, y } );
- }
-
- public static int hashCode(int x, int y, int z) {
- return hashCode(new int[] { x, y, z } );
- }
-
- public static int hashCode(int x, int y, int z, int w) {
- return hashCode(new int[] { x, y, z, w } );
- }
-
- public static int hashCode(int x, int y, int z, int w, int t) {
- return hashCode(new int[] { x, y, z, w, t } );
- }
-
-
-}
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java b/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java
deleted file mode 100644
index 6d224ef..0000000
--- a/core/java/android/hardware/camera2/impl/MetadataMarshalClass.java
+++ /dev/null
@@ -1,67 +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 android.hardware.camera2.impl;
-
-import java.nio.ByteBuffer;
-
-public interface MetadataMarshalClass<T> {
-
- /**
- * Marshal the specified object instance (value) into a byte buffer.
- *
- * @param value the value of type T that we wish to write into the byte buffer
- * @param buffer the byte buffer into which the marshalled object will be written
- * @param nativeType the native type, e.g.
- * {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
- * Guaranteed to be one for which isNativeTypeSupported returns true.
- * @param sizeOnly if this is true, don't write to the byte buffer. calculate the size only.
- * @return the size that needs to be written to the byte buffer
- */
- int marshal(T value, ByteBuffer buffer, int nativeType, boolean sizeOnly);
-
- /**
- * Unmarshal a new object instance from the byte buffer.
- * @param buffer the byte buffer, from which we will read the object
- * @param nativeType the native type, e.g.
- * {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
- * Guaranteed to be one for which isNativeTypeSupported returns true.
- * @return a new instance of type T read from the byte buffer
- */
- T unmarshal(ByteBuffer buffer, int nativeType);
-
- Class<T> getMarshalingClass();
-
- /**
- * Determines whether or not this marshaller supports this native type. Most marshallers
- * will are likely to only support one type.
- *
- * @param nativeType the native type, e.g.
- * {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
- * @return true if it supports, false otherwise
- */
- boolean isNativeTypeSupported(int nativeType);
-
- public static int NATIVE_SIZE_DYNAMIC = -1;
-
- /**
- * How many bytes T will take up if marshalled to/from nativeType
- * @param nativeType the native type, e.g.
- * {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
- * @return a size in bytes, or NATIVE_SIZE_DYNAMIC if the size is dynamic
- */
- int getNativeSize(int nativeType);
-}
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java b/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java
deleted file mode 100644
index ab72c4f..0000000
--- a/core/java/android/hardware/camera2/impl/MetadataMarshalRect.java
+++ /dev/null
@@ -1,67 +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 android.hardware.camera2.impl;
-
-import android.graphics.Rect;
-
-import java.nio.ByteBuffer;
-
-public class MetadataMarshalRect implements MetadataMarshalClass<Rect> {
- private static final int SIZE = 16;
-
- @Override
- public int marshal(Rect value, ByteBuffer buffer, int nativeType, boolean sizeOnly) {
- if (sizeOnly) {
- return SIZE;
- }
-
- buffer.putInt(value.left);
- buffer.putInt(value.top);
- buffer.putInt(value.width());
- buffer.putInt(value.height());
-
- return SIZE;
- }
-
- @Override
- public Rect unmarshal(ByteBuffer buffer, int nativeType) {
-
- int left = buffer.getInt();
- int top = buffer.getInt();
- int width = buffer.getInt();
- int height = buffer.getInt();
-
- int right = left + width;
- int bottom = top + height;
-
- return new Rect(left, top, right, bottom);
- }
-
- @Override
- public Class<Rect> getMarshalingClass() {
- return Rect.class;
- }
-
- @Override
- public boolean isNativeTypeSupported(int nativeType) {
- return nativeType == CameraMetadataNative.TYPE_INT32;
- }
-
- @Override
- public int getNativeSize(int nativeType) {
- return SIZE;
- }
-}
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java b/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java
deleted file mode 100644
index e8143e0..0000000
--- a/core/java/android/hardware/camera2/impl/MetadataMarshalSize.java
+++ /dev/null
@@ -1,60 +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 android.hardware.camera2.impl;
-
-import android.hardware.camera2.Size;
-
-import java.nio.ByteBuffer;
-
-public class MetadataMarshalSize implements MetadataMarshalClass<Size> {
-
- private static final int SIZE = 8;
-
- @Override
- public int marshal(Size value, ByteBuffer buffer, int nativeType, boolean sizeOnly) {
- if (sizeOnly) {
- return SIZE;
- }
-
- buffer.putInt(value.getWidth());
- buffer.putInt(value.getHeight());
-
- return SIZE;
- }
-
- @Override
- public Size unmarshal(ByteBuffer buffer, int nativeType) {
- int width = buffer.getInt();
- int height = buffer.getInt();
-
- return new Size(width, height);
- }
-
- @Override
- public Class<Size> getMarshalingClass() {
- return Size.class;
- }
-
- @Override
- public boolean isNativeTypeSupported(int nativeType) {
- return nativeType == CameraMetadataNative.TYPE_INT32;
- }
-
- @Override
- public int getNativeSize(int nativeType) {
- return SIZE;
- }
-}
diff --git a/core/java/android/hardware/camera2/impl/MetadataMarshalString.java b/core/java/android/hardware/camera2/impl/MetadataMarshalString.java
deleted file mode 100644
index b61b8d3..0000000
--- a/core/java/android/hardware/camera2/impl/MetadataMarshalString.java
+++ /dev/null
@@ -1,79 +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 android.hardware.camera2.impl;
-
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-
-public class MetadataMarshalString implements MetadataMarshalClass<String> {
-
- private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
-
- @Override
- public int marshal(String value, ByteBuffer buffer, int nativeType, boolean sizeOnly) {
- byte[] arr = value.getBytes(UTF8_CHARSET);
-
- if (!sizeOnly) {
- buffer.put(arr);
- buffer.put((byte)0); // metadata strings are NULL-terminated
- }
-
- return arr.length + 1;
- }
-
- @Override
- public String unmarshal(ByteBuffer buffer, int nativeType) {
-
- buffer.mark(); // save the current position
-
- boolean foundNull = false;
- int stringLength = 0;
- while (buffer.hasRemaining()) {
- if (buffer.get() == (byte)0) {
- foundNull = true;
- break;
- }
-
- stringLength++;
- }
- if (!foundNull) {
- throw new IllegalArgumentException("Strings must be null-terminated");
- }
-
- buffer.reset(); // go back to the previously marked position
-
- byte[] strBytes = new byte[stringLength + 1];
- buffer.get(strBytes, /*dstOffset*/0, stringLength + 1); // including null character
-
- // not including null character
- return new String(strBytes, /*offset*/0, stringLength, UTF8_CHARSET);
- }
-
- @Override
- public Class<String> getMarshalingClass() {
- return String.class;
- }
-
- @Override
- public boolean isNativeTypeSupported(int nativeType) {
- return nativeType == CameraMetadataNative.TYPE_BYTE;
- }
-
- @Override
- public int getNativeSize(int nativeType) {
- return NATIVE_SIZE_DYNAMIC;
- }
-}
diff --git a/core/java/android/hardware/camera2/marshal/MarshalHelpers.java b/core/java/android/hardware/camera2/marshal/MarshalHelpers.java
new file mode 100644
index 0000000..fd72ee2
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/MarshalHelpers.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static com.android.internal.util.Preconditions.*;
+
+import android.hardware.camera2.Rational;
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+/**
+ * Static functions in order to help implementing various marshaler functionality.
+ *
+ * <p>The intention is to statically import everything from this file into another file when
+ * implementing a new marshaler (or marshal queryable).</p>
+ *
+ * <p>The helpers are centered around providing primitive knowledge of the native types,
+ * such as the native size, the managed class wrappers, and various precondition checks.</p>
+ */
+public final class MarshalHelpers {
+
+ public static final int SIZEOF_BYTE = 1;
+ public static final int SIZEOF_INT32 = Integer.SIZE / Byte.SIZE;
+ public static final int SIZEOF_INT64 = Long.SIZE / Byte.SIZE;
+ public static final int SIZEOF_FLOAT = Float.SIZE / Byte.SIZE;
+ public static final int SIZEOF_DOUBLE = Double.SIZE / Byte.SIZE;
+ public static final int SIZEOF_RATIONAL = SIZEOF_INT32 * 2;
+
+ /**
+ * Get the size in bytes for the native camera metadata type.
+ *
+ * <p>This used to determine how many bytes it would take to encode/decode a single value
+ * of that {@link nativeType}.</p>
+ *
+ * @param nativeType the native type, e.g.
+ * {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
+ * @return size in bytes >= 1
+ *
+ * @throws UnsupportedOperationException if nativeType was not one of the built-in types
+ */
+ public static int getPrimitiveTypeSize(int nativeType) {
+ switch (nativeType) {
+ case TYPE_BYTE:
+ return SIZEOF_BYTE;
+ case TYPE_INT32:
+ return SIZEOF_INT32;
+ case TYPE_FLOAT:
+ return SIZEOF_FLOAT;
+ case TYPE_INT64:
+ return SIZEOF_INT64;
+ case TYPE_DOUBLE:
+ return SIZEOF_DOUBLE;
+ case TYPE_RATIONAL:
+ return SIZEOF_RATIONAL;
+ }
+
+ throw new UnsupportedOperationException("Unknown type, can't get size for "
+ + nativeType);
+ }
+
+
+ /**
+ * Ensure that the {@code klass} is one of the metadata-primitive classes.
+ *
+ * @param klass a non-{@code null} reference
+ * @return {@code klass} instance
+ *
+ * @throws UnsupportedOperationException if klass was not one of the built-in classes
+ * @throws NullPointerException if klass was null
+ *
+ * @see #isPrimitiveClass
+ */
+ public static <T> Class<T> checkPrimitiveClass(Class<T> klass) {
+ checkNotNull(klass, "klass must not be null");
+
+ if (isPrimitiveClass(klass)) {
+ return klass;
+ }
+
+ throw new UnsupportedOperationException("Unsupported class '" + klass +
+ "'; expected a metadata primitive class");
+ }
+
+ /**
+ * Checks whether or not {@code klass} is one of the metadata-primitive classes.
+ *
+ * <p>The following types (whether boxed or unboxed) are considered primitive:
+ * <ul>
+ * <li>byte
+ * <li>int
+ * <li>float
+ * <li>double
+ * <li>Rational
+ * </ul>
+ * </p>
+ *
+ * <p>This doesn't strictly follow the java understanding of primitive since
+ * boxed objects are included, Rational is included, and other types such as char and
+ * short are not included.</p>
+ *
+ * @param klass a {@link Class} instance; using {@code null} will return {@code false}
+ * @return {@code true} if primitive, {@code false} otherwise
+ */
+ public static <T> boolean isPrimitiveClass(Class<T> klass) {
+ if (klass == null) {
+ return false;
+ }
+
+ if (klass == byte.class || klass == Byte.class) {
+ return true;
+ } else if (klass == int.class || klass == Integer.class) {
+ return true;
+ } else if (klass == float.class || klass == Float.class) {
+ return true;
+ } else if (klass == long.class || klass == Long.class) {
+ return true;
+ } else if (klass == double.class || klass == Double.class) {
+ return true;
+ } else if (klass == Rational.class) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Wrap {@code klass} with its wrapper variant if it was a {@code Class} corresponding
+ * to a Java primitive.
+ *
+ * <p>Non-primitive classes are passed through as-is.</p>
+ *
+ * <p>For example, for a primitive {@code int.class => Integer.class},
+ * but for a non-primitive {@code Rational.class => Rational.class}.</p>
+ *
+ * @param klass a {@code Class} reference
+ *
+ * @return wrapped class object, or same class object if non-primitive
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Class<T> wrapClassIfPrimitive(Class<T> klass) {
+ if (klass == byte.class) {
+ return (Class<T>)Byte.class;
+ } else if (klass == int.class) {
+ return (Class<T>)Integer.class;
+ } else if (klass == float.class) {
+ return (Class<T>)Float.class;
+ } else if (klass == long.class) {
+ return (Class<T>)Long.class;
+ } else if (klass == double.class) {
+ return (Class<T>)Double.class;
+ }
+
+ return klass;
+ }
+
+ /**
+ * Return a human-readable representation of the {@code nativeType}, e.g. "TYPE_INT32"
+ *
+ * <p>Out-of-range values return a string with "UNKNOWN" as the prefix.</p>
+ *
+ * @param nativeType the native type
+ *
+ * @return human readable type name
+ */
+ public static String toStringNativeType(int nativeType) {
+ switch (nativeType) {
+ case TYPE_BYTE:
+ return "TYPE_BYTE";
+ case TYPE_INT32:
+ return "TYPE_INT32";
+ case TYPE_FLOAT:
+ return "TYPE_FLOAT";
+ case TYPE_INT64:
+ return "TYPE_INT64";
+ case TYPE_DOUBLE:
+ return "TYPE_DOUBLE";
+ case TYPE_RATIONAL:
+ return "TYPE_RATIONAL";
+ }
+
+ return "UNKNOWN(" + nativeType + ")";
+ }
+
+ /**
+ * Ensure that the {@code nativeType} is one of the native types supported
+ * by {@link CameraMetadataNative}.
+ *
+ * @param nativeType the native type
+ *
+ * @return the native type
+ *
+ * @throws UnsupportedOperationException if the native type was invalid
+ */
+ public static int checkNativeType(int nativeType) {
+ switch (nativeType) {
+ case TYPE_BYTE:
+ case TYPE_INT32:
+ case TYPE_FLOAT:
+ case TYPE_INT64:
+ case TYPE_DOUBLE:
+ case TYPE_RATIONAL:
+ return nativeType;
+ }
+
+ throw new UnsupportedOperationException("Unknown nativeType " + nativeType);
+ }
+
+ /**
+ * Ensure that the expected and actual native types are equal.
+ *
+ * @param expectedNativeType the expected native type
+ * @param actualNativeType the actual native type
+ * @return the actual native type
+ *
+ * @throws UnsupportedOperationException if the types are not equal
+ */
+ public static int checkNativeTypeEquals(int expectedNativeType, int actualNativeType) {
+ if (expectedNativeType != actualNativeType) {
+ throw new UnsupportedOperationException(
+ String.format("Expected native type %d, but got %d",
+ expectedNativeType, actualNativeType));
+ }
+
+ return actualNativeType;
+ }
+
+ private MarshalHelpers() {
+ throw new AssertionError();
+ }
+}
diff --git a/core/java/android/hardware/camera2/marshal/MarshalQueryable.java b/core/java/android/hardware/camera2/marshal/MarshalQueryable.java
new file mode 100644
index 0000000..35fed1f
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/MarshalQueryable.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal;
+
+import android.hardware.camera2.utils.TypeReference;
+
+/**
+ * Query if a marshaler can marshal to/from a particular native and managed type; if it supports
+ * the combination, allow creating a marshaler instance to do the serialization.
+ *
+ * <p>Not all queryable instances will support exactly one combination. Some, such as the
+ * primitive queryable will support all primitive to/from managed mappings (as long as they are
+ * 1:1). Others, such as the rectangle queryable will only support integer to rectangle mappings.
+ * </p>
+ *
+ * <p>Yet some others are codependent on other queryables; e.g. array queryables might only support
+ * a type map for {@code T[]} if another queryable exists with support for the component type
+ * {@code T}.</p>
+ */
+public interface MarshalQueryable<T> {
+ /**
+ * Create a marshaler between the selected managed and native type.
+ *
+ * <p>This marshaler instance is only good for that specific type mapping; and will refuse
+ * to map other managed types, other native types, or an other combination that isn't
+ * this exact one.</p>
+ *
+ * @param managedType a managed type reference
+ * @param nativeType the native type, e.g.
+ * {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
+ * @return
+ *
+ * @throws UnsupportedOperationException
+ * if {@link #isTypeMappingSupported} returns {@code false}
+ */
+ public Marshaler<T> createMarshaler(
+ TypeReference<T> managedType, int nativeType);
+
+ /**
+ * Determine whether or not this query marshal is able to create a marshaler that will
+ * support the managed type and native type mapping.
+ *
+ * <p>If this returns {@code true}, then a marshaler can be instantiated by
+ * {@link #createMarshaler} that will marshal data to/from the native type
+ * from/to the managed type.</p>
+ *
+ * <p>Most marshalers are likely to only support one type map.</p>
+ */
+ public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType);
+}
diff --git a/core/java/android/hardware/camera2/marshal/MarshalRegistry.java b/core/java/android/hardware/camera2/marshal/MarshalRegistry.java
new file mode 100644
index 0000000..92d9057
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/MarshalRegistry.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal;
+
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.utils.TypeReference;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Registry of supported marshalers; add new query-able marshalers or lookup existing ones.</p>
+ */
+public class MarshalRegistry {
+
+ /**
+ * Register a marshal queryable for the managed type {@code T}.
+ *
+ * <p>Multiple marshal queryables for the same managed type {@code T} may be registered;
+ * this is desirable if they support different native types (e.g. marshaler 1 supports
+ * {@code Integer <-> TYPE_INT32}, marshaler 2 supports {@code Integer <-> TYPE_BYTE}.</p>
+ *
+ * @param queryable a non-{@code null} marshal queryable that supports marshaling {@code T}
+ */
+ public static <T> void registerMarshalQueryable(MarshalQueryable<T> queryable) {
+ sRegisteredMarshalQueryables.add(queryable);
+ }
+
+ /**
+ * Lookup a marshaler between {@code T} and {@code nativeType}.
+ *
+ * <p>Marshalers are looked up in the order they were registered; earlier registered
+ * marshal queriers get priority.</p>
+ *
+ * @param typeToken The compile-time type reference for {@code T}
+ * @param nativeType The native type, e.g. {@link CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
+ * @return marshaler a non-{@code null} marshaler that supports marshaling the type combo
+ *
+ * @throws UnsupportedOperationException If no marshaler matching the args could be found
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Marshaler<T> getMarshaler(TypeReference<T> typeToken, int nativeType) {
+ // TODO: can avoid making a new token each time by code-genning
+ // the list of type tokens and native types from the keys (at the call sites)
+ MarshalToken<T> marshalToken = new MarshalToken<T>(typeToken, nativeType);
+
+ /*
+ * Marshalers are instantiated lazily once they are looked up; successive lookups
+ * will not instantiate new marshalers.
+ */
+ Marshaler<T> marshaler =
+ (Marshaler<T>) sMarshalerMap.get(marshalToken);
+
+ if (sRegisteredMarshalQueryables.size() == 0) {
+ throw new AssertionError("No available query marshalers registered");
+ }
+
+ if (marshaler == null) {
+ // Query each marshaler to see if they support the native/managed type combination
+ for (MarshalQueryable<?> potentialMarshaler : sRegisteredMarshalQueryables) {
+
+ MarshalQueryable<T> castedPotential =
+ (MarshalQueryable<T>)potentialMarshaler;
+
+ if (castedPotential.isTypeMappingSupported(typeToken, nativeType)) {
+ marshaler = castedPotential.createMarshaler(typeToken, nativeType);
+ break;
+ }
+ }
+ }
+
+ if (marshaler == null) {
+ throw new UnsupportedOperationException(
+ "Could not find marshaler that matches the requested " +
+ "combination of type reference " +
+ typeToken + " and native type " +
+ MarshalHelpers.toStringNativeType(nativeType));
+ }
+
+ sMarshalerMap.put(marshalToken, marshaler);
+
+ return marshaler;
+ }
+
+ private static class MarshalToken<T> {
+ public MarshalToken(TypeReference<T> typeReference, int nativeType) {
+ this.typeReference = typeReference;
+ this.nativeType = nativeType;
+ }
+
+ final TypeReference<T> typeReference;
+ final int nativeType;
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof MarshalToken<?>) {
+ MarshalToken<?> otherToken = (MarshalToken<?>)other;
+ return typeReference.equals(otherToken.typeReference) &&
+ nativeType == otherToken.nativeType;
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return typeReference.hashCode() ^ nativeType;
+ }
+ }
+
+ private static List<MarshalQueryable<?>> sRegisteredMarshalQueryables =
+ new ArrayList<MarshalQueryable<?>>();
+ private static HashMap<MarshalToken<?>, Marshaler<?>> sMarshalerMap =
+ new HashMap<MarshalToken<?>, Marshaler<?>>();
+
+ private MarshalRegistry() {
+ throw new AssertionError();
+ }
+}
diff --git a/core/java/android/hardware/camera2/marshal/Marshaler.java b/core/java/android/hardware/camera2/marshal/Marshaler.java
new file mode 100644
index 0000000..eb0ad15
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/Marshaler.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal;
+
+import android.hardware.camera2.utils.TypeReference;
+
+import java.nio.ByteBuffer;
+
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Base class to marshal data to/from managed/native metadata byte buffers.
+ *
+ * <p>This class should not be created directly; an instance of it can be obtained
+ * using {@link MarshalQueryable#createMarshaler} for the same type {@code T} if the native type
+ * mapping for {@code T} {@link MarshalQueryable#isTypeMappingSupported supported}.</p>
+ *
+ * @param <T> the compile-time managed type
+ */
+public abstract class Marshaler<T> {
+
+ protected final TypeReference<T> mTypeReference;
+ protected final int mNativeType;
+
+ /**
+ * Instantiate a marshaler between a single managed/native type combination.
+ *
+ * <p>This particular managed/native type combination must be supported by
+ * {@link #isTypeMappingSupported}.</p>
+ *
+ * @param query an instance of {@link MarshalQueryable}
+ * @param typeReference the managed type reference
+ * Must be one for which {@link #isTypeMappingSupported} returns {@code true}
+ * @param nativeType the native type, e.g.
+ * {@link android.hardware.camera2.impl.CameraMetadataNative#TYPE_BYTE TYPE_BYTE}.
+ * Must be one for which {@link #isTypeMappingSupported} returns {@code true}.
+ *
+ * @throws NullPointerException if any args were {@code null}
+ * @throws UnsupportedOperationException if the type mapping was not supported
+ */
+ protected Marshaler(
+ MarshalQueryable<T> query, TypeReference<T> typeReference, int nativeType) {
+ mTypeReference = checkNotNull(typeReference, "typeReference must not be null");
+ mNativeType = checkNativeType(nativeType);
+
+ if (!query.isTypeMappingSupported(typeReference, nativeType)) {
+ throw new UnsupportedOperationException(
+ "Unsupported type marshaling for managed type "
+ + typeReference + " and native type "
+ + MarshalHelpers.toStringNativeType(nativeType));
+ }
+ }
+
+ /**
+ * Marshal the specified object instance (value) into a byte buffer.
+ *
+ * <p>Upon completion, the {@link ByteBuffer#position()} will have advanced by
+ * the {@link #calculateMarshalSize marshal size} of {@code value}.</p>
+ *
+ * @param value the value of type T that we wish to write into the byte buffer
+ * @param buffer the byte buffer into which the marshaled object will be written
+ */
+ public abstract void marshal(T value, ByteBuffer buffer);
+
+ /**
+ * Get the size in bytes for how much space would be required to write this {@code value}
+ * into a byte buffer using the given {@code nativeType}.
+ *
+ * <p>If the size of this {@code T} instance when serialized into a buffer is always constant,
+ * then this method will always return the same value (and particularly, it will return
+ * an equivalent value to {@link #getNativeSize()}.</p>
+ *
+ * <p>Overriding this method is a must when the size is {@link NATIVE_SIZE_DYNAMIC dynamic}.</p>
+ *
+ * @param value the value of type T that we wish to write into the byte buffer
+ * @return the size that would need to be written to the byte buffer
+ */
+ public int calculateMarshalSize(T value) {
+ int nativeSize = getNativeSize();
+
+ if (nativeSize == NATIVE_SIZE_DYNAMIC) {
+ throw new AssertionError("Override this function for dynamically-sized objects");
+ }
+
+ return nativeSize;
+ }
+
+ /**
+ * Unmarshal a new object instance from the byte buffer into its managed type.
+ *
+ * <p>Upon completion, the {@link ByteBuffer#position()} will have advanced by
+ * the {@link #calculateMarshalSize marshal size} of the returned {@code T} instance.</p>
+ *
+ * @param buffer the byte buffer, from which we will read the object
+ * @return a new instance of type T read from the byte buffer
+ */
+ public abstract T unmarshal(ByteBuffer buffer);
+
+ /**
+ * Used to denote variable-length data structures.
+ *
+ * <p>If the size is dynamic then we can't know ahead of time how big of a data structure
+ * to preallocate for e.g. arrays, so one object must be unmarshaled at a time.</p>
+ */
+ public static int NATIVE_SIZE_DYNAMIC = -1;
+
+ /**
+ * How many bytes a single instance of {@code T} will take up if marshalled to/from
+ * {@code nativeType}.
+ *
+ * <p>When unmarshaling data from native to managed, the instance {@code T} is not yet
+ * available. If the native size is always a fixed mapping regardless of the instance of
+ * {@code T} (e.g. if the type is not a container of some sort), it can be used to preallocate
+ * containers for {@code T} to avoid resizing them.</p>
+ *
+ * <p>In particular, the array marshaler takes advantage of this (when size is not dynamic)
+ * to preallocate arrays of the right length when unmarshaling an array {@code T[]}.</p>
+ *
+ * @return a size in bytes, or {@link #NATIVE_SIZE_DYNAMIC} if the size is dynamic
+ */
+ public abstract int getNativeSize();
+
+ /**
+ * The type reference for {@code T} for the managed type side of this marshaler.
+ */
+ public TypeReference<T> getTypeReference() {
+ return mTypeReference;
+ }
+
+ /** The native type corresponding to this marshaler for the native side of this marshaler.*/
+ public int getNativeType() {
+ return mNativeType;
+ }
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableArray.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableArray.java
new file mode 100644
index 0000000..22b87ef
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableArray.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.marshal.MarshalRegistry;
+import android.hardware.camera2.utils.TypeReference;
+import android.util.Log;
+
+import java.lang.reflect.Array;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+/**
+ * Marshal any array {@code T}.
+ *
+ * <p>To marshal any {@code T} to/from a native type, the marshaler for T to/from that native type
+ * also has to exist.</p>
+ *
+ * <p>{@code T} can be either a T2[] where T2 is an object type, or a P[] where P is a
+ * built-in primitive (e.g. int[], float[], etc).</p>
+
+ * @param <T> the type of the array (e.g. T = int[], or T = Rational[])
+ */
+public class MarshalQueryableArray<T> implements MarshalQueryable<T> {
+
+ private static final String TAG = MarshalQueryableArray.class.getSimpleName();
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
+ private class MarshalerArray extends Marshaler<T> {
+ private final Class<T> mClass;
+ private final Marshaler<?> mComponentMarshaler;
+ private final Class<?> mComponentClass;
+
+ @SuppressWarnings("unchecked")
+ protected MarshalerArray(TypeReference<T> typeReference, int nativeType) {
+ super(MarshalQueryableArray.this, typeReference, nativeType);
+
+ mClass = (Class<T>)typeReference.getRawType();
+
+ TypeReference<?> componentToken = typeReference.getComponentType();
+ mComponentMarshaler = MarshalRegistry.getMarshaler(componentToken, mNativeType);
+ mComponentClass = componentToken.getRawType();
+ }
+
+ @Override
+ public void marshal(T value, ByteBuffer buffer) {
+ int length = Array.getLength(value);
+ for (int i = 0; i < length; ++i) {
+ marshalArrayElement(mComponentMarshaler, buffer, value, i);
+ }
+ }
+
+ @Override
+ public T unmarshal(ByteBuffer buffer) {
+ Object array;
+
+ int elementSize = mComponentMarshaler.getNativeSize();
+
+ if (elementSize != Marshaler.NATIVE_SIZE_DYNAMIC) {
+ int remaining = buffer.remaining();
+ int arraySize = remaining / elementSize;
+
+ if (remaining % elementSize != 0) {
+ throw new UnsupportedOperationException("Arrays for " + mTypeReference
+ + " must be packed tighly into a multiple of " + elementSize
+ + "; but there are " + (remaining % elementSize) + " left over bytes");
+ }
+
+ if (VERBOSE) {
+ Log.v(TAG, String.format(
+ "Attempting to unpack array (count = %d, element size = %d, bytes "
+ + "remaining = %d) for type %s",
+ arraySize, elementSize, remaining, mClass));
+ }
+
+ array = Array.newInstance(mComponentClass, arraySize);
+ for (int i = 0; i < arraySize; ++i) {
+ Object elem = mComponentMarshaler.unmarshal(buffer);
+ Array.set(array, i, elem);
+ }
+ } else {
+ // Dynamic size, use an array list.
+ ArrayList<Object> arrayList = new ArrayList<Object>();
+
+ // Assumes array is packed tightly; no unused bytes allowed
+ while (buffer.hasRemaining()) {
+ Object elem = mComponentMarshaler.unmarshal(buffer);
+ arrayList.add(elem);
+ }
+
+ int arraySize = arrayList.size();
+ array = copyListToArray(arrayList, Array.newInstance(mComponentClass, arraySize));
+ }
+
+ if (buffer.remaining() != 0) {
+ Log.e(TAG, "Trailing bytes (" + buffer.remaining() + ") left over after unpacking "
+ + mClass);
+ }
+
+ return mClass.cast(array);
+ }
+
+ @Override
+ public int getNativeSize() {
+ return NATIVE_SIZE_DYNAMIC;
+ }
+
+ @Override
+ public int calculateMarshalSize(T value) {
+ int elementSize = mComponentMarshaler.getNativeSize();
+ int arrayLength = Array.getLength(value);
+
+ if (elementSize != Marshaler.NATIVE_SIZE_DYNAMIC) {
+ // The fast way. Every element size is uniform.
+ return elementSize * arrayLength;
+ } else {
+ // The slow way. Accumulate size for each element.
+ int size = 0;
+ for (int i = 0; i < arrayLength; ++i) {
+ size += calculateElementMarshalSize(mComponentMarshaler, value, i);
+ }
+
+ return size;
+ }
+ }
+
+ /*
+ * Helpers to avoid compiler errors regarding types with wildcards (?)
+ */
+
+ @SuppressWarnings("unchecked")
+ private <TElem> void marshalArrayElement(Marshaler<TElem> marshaler,
+ ByteBuffer buffer, Object array, int index) {
+ marshaler.marshal((TElem)Array.get(array, index), buffer);
+ }
+
+ @SuppressWarnings("unchecked")
+ private Object copyListToArray(ArrayList<?> arrayList, Object arrayDest) {
+ return arrayList.toArray((T[]) arrayDest);
+ }
+
+ @SuppressWarnings("unchecked")
+ private <TElem> int calculateElementMarshalSize(Marshaler<TElem> marshaler,
+ Object array, int index) {
+ Object elem = Array.get(array, index);
+
+ return marshaler.calculateMarshalSize((TElem) elem);
+ }
+ }
+
+ @Override
+ public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
+ return new MarshalerArray(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
+ // support both ConcreteType[] and GenericType<ConcreteType>[]
+ return managedType.getRawType().isArray();
+
+ // TODO: Should this recurse deeper and check that there is
+ // a valid marshaler for the ConcreteType as well?
+ }
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableBoolean.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableBoolean.java
new file mode 100644
index 0000000..4aa4b4a
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableBoolean.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshal booleans: TYPE_BYTE <-> boolean/Boolean
+ */
+public class MarshalQueryableBoolean implements MarshalQueryable<Boolean> {
+
+ private class MarshalerBoolean extends Marshaler<Boolean> {
+ protected MarshalerBoolean(TypeReference<Boolean> typeReference, int nativeType) {
+ super(MarshalQueryableBoolean.this, typeReference, nativeType);
+ }
+
+ @Override
+ public void marshal(Boolean value, ByteBuffer buffer) {
+ boolean unboxValue = value;
+ buffer.put((byte)(unboxValue ? 1 : 0));
+ }
+
+ @Override
+ public Boolean unmarshal(ByteBuffer buffer) {
+ return buffer.get() != 0;
+ }
+
+ @Override
+ public int getNativeSize() {
+ return SIZEOF_BYTE;
+ }
+ }
+
+ @Override
+ public Marshaler<Boolean> createMarshaler(TypeReference<Boolean> managedType,
+ int nativeType) {
+ return new MarshalerBoolean(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(TypeReference<Boolean> managedType, int nativeType) {
+ return (Boolean.class.equals(managedType.getType())
+ || boolean.class.equals(managedType.getType())) && nativeType == TYPE_BYTE;
+ }
+
+
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java
new file mode 100644
index 0000000..d3796db
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.ColorSpaceTransform;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import java.nio.ByteBuffer;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+/**
+ * Marshal {@link ColorSpaceTransform} to/from {@link #TYPE_RATIONAL}
+ */
+public class MarshalQueryableColorSpaceTransform implements
+ MarshalQueryable<ColorSpaceTransform> {
+
+ private static final int ELEMENTS_INT32 = 3 * 3 * (SIZEOF_RATIONAL / SIZEOF_INT32);
+ private static final int SIZE = SIZEOF_INT32 * ELEMENTS_INT32;
+
+ /** rational x 3 x 3 */
+ private class MarshalerColorSpaceTransform extends Marshaler<ColorSpaceTransform> {
+ protected MarshalerColorSpaceTransform(TypeReference<ColorSpaceTransform> typeReference,
+ int nativeType) {
+ super(MarshalQueryableColorSpaceTransform.this, typeReference, nativeType);
+ }
+
+ @Override
+ public void marshal(ColorSpaceTransform value, ByteBuffer buffer) {
+ int[] transformAsArray = new int[ELEMENTS_INT32];
+ value.copyElements(transformAsArray, /*offset*/0);
+
+ for (int i = 0; i < ELEMENTS_INT32; ++i) {
+ buffer.putInt(transformAsArray[i]);
+ }
+ }
+
+ @Override
+ public ColorSpaceTransform unmarshal(ByteBuffer buffer) {
+ int[] transformAsArray = new int[ELEMENTS_INT32];
+
+ for (int i = 0; i < ELEMENTS_INT32; ++i) {
+ transformAsArray[i] = buffer.getInt();
+ }
+
+ return new ColorSpaceTransform(transformAsArray);
+ }
+
+ @Override
+ public int getNativeSize() {
+ return SIZE;
+ }
+ }
+
+ @Override
+ public Marshaler<ColorSpaceTransform> createMarshaler(
+ TypeReference<ColorSpaceTransform> managedType, int nativeType) {
+ return new MarshalerColorSpaceTransform(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(
+ TypeReference<ColorSpaceTransform> managedType, int nativeType) {
+ return nativeType == TYPE_RATIONAL &&
+ ColorSpaceTransform.class.equals(managedType.getType());
+ }
+
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableEnum.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableEnum.java
new file mode 100644
index 0000000..fa53db2
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableEnum.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+import android.util.Log;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+/**
+ * Marshal any simple enum (0-arg constructors only) into/from either
+ * {@code TYPE_BYTE} or {@code TYPE_INT32}.
+ *
+ * <p>Default values of the enum are mapped to its ordinal; this can be overridden
+ * by providing a manual value with {@link #registerEnumValues}.</p>
+
+ * @param <T> the type of {@code Enum}
+ */
+public class MarshalQueryableEnum<T extends Enum<T>> implements MarshalQueryable<T> {
+
+ private static final String TAG = MarshalQueryableEnum.class.getSimpleName();
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
+ private static final int UINT8_MIN = 0x0;
+ private static final int UINT8_MAX = (1 << Byte.SIZE) - 1;
+ private static final int UINT8_MASK = UINT8_MAX;
+
+ private class MarshalerEnum extends Marshaler<T> {
+
+ private final Class<T> mClass;
+
+ @SuppressWarnings("unchecked")
+ protected MarshalerEnum(TypeReference<T> typeReference, int nativeType) {
+ super(MarshalQueryableEnum.this, typeReference, nativeType);
+
+ mClass = (Class<T>)typeReference.getRawType();
+ }
+
+ @Override
+ public void marshal(T value, ByteBuffer buffer) {
+ int enumValue = getEnumValue(value);
+
+ if (mNativeType == TYPE_INT32) {
+ buffer.putInt(enumValue);
+ } else if (mNativeType == TYPE_BYTE) {
+ if (enumValue < UINT8_MIN || enumValue > UINT8_MAX) {
+ throw new UnsupportedOperationException(String.format(
+ "Enum value %x too large to fit into unsigned byte", enumValue));
+ }
+ buffer.put((byte)enumValue);
+ } else {
+ throw new AssertionError();
+ }
+ }
+
+ @Override
+ public T unmarshal(ByteBuffer buffer) {
+ int enumValue;
+
+ switch (mNativeType) {
+ case TYPE_INT32:
+ enumValue = buffer.getInt();
+ break;
+ case TYPE_BYTE:
+ // get the unsigned byte value; avoid sign extension
+ enumValue = buffer.get() & UINT8_MASK;
+ break;
+ default:
+ throw new AssertionError(
+ "Unexpected native type; impossible since its not supported");
+ }
+
+ return getEnumFromValue(mClass, enumValue);
+ }
+
+ @Override
+ public int getNativeSize() {
+ return getPrimitiveTypeSize(mNativeType);
+ }
+ }
+
+ @Override
+ public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
+ return new MarshalerEnum(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
+ if (nativeType == TYPE_INT32 || nativeType == TYPE_BYTE) {
+ if (managedType.getType() instanceof Class<?>) {
+ Class<?> typeClass = (Class<?>)managedType.getType();
+
+ if (typeClass.isEnum()) {
+ if (VERBOSE) {
+ Log.v(TAG, "possible enum detected for " + typeClass);
+ }
+
+ // The enum must not take extra arguments
+ try {
+ // match a class like: "public enum Fruits { Apple, Orange; }"
+ typeClass.getDeclaredConstructor(String.class, int.class);
+ return true;
+ } catch (NoSuchMethodException e) {
+ // Skip: custom enum with a special constructor e.g. Foo(T), but need Foo()
+ Log.e(TAG, "Can't marshal class " + typeClass + "; no default constructor");
+ } catch (SecurityException e) {
+ // Skip: wouldn't be able to touch the enum anyway
+ Log.e(TAG, "Can't marshal class " + typeClass + "; not accessible");
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ @SuppressWarnings("rawtypes")
+ private static final HashMap<Class<? extends Enum>, int[]> sEnumValues =
+ new HashMap<Class<? extends Enum>, int[]>();
+
+ /**
+ * Register a non-sequential set of values to be used with the marshal/unmarshal functions.
+ *
+ * <p>This enables get/set to correctly marshal the enum into a value that is C-compatible.</p>
+ *
+ * @param enumType The class for an enum
+ * @param values A list of values mapping to the ordinals of the enum
+ */
+ public static <T extends Enum<T>> void registerEnumValues(Class<T> enumType, int[] values) {
+ if (enumType.getEnumConstants().length != values.length) {
+ throw new IllegalArgumentException(
+ "Expected values array to be the same size as the enumTypes values "
+ + values.length + " for type " + enumType);
+ }
+ if (VERBOSE) {
+ Log.v(TAG, "Registered enum values for type " + enumType + " values");
+ }
+
+ sEnumValues.put(enumType, values);
+ }
+
+ /**
+ * Get the numeric value from an enum.
+ *
+ * <p>This is usually the same as the ordinal value for
+ * enums that have fully sequential values, although for C-style enums the range of values
+ * may not map 1:1.</p>
+ *
+ * @param enumValue Enum instance
+ * @return Int guaranteed to be ABI-compatible with the C enum equivalent
+ */
+ private static <T extends Enum<T>> int getEnumValue(T enumValue) {
+ int[] values;
+ values = sEnumValues.get(enumValue.getClass());
+
+ int ordinal = enumValue.ordinal();
+ if (values != null) {
+ return values[ordinal];
+ }
+
+ return ordinal;
+ }
+
+ /**
+ * Finds the enum corresponding to it's numeric value. Opposite of {@link #getEnumValue} method.
+ *
+ * @param enumType Class of the enum we want to find
+ * @param value The numeric value of the enum
+ * @return An instance of the enum
+ */
+ private static <T extends Enum<T>> T getEnumFromValue(Class<T> enumType, int value) {
+ int ordinal;
+
+ int[] registeredValues = sEnumValues.get(enumType);
+ if (registeredValues != null) {
+ ordinal = -1;
+
+ for (int i = 0; i < registeredValues.length; ++i) {
+ if (registeredValues[i] == value) {
+ ordinal = i;
+ break;
+ }
+ }
+ } else {
+ ordinal = value;
+ }
+
+ T[] values = enumType.getEnumConstants();
+
+ if (ordinal < 0 || ordinal >= values.length) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Argument 'value' (%d) was not a valid enum value for type %s "
+ + "(registered? %b)",
+ value,
+ enumType, (registeredValues != null)));
+ }
+
+ return values[ordinal];
+ }
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java
new file mode 100644
index 0000000..c8b9bd8
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.MeteringRectangle;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import java.nio.ByteBuffer;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+/**
+ * Marshal {@link MeteringRectangle} to/from {@link #TYPE_INT32}
+ */
+public class MarshalQueryableMeteringRectangle implements MarshalQueryable<MeteringRectangle> {
+ private static final int SIZE = SIZEOF_INT32 * 5;
+
+ /** (xmin, ymin, xmax, ymax, weight) */
+ private class MarshalerMeteringRectangle extends Marshaler<MeteringRectangle> {
+ protected MarshalerMeteringRectangle(TypeReference<MeteringRectangle> typeReference,
+ int nativeType) {
+ super(MarshalQueryableMeteringRectangle.this, typeReference, nativeType);
+ }
+
+ @Override
+ public void marshal(MeteringRectangle value, ByteBuffer buffer) {
+ int xMin = value.getX();
+ int yMin = value.getY();
+ int xMax = xMin + value.getWidth();
+ int yMax = yMin + value.getHeight();
+ int weight = value.getMeteringWeight();
+
+ buffer.putInt(xMin);
+ buffer.putInt(yMin);
+ buffer.putInt(xMax);
+ buffer.putInt(yMax);
+ buffer.putInt(weight);
+ }
+
+ @Override
+ public MeteringRectangle unmarshal(ByteBuffer buffer) {
+ int xMin = buffer.getInt();
+ int yMin = buffer.getInt();
+ int xMax = buffer.getInt();
+ int yMax = buffer.getInt();
+ int weight = buffer.getInt();
+
+ int width = xMax - xMin;
+ int height = yMax - yMin;
+
+ return new MeteringRectangle(xMin, yMin, width, height, weight);
+ }
+
+ @Override
+ public int getNativeSize() {
+ return SIZE;
+ }
+ }
+
+ @Override
+ public Marshaler<MeteringRectangle> createMarshaler(
+ TypeReference<MeteringRectangle> managedType, int nativeType) {
+ return new MarshalerMeteringRectangle(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(
+ TypeReference<MeteringRectangle> managedType, int nativeType) {
+ return nativeType == TYPE_INT32 && MeteringRectangle.class.equals(managedType.getType());
+ }
+
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableNativeByteToInteger.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableNativeByteToInteger.java
new file mode 100644
index 0000000..3b89c82
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableNativeByteToInteger.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshal fake native enums (ints): TYPE_BYTE <-> int/Integer
+ */
+public class MarshalQueryableNativeByteToInteger implements MarshalQueryable<Integer> {
+
+ private static final int UINT8_MASK = (1 << Byte.SIZE) - 1;
+
+ private class MarshalerNativeByteToInteger extends Marshaler<Integer> {
+ protected MarshalerNativeByteToInteger(TypeReference<Integer> typeReference,
+ int nativeType) {
+ super(MarshalQueryableNativeByteToInteger.this, typeReference, nativeType);
+ }
+
+ @Override
+ public void marshal(Integer value, ByteBuffer buffer) {
+ buffer.put((byte)(int)value); // truncate down to byte
+ }
+
+ @Override
+ public Integer unmarshal(ByteBuffer buffer) {
+ // expand unsigned byte to int; avoid sign extension
+ return buffer.get() & UINT8_MASK;
+ }
+
+ @Override
+ public int getNativeSize() {
+ return SIZEOF_BYTE;
+ }
+ }
+
+ @Override
+ public Marshaler<Integer> createMarshaler(TypeReference<Integer> managedType,
+ int nativeType) {
+ return new MarshalerNativeByteToInteger(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(TypeReference<Integer> managedType, int nativeType) {
+ return (Integer.class.equals(managedType.getType())
+ || int.class.equals(managedType.getType())) && nativeType == TYPE_BYTE;
+ }
+
+
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableParcelable.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableParcelable.java
new file mode 100644
index 0000000..1fd6a1d
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableParcelable.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+/**
+ * Marshal any {@code T extends Parcelable} to/from any native type
+ *
+ * <p>Use with extreme caution! File descriptors and binders will not be marshaled across.</p>
+ */
+public class MarshalQueryableParcelable<T extends Parcelable>
+ implements MarshalQueryable<T> {
+
+ private static final String TAG = "MarshalParcelable";
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
+ private static final String FIELD_CREATOR = "CREATOR";
+
+ private class MarshalerParcelable extends Marshaler<T> {
+
+ private final Class<T> mClass;
+ private final Parcelable.Creator<T> mCreator;
+
+ @SuppressWarnings("unchecked")
+ protected MarshalerParcelable(TypeReference<T> typeReference,
+ int nativeType) {
+ super(MarshalQueryableParcelable.this, typeReference, nativeType);
+
+ mClass = (Class<T>)typeReference.getRawType();
+ Field creatorField;
+ try {
+ creatorField = mClass.getDeclaredField(FIELD_CREATOR);
+ } catch (NoSuchFieldException e) {
+ // Impossible. All Parcelable implementations must have a 'CREATOR' static field
+ throw new AssertionError(e);
+ }
+
+ try {
+ mCreator = (Parcelable.Creator<T>)creatorField.get(null);
+ } catch (IllegalAccessException e) {
+ // Impossible: All 'CREATOR' static fields must be public
+ throw new AssertionError(e);
+ } catch (IllegalArgumentException e) {
+ // Impossible: This is a static field, so null must be ok
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public void marshal(T value, ByteBuffer buffer) {
+ if (VERBOSE) {
+ Log.v(TAG, "marshal " + value);
+ }
+
+ Parcel parcel = Parcel.obtain();
+ byte[] parcelContents;
+
+ try {
+ value.writeToParcel(parcel, /*flags*/0);
+
+ if (parcel.hasFileDescriptors()) {
+ throw new UnsupportedOperationException(
+ "Parcelable " + value + " must not have file descriptors");
+ }
+
+ parcelContents = parcel.marshall();
+ }
+ finally {
+ parcel.recycle();
+ }
+
+ if (parcelContents.length == 0) {
+ throw new AssertionError("No data marshaled for " + value);
+ }
+
+ buffer.put(parcelContents);
+ }
+
+ @Override
+ public T unmarshal(ByteBuffer buffer) {
+ if (VERBOSE) {
+ Log.v(TAG, "unmarshal, buffer remaining " + buffer.remaining());
+ }
+
+ /*
+ * Quadratically slow when marshaling an array of parcelables.
+ *
+ * Read out the entire byte buffer as an array, then copy it into the parcel.
+ *
+ * Once we unparcel the entire object, advance the byte buffer by only how many
+ * bytes the parcel actually used up.
+ *
+ * Future: If we ever do need to use parcelable arrays, we can do this a little smarter
+ * by reading out a chunk like 4,8,16,24 each time, but not sure how to detect
+ * parcels being too short in this case.
+ *
+ * Future: Alternatively use Parcel#obtain(long) directly into the native
+ * pointer of a ByteBuffer, which would not copy if the ByteBuffer was direct.
+ */
+ buffer.mark();
+
+ Parcel parcel = Parcel.obtain();
+ try {
+ int maxLength = buffer.remaining();
+
+ byte[] remaining = new byte[maxLength];
+ buffer.get(remaining);
+
+ parcel.unmarshall(remaining, /*offset*/0, maxLength);
+ parcel.setDataPosition(/*pos*/0);
+
+ T value = mCreator.createFromParcel(parcel);
+ int actualLength = parcel.dataPosition();
+
+ if (actualLength == 0) {
+ throw new AssertionError("No data marshaled for " + value);
+ }
+
+ // set the position past the bytes the parcelable actually used
+ buffer.reset();
+ buffer.position(buffer.position() + actualLength);
+
+ if (VERBOSE) {
+ Log.v(TAG, "unmarshal, parcel length was " + actualLength);
+ Log.v(TAG, "unmarshal, value is " + value);
+ }
+
+ return mClass.cast(value);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+ @Override
+ public int getNativeSize() {
+ return NATIVE_SIZE_DYNAMIC;
+ }
+
+ @Override
+ public int calculateMarshalSize(T value) {
+ Parcel parcel = Parcel.obtain();
+ try {
+ value.writeToParcel(parcel, /*flags*/0);
+ int length = parcel.marshall().length;
+
+ if (VERBOSE) {
+ Log.v(TAG, "calculateMarshalSize, length when parceling "
+ + value + " is " + length);
+ }
+
+ return length;
+ } finally {
+ parcel.recycle();
+ }
+ }
+ }
+
+ @Override
+ public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
+ return new MarshalerParcelable(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
+ return Parcelable.class.isAssignableFrom(managedType.getRawType());
+ }
+
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
new file mode 100644
index 0000000..708da70
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.Rational;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+import static com.android.internal.util.Preconditions.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshal/unmarshal built-in primitive types to and from a {@link ByteBuffer}.
+ *
+ * <p>The following list of type marshaling is supported:
+ * <ul>
+ * <li>byte <-> TYPE_BYTE
+ * <li>int <-> TYPE_INT32
+ * <li>long <-> TYPE_INT64
+ * <li>float <-> TYPE_FLOAT
+ * <li>double <-> TYPE_DOUBLE
+ * <li>Rational <-> TYPE_RATIONAL
+ * </ul>
+ * </p>
+ *
+ * <p>Due to the nature of generics, values are always boxed; this also means that both
+ * the boxed and unboxed types are supported (i.e. both {@code int} and {@code Integer}).</p>
+ *
+ * <p>Each managed type <!--(other than boolean)--> must correspond 1:1 to the native type
+ * (e.g. a byte will not map to a {@link CameraMetadataNative#TYPE_INT32 TYPE_INT32} or vice versa)
+ * for marshaling.</p>
+ */
+public final class MarshalQueryablePrimitive<T> implements MarshalQueryable<T> {
+
+ private class MarshalerPrimitive extends Marshaler<T> {
+ /** Always the wrapped class variant of the primitive class for {@code T} */
+ private final Class<T> mClass;
+
+ @SuppressWarnings("unchecked")
+ protected MarshalerPrimitive(TypeReference<T> typeReference, int nativeType) {
+ super(MarshalQueryablePrimitive.this, typeReference, nativeType);
+
+ // Turn primitives into wrappers, otherwise int.class.cast(Integer) will fail
+ mClass = wrapClassIfPrimitive((Class<T>)typeReference.getRawType());
+ }
+
+ @Override
+ public T unmarshal(ByteBuffer buffer) {
+ return mClass.cast(unmarshalObject(buffer));
+ }
+
+ @Override
+ public int calculateMarshalSize(T value) {
+ return getPrimitiveTypeSize(mNativeType);
+ }
+
+ @Override
+ public void marshal(T value, ByteBuffer buffer) {
+ if (value instanceof Integer) {
+ checkNativeTypeEquals(TYPE_INT32, mNativeType);
+ final int val = (Integer) value;
+ marshalPrimitive(val, buffer);
+ } else if (value instanceof Float) {
+ checkNativeTypeEquals(TYPE_FLOAT, mNativeType);
+ final float val = (Float) value;
+ marshalPrimitive(val, buffer);
+ } else if (value instanceof Long) {
+ checkNativeTypeEquals(TYPE_INT64, mNativeType);
+ final long val = (Long) value;
+ marshalPrimitive(val, buffer);
+ } else if (value instanceof Rational) {
+ checkNativeTypeEquals(TYPE_RATIONAL, mNativeType);
+ marshalPrimitive((Rational) value, buffer);
+ } else if (value instanceof Double) {
+ checkNativeTypeEquals(TYPE_DOUBLE, mNativeType);
+ final double val = (Double) value;
+ marshalPrimitive(val, buffer);
+ } else if (value instanceof Byte) {
+ checkNativeTypeEquals(TYPE_BYTE, mNativeType);
+ final byte val = (Byte) value;
+ marshalPrimitive(val, buffer);
+ } else {
+ throw new UnsupportedOperationException(
+ "Can't marshal managed type " + mTypeReference);
+ }
+ }
+
+ private void marshalPrimitive(int value, ByteBuffer buffer) {
+ buffer.putInt(value);
+ }
+
+ private void marshalPrimitive(float value, ByteBuffer buffer) {
+ buffer.putFloat(value);
+ }
+
+ private void marshalPrimitive(double value, ByteBuffer buffer) {
+ buffer.putDouble(value);
+ }
+
+ private void marshalPrimitive(long value, ByteBuffer buffer) {
+ buffer.putLong(value);
+ }
+
+ private void marshalPrimitive(Rational value, ByteBuffer buffer) {
+ buffer.putInt(value.getNumerator());
+ buffer.putInt(value.getDenominator());
+ }
+
+ private void marshalPrimitive(byte value, ByteBuffer buffer) {
+ buffer.put(value);
+ }
+
+ private Object unmarshalObject(ByteBuffer buffer) {
+ switch (mNativeType) {
+ case TYPE_INT32:
+ return buffer.getInt();
+ case TYPE_FLOAT:
+ return buffer.getFloat();
+ case TYPE_INT64:
+ return buffer.getLong();
+ case TYPE_RATIONAL:
+ int numerator = buffer.getInt();
+ int denominator = buffer.getInt();
+ return new Rational(numerator, denominator);
+ case TYPE_DOUBLE:
+ return buffer.getDouble();
+ case TYPE_BYTE:
+ return buffer.get(); // getByte
+ default:
+ throw new UnsupportedOperationException(
+ "Can't unmarshal native type " + mNativeType);
+ }
+ }
+
+ @Override
+ public int getNativeSize() {
+ return getPrimitiveTypeSize(mNativeType);
+ }
+ }
+
+ @Override
+ public Marshaler<T> createMarshaler(TypeReference<T> managedType, int nativeType) {
+ return new MarshalerPrimitive(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(TypeReference<T> managedType, int nativeType) {
+ if (managedType.getType() instanceof Class<?>) {
+ Class<?> klass = (Class<?>)managedType.getType();
+
+ if (klass == byte.class || klass == Byte.class) {
+ return nativeType == TYPE_BYTE;
+ } else if (klass == int.class || klass == Integer.class) {
+ return nativeType == TYPE_INT32;
+ } else if (klass == float.class || klass == Float.class) {
+ return nativeType == TYPE_FLOAT;
+ } else if (klass == long.class || klass == Long.class) {
+ return nativeType == TYPE_INT64;
+ } else if (klass == double.class || klass == Double.class) {
+ return nativeType == TYPE_DOUBLE;
+ } else if (klass == Rational.class) {
+ return nativeType == TYPE_RATIONAL;
+ }
+ }
+ return false;
+ }
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRange.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRange.java
new file mode 100644
index 0000000..8512804
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRange.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.marshal.MarshalRegistry;
+import android.hardware.camera2.utils.TypeReference;
+import android.util.Range;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.nio.ByteBuffer;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+/**
+ * Marshal {@link Range} to/from any native type
+ */
+public class MarshalQueryableRange<T extends Comparable<? super T>>
+ implements MarshalQueryable<Range<T>> {
+ private static final int RANGE_COUNT = 2;
+
+ private class MarshalerRange extends Marshaler<Range<T>> {
+ private final Class<? super Range<T>> mClass;
+ private final Constructor<Range<T>> mConstructor;
+ /** Marshal the {@code T} inside of {@code Range<T>} */
+ private final Marshaler<T> mNestedTypeMarshaler;
+
+ @SuppressWarnings("unchecked")
+ protected MarshalerRange(TypeReference<Range<T>> typeReference,
+ int nativeType) {
+ super(MarshalQueryableRange.this, typeReference, nativeType);
+
+ mClass = typeReference.getRawType();
+
+ /*
+ * Lookup the actual type argument, e.g. Range<Integer> --> Integer
+ * and then get the marshaler for that managed type.
+ */
+ ParameterizedType paramType;
+ try {
+ paramType = (ParameterizedType) typeReference.getType();
+ } catch (ClassCastException e) {
+ throw new AssertionError("Raw use of Range is not supported", e);
+ }
+ Type actualTypeArgument = paramType.getActualTypeArguments()[0];
+
+ TypeReference<?> actualTypeArgToken =
+ TypeReference.createSpecializedTypeReference(actualTypeArgument);
+
+ mNestedTypeMarshaler = (Marshaler<T>)MarshalRegistry.getMarshaler(
+ actualTypeArgToken, mNativeType);
+ try {
+ mConstructor = (Constructor<Range<T>>)mClass.getConstructor(
+ Comparable.class, Comparable.class);
+ } catch (NoSuchMethodException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public void marshal(Range<T> value, ByteBuffer buffer) {
+ mNestedTypeMarshaler.marshal(value.getLower(), buffer);
+ mNestedTypeMarshaler.marshal(value.getUpper(), buffer);
+ }
+
+ @Override
+ public Range<T> unmarshal(ByteBuffer buffer) {
+ T lower = mNestedTypeMarshaler.unmarshal(buffer);
+ T upper = mNestedTypeMarshaler.unmarshal(buffer);
+
+ try {
+ return mConstructor.newInstance(lower, upper);
+ } catch (InstantiationException e) {
+ throw new AssertionError(e);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(e);
+ } catch (IllegalArgumentException e) {
+ throw new AssertionError(e);
+ } catch (InvocationTargetException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public int getNativeSize() {
+ int nestedSize = mNestedTypeMarshaler.getNativeSize();
+
+ if (nestedSize != NATIVE_SIZE_DYNAMIC) {
+ return nestedSize * RANGE_COUNT;
+ } else {
+ return NATIVE_SIZE_DYNAMIC;
+ }
+ }
+
+ @Override
+ public int calculateMarshalSize(Range<T> value) {
+ int nativeSize = getNativeSize();
+
+ if (nativeSize != NATIVE_SIZE_DYNAMIC) {
+ return nativeSize;
+ } else {
+ int lowerSize = mNestedTypeMarshaler.calculateMarshalSize(value.getLower());
+ int upperSize = mNestedTypeMarshaler.calculateMarshalSize(value.getUpper());
+
+ return lowerSize + upperSize;
+ }
+ }
+ }
+
+ @Override
+ public Marshaler<Range<T>> createMarshaler(TypeReference<Range<T>> managedType,
+ int nativeType) {
+ return new MarshalerRange(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(TypeReference<Range<T>> managedType, int nativeType) {
+ return (Range.class.equals(managedType.getRawType()));
+ }
+
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRect.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRect.java
new file mode 100644
index 0000000..de20a1f
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRect.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.graphics.Rect;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import java.nio.ByteBuffer;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+/**
+ * Marshal {@link Rect} to/from {@link #TYPE_INT32}
+ */
+public class MarshalQueryableRect implements MarshalQueryable<Rect> {
+ private static final int SIZE = SIZEOF_INT32 * 4;
+
+ private class MarshalerRect extends Marshaler<Rect> {
+ protected MarshalerRect(TypeReference<Rect> typeReference,
+ int nativeType) {
+ super(MarshalQueryableRect.this, typeReference, nativeType);
+ }
+
+ @Override
+ public void marshal(Rect value, ByteBuffer buffer) {
+ buffer.putInt(value.left);
+ buffer.putInt(value.top);
+ buffer.putInt(value.width());
+ buffer.putInt(value.height());
+ }
+
+ @Override
+ public Rect unmarshal(ByteBuffer buffer) {
+ int left = buffer.getInt();
+ int top = buffer.getInt();
+ int width = buffer.getInt();
+ int height = buffer.getInt();
+
+ int right = left + width;
+ int bottom = top + height;
+
+ return new Rect(left, top, right, bottom);
+ }
+
+ @Override
+ public int getNativeSize() {
+ return SIZE;
+ }
+ }
+
+ @Override
+ public Marshaler<Rect> createMarshaler(TypeReference<Rect> managedType, int nativeType) {
+ return new MarshalerRect(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(TypeReference<Rect> managedType, int nativeType) {
+ return nativeType == TYPE_INT32 && (Rect.class.equals(managedType.getType()));
+ }
+
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableReprocessFormatsMap.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableReprocessFormatsMap.java
new file mode 100644
index 0000000..98a7ad7
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableReprocessFormatsMap.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.ReprocessFormatsMap;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.hardware.camera2.utils.TypeReference;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * Marshaler for {@code android.scaler.availableInputOutputFormatsMap} custom class
+ * {@link ReprocessFormatsMap}
+ */
+public class MarshalQueryableReprocessFormatsMap
+ implements MarshalQueryable<ReprocessFormatsMap> {
+
+ private class MarshalerReprocessFormatsMap extends Marshaler<ReprocessFormatsMap> {
+ protected MarshalerReprocessFormatsMap(
+ TypeReference<ReprocessFormatsMap> typeReference, int nativeType) {
+ super(MarshalQueryableReprocessFormatsMap.this, typeReference, nativeType);
+ }
+
+ @Override
+ public void marshal(ReprocessFormatsMap value, ByteBuffer buffer) {
+ /*
+ * // writing (static example, DNG+ZSL)
+ * int32_t[] contents = {
+ * RAW_OPAQUE, 3, RAW16, YUV_420_888, BLOB,
+ * RAW16, 2, YUV_420_888, BLOB,
+ * ...,
+ * INPUT_FORMAT, OUTPUT_FORMAT_COUNT, [OUTPUT_0, OUTPUT_1, ..., OUTPUT_FORMAT_COUNT-1]
+ * };
+ */
+ int[] inputs = StreamConfigurationMap.imageFormatToInternal(value.getInputs());
+ for (int input : inputs) {
+ // INPUT_FORMAT
+ buffer.putInt(input);
+
+ int[] outputs =
+ StreamConfigurationMap.imageFormatToInternal(value.getOutputs(input));
+ // OUTPUT_FORMAT_COUNT
+ buffer.putInt(outputs.length);
+
+ // [OUTPUT_0, OUTPUT_1, ..., OUTPUT_FORMAT_COUNT-1]
+ for (int output : outputs) {
+ buffer.putInt(output);
+ }
+ }
+ }
+
+ @Override
+ public ReprocessFormatsMap unmarshal(ByteBuffer buffer) {
+ int len = buffer.remaining() / SIZEOF_INT32;
+ if (buffer.remaining() % SIZEOF_INT32 != 0) {
+ throw new AssertionError("ReprocessFormatsMap was not TYPE_INT32");
+ }
+
+ int[] entries = new int[len];
+
+ IntBuffer intBuffer = buffer.asIntBuffer();
+ intBuffer.get(entries);
+
+ // TODO: consider moving rest of parsing code from ReprocessFormatsMap to here
+
+ return new ReprocessFormatsMap(entries);
+ }
+
+ @Override
+ public int getNativeSize() {
+ return NATIVE_SIZE_DYNAMIC;
+ }
+
+ @Override
+ public int calculateMarshalSize(ReprocessFormatsMap value) {
+ /*
+ * // writing (static example, DNG+ZSL)
+ * int32_t[] contents = {
+ * RAW_OPAQUE, 3, RAW16, YUV_420_888, BLOB,
+ * RAW16, 2, YUV_420_888, BLOB,
+ * ...,
+ * INPUT_FORMAT, OUTPUT_FORMAT_COUNT, [OUTPUT_0, OUTPUT_1, ..., OUTPUT_FORMAT_COUNT-1]
+ * };
+ */
+ int length = 0;
+
+ int[] inputs = value.getInputs();
+ for (int input : inputs) {
+
+ length += 1; // INPUT_FORMAT
+ length += 1; // OUTPUT_FORMAT_COUNT
+
+ int[] outputs = value.getOutputs(input);
+ length += outputs.length; // [OUTPUT_0, OUTPUT_1, ..., OUTPUT_FORMAT_COUNT-1]
+ }
+
+ return length * SIZEOF_INT32;
+ }
+ }
+
+ @Override
+ public Marshaler<ReprocessFormatsMap> createMarshaler(
+ TypeReference<ReprocessFormatsMap> managedType, int nativeType) {
+ return new MarshalerReprocessFormatsMap(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(TypeReference<ReprocessFormatsMap> managedType,
+ int nativeType) {
+ return nativeType == TYPE_INT32 && managedType.getType().equals(ReprocessFormatsMap.class);
+ }
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java
new file mode 100644
index 0000000..93c0e92
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.RggbChannelVector;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import java.nio.ByteBuffer;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+/**
+ * Marshal {@link RggbChannelVector} to/from {@link #TYPE_FLOAT} {@code x 4}
+ */
+public class MarshalQueryableRggbChannelVector implements MarshalQueryable<RggbChannelVector> {
+ private static final int SIZE = SIZEOF_FLOAT * RggbChannelVector.COUNT;
+
+ private class MarshalerRggbChannelVector extends Marshaler<RggbChannelVector> {
+ protected MarshalerRggbChannelVector(TypeReference<RggbChannelVector> typeReference,
+ int nativeType) {
+ super(MarshalQueryableRggbChannelVector.this, typeReference, nativeType);
+ }
+
+ @Override
+ public void marshal(RggbChannelVector value, ByteBuffer buffer) {
+ for (int i = 0; i < RggbChannelVector.COUNT; ++i) {
+ buffer.putFloat(value.getComponent(i));
+ }
+ }
+
+ @Override
+ public RggbChannelVector unmarshal(ByteBuffer buffer) {
+ float red = buffer.getFloat();
+ float gEven = buffer.getFloat();
+ float gOdd = buffer.getFloat();
+ float blue = buffer.getFloat();
+
+ return new RggbChannelVector(red, gEven, gOdd, blue);
+ }
+
+ @Override
+ public int getNativeSize() {
+ return SIZE;
+ }
+ }
+
+ @Override
+ public Marshaler<RggbChannelVector> createMarshaler(
+ TypeReference<RggbChannelVector> managedType, int nativeType) {
+ return new MarshalerRggbChannelVector(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(
+ TypeReference<RggbChannelVector> managedType, int nativeType) {
+ return nativeType == TYPE_FLOAT && (RggbChannelVector.class.equals(managedType.getType()));
+ }
+
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java
new file mode 100644
index 0000000..6a73bee
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.Size;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshal {@link Size} to/from {@code TYPE_INT32}
+ */
+public class MarshalQueryableSize implements MarshalQueryable<Size> {
+ private static final int SIZE = SIZEOF_INT32 * 2;
+
+ private class MarshalerSize extends Marshaler<Size> {
+ protected MarshalerSize(TypeReference<Size> typeReference, int nativeType) {
+ super(MarshalQueryableSize.this, typeReference, nativeType);
+ }
+
+ @Override
+ public void marshal(Size value, ByteBuffer buffer) {
+ buffer.putInt(value.getWidth());
+ buffer.putInt(value.getHeight());
+ }
+
+ @Override
+ public Size unmarshal(ByteBuffer buffer) {
+ int width = buffer.getInt();
+ int height = buffer.getInt();
+
+ return new Size(width, height);
+ }
+
+ @Override
+ public int getNativeSize() {
+ return SIZE;
+ }
+ }
+
+ @Override
+ public Marshaler<Size> createMarshaler(TypeReference<Size> managedType, int nativeType) {
+ return new MarshalerSize(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(TypeReference<Size> managedType, int nativeType) {
+ return nativeType == TYPE_INT32 && (Size.class.equals(managedType.getType()));
+ }
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSizeF.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSizeF.java
new file mode 100644
index 0000000..b60a46d
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSizeF.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+import android.util.SizeF;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshal {@link SizeF} to/from {@code TYPE_FLOAT}
+ */
+public class MarshalQueryableSizeF implements MarshalQueryable<SizeF> {
+
+ private static final int SIZE = SIZEOF_FLOAT * 2;
+
+ private class MarshalerSizeF extends Marshaler<SizeF> {
+
+ protected MarshalerSizeF(TypeReference<SizeF> typeReference, int nativeType) {
+ super(MarshalQueryableSizeF.this, typeReference, nativeType);
+ }
+
+ @Override
+ public void marshal(SizeF value, ByteBuffer buffer) {
+ buffer.putFloat(value.getWidth());
+ buffer.putFloat(value.getHeight());
+ }
+
+ @Override
+ public SizeF unmarshal(ByteBuffer buffer) {
+ float width = buffer.getFloat();
+ float height = buffer.getFloat();
+
+ return new SizeF(width, height);
+ }
+
+ @Override
+ public int getNativeSize() {
+ return SIZE;
+ }
+ }
+
+ @Override
+ public Marshaler<SizeF> createMarshaler(
+ TypeReference<SizeF> managedType, int nativeType) {
+ return new MarshalerSizeF(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(TypeReference<SizeF> managedType, int nativeType) {
+ return nativeType == TYPE_FLOAT && (SizeF.class.equals(managedType.getType()));
+ }
+}
+
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfiguration.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfiguration.java
new file mode 100644
index 0000000..62ace31
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfiguration.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.StreamConfiguration;
+import android.hardware.camera2.utils.TypeReference;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshaler for {@code android.scaler.availableStreamConfigurations} custom class
+ * {@link StreamConfiguration}
+ *
+ * <p>Data is stored as {@code (format, width, height, input?)} tuples (int32).</p>
+ */
+public class MarshalQueryableStreamConfiguration
+ implements MarshalQueryable<StreamConfiguration> {
+ private static final int SIZE = SIZEOF_INT32 * 4;
+
+ private class MarshalerStreamConfiguration extends Marshaler<StreamConfiguration> {
+ protected MarshalerStreamConfiguration(TypeReference<StreamConfiguration> typeReference,
+ int nativeType) {
+ super(MarshalQueryableStreamConfiguration.this, typeReference, nativeType);
+ }
+
+ @Override
+ public void marshal(StreamConfiguration value, ByteBuffer buffer) {
+ buffer.putInt(value.getFormat());
+ buffer.putInt(value.getWidth());
+ buffer.putInt(value.getHeight());
+ buffer.putInt(value.isInput() ? 1 : 0);
+ }
+
+ @Override
+ public StreamConfiguration unmarshal(ByteBuffer buffer) {
+ int format = buffer.getInt();
+ int width = buffer.getInt();
+ int height = buffer.getInt();
+ boolean input = buffer.getInt() != 0;
+
+ return new StreamConfiguration(format, width, height, input);
+ }
+
+ @Override
+ public int getNativeSize() {
+ return SIZE;
+ }
+
+ }
+
+ @Override
+ public Marshaler<StreamConfiguration> createMarshaler(
+ TypeReference<StreamConfiguration> managedType, int nativeType) {
+ return new MarshalerStreamConfiguration(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(TypeReference<StreamConfiguration> managedType,
+ int nativeType) {
+ return nativeType == TYPE_INT32 && managedType.getType().equals(StreamConfiguration.class);
+ }
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfigurationDuration.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfigurationDuration.java
new file mode 100644
index 0000000..fd3dfac
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfigurationDuration.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.StreamConfigurationDuration;
+import android.hardware.camera2.utils.TypeReference;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshaler for custom class {@link StreamConfigurationDuration} for min-frame and stall durations.
+ *
+ * <p>
+ * Data is stored as {@code (format, width, height, durationNs)} tuples (int64).
+ * </p>
+ */
+public class MarshalQueryableStreamConfigurationDuration
+ implements MarshalQueryable<StreamConfigurationDuration> {
+
+ private static final int SIZE = SIZEOF_INT64 * 4;
+ /**
+ * Values and-ed with this will do an unsigned int to signed long conversion;
+ * in other words the sign bit from the int will not be extended.
+ * */
+ private static final long MASK_UNSIGNED_INT = 0x00000000ffffffffL;
+
+ private class MarshalerStreamConfigurationDuration
+ extends Marshaler<StreamConfigurationDuration> {
+
+ protected MarshalerStreamConfigurationDuration(
+ TypeReference<StreamConfigurationDuration> typeReference, int nativeType) {
+ super(MarshalQueryableStreamConfigurationDuration.this, typeReference, nativeType);
+ }
+
+ @Override
+ public void marshal(StreamConfigurationDuration value, ByteBuffer buffer) {
+ buffer.putLong(value.getFormat() & MASK_UNSIGNED_INT); // unsigned int -> long
+ buffer.putLong(value.getWidth());
+ buffer.putLong(value.getHeight());
+ buffer.putLong(value.getDuration());
+ }
+
+ @Override
+ public StreamConfigurationDuration unmarshal(ByteBuffer buffer) {
+ int format = (int)buffer.getLong();
+ int width = (int)buffer.getLong();
+ int height = (int)buffer.getLong();
+ long durationNs = buffer.getLong();
+
+ return new StreamConfigurationDuration(format, width, height, durationNs);
+ }
+
+ @Override
+ public int getNativeSize() {
+ return SIZE;
+ }
+ }
+
+ @Override
+ public Marshaler<StreamConfigurationDuration> createMarshaler(
+ TypeReference<StreamConfigurationDuration> managedType, int nativeType) {
+ return new MarshalerStreamConfigurationDuration(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(TypeReference<StreamConfigurationDuration> managedType,
+ int nativeType) {
+ return nativeType == TYPE_INT64 &&
+ (StreamConfigurationDuration.class.equals(managedType.getType()));
+ }
+
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableString.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableString.java
new file mode 100644
index 0000000..bf518bb
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableString.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.utils.TypeReference;
+import android.util.Log;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+
+/**
+ * Marshal {@link String} to/from {@link #TYPE_BYTE}.
+ */
+public class MarshalQueryableString implements MarshalQueryable<String> {
+
+ private static final String TAG = MarshalQueryableString.class.getSimpleName();
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
+ private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
+ private static final byte NUL = (byte)'\0'; // used as string terminator
+
+ private class MarshalerString extends Marshaler<String> {
+
+ protected MarshalerString(TypeReference<String> typeReference, int nativeType) {
+ super(MarshalQueryableString.this, typeReference, nativeType);
+ }
+
+ @Override
+ public void marshal(String value, ByteBuffer buffer) {
+ byte[] arr = value.getBytes(UTF8_CHARSET);
+
+ buffer.put(arr);
+ buffer.put(NUL); // metadata strings are NUL-terminated
+ }
+
+ @Override
+ public int calculateMarshalSize(String value) {
+ byte[] arr = value.getBytes(UTF8_CHARSET);
+
+ return arr.length + 1; // metadata strings are NUL-terminated
+ }
+
+ @Override
+ public String unmarshal(ByteBuffer buffer) {
+ buffer.mark(); // save the current position
+
+ boolean foundNull = false;
+ int stringLength = 0;
+ while (buffer.hasRemaining()) {
+ if (buffer.get() == NUL) {
+ foundNull = true;
+ break;
+ }
+
+ stringLength++;
+ }
+
+ if (VERBOSE) {
+ Log.v(TAG,
+ "unmarshal - scanned " + stringLength + " characters; found null? "
+ + foundNull);
+ }
+
+ if (!foundNull) {
+ throw new UnsupportedOperationException("Strings must be null-terminated");
+ }
+
+ buffer.reset(); // go back to the previously marked position
+
+ byte[] strBytes = new byte[stringLength + 1];
+ buffer.get(strBytes, /*dstOffset*/0, stringLength + 1); // including null character
+
+ // not including null character
+ return new String(strBytes, /*offset*/0, stringLength, UTF8_CHARSET);
+ }
+
+ @Override
+ public int getNativeSize() {
+ return NATIVE_SIZE_DYNAMIC;
+ }
+ }
+
+ @Override
+ public Marshaler<String> createMarshaler(
+ TypeReference<String> managedType, int nativeType) {
+ return new MarshalerString(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(TypeReference<String> managedType, int nativeType) {
+ return nativeType == TYPE_BYTE && String.class.equals(managedType.getType());
+ }
+}
diff --git a/core/java/android/hardware/camera2/marshal/impl/package.html b/core/java/android/hardware/camera2/marshal/impl/package.html
new file mode 100644
index 0000000..783d0a1
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/package.html
@@ -0,0 +1,3 @@
+<body>
+{@hide}
+</body>
diff --git a/core/java/android/hardware/camera2/marshal/package.html b/core/java/android/hardware/camera2/marshal/package.html
new file mode 100644
index 0000000..783d0a1
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/package.html
@@ -0,0 +1,3 @@
+<body>
+{@hide}
+</body>
diff --git a/core/java/android/hardware/camera2/params/ReprocessFormatsMap.java b/core/java/android/hardware/camera2/params/ReprocessFormatsMap.java
new file mode 100644
index 0000000..d3f5bc3
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/ReprocessFormatsMap.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.params;
+
+import static com.android.internal.util.Preconditions.*;
+
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.utils.HashCodeHelpers;
+
+import java.util.Arrays;
+
+/**
+ * Immutable class to store the input to output formats
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP map} to be used for with
+ * camera image reprocessing.
+ *
+ * <p>
+ * The mapping of image formats that are supported by this camera device for input streams,
+ * to their corresponding output formats.</p>
+ *
+ * <p>
+ * Attempting to configure an input stream with output streams not listed as available in this map
+ * is not valid.
+ * </p>
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ *
+ * <!-- hide this until we expose input streams through public API -->
+ * @hide
+ */
+public final class ReprocessFormatsMap {
+ /**
+ * Create a new {@link ReprocessFormatsMap}
+ *
+ * <p>This value is encoded as a variable-size array-of-arrays.
+ * The inner array always contains {@code [format, length, ...]} where ... has length elements.
+ * An inner array is followed by another inner array if the total metadata entry size hasn't
+ * yet been exceeded.</p>
+ *
+ * <p>Entry must not be {@code null}. Empty array is acceptable.</p>
+ *
+ * <p>The entry array ownership is passed to this instance after construction; do not
+ * write to it afterwards.</p>
+ *
+ * @param entry Array of ints, not yet deserialized (not-null)
+ *
+ * @throws IllegalArgumentException
+ * if the data was poorly formatted
+ * (missing output format length or too few output formats)
+ * or if any of the input/formats were not valid
+ * @throws NullPointerException
+ * if entry was null
+ *
+ * @see StreamConfigurationMap#checkArgumentFormatInternal
+ *
+ * @hide
+ */
+ public ReprocessFormatsMap(final int[] entry) {
+ checkNotNull(entry, "entry must not be null");
+
+ int numInputs = 0;
+ int left = entry.length;
+ for (int i = 0; i < entry.length; ) {
+ int inputFormat = StreamConfigurationMap.checkArgumentFormatInternal(entry[i]);
+
+ left--;
+ i++;
+
+ if (left < 1) {
+ throw new IllegalArgumentException(
+ String.format("Input %x had no output format length listed", inputFormat));
+ }
+
+ final int length = entry[i];
+ left--;
+ i++;
+
+ for (int j = 0; j < length; ++j) {
+ int outputFormat = entry[i + j];
+ StreamConfigurationMap.checkArgumentFormatInternal(outputFormat);
+ }
+
+ if (length > 0) {
+ if (left < length) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Input %x had too few output formats listed (actual: %d, " +
+ "expected: %d)", inputFormat, left, length));
+ }
+
+ i += length;
+ left -= length;
+ }
+
+ numInputs++;
+ }
+
+ mEntry = entry;
+ mInputCount = numInputs;
+ }
+
+ /**
+ * Get a list of all input image formats that can be used to reprocess an input
+ * stream into an output stream.
+ *
+ * <p>Use this input format to look up the available output formats with {@link #getOutputs}.
+ * </p>
+ *
+ * @return an array of inputs (possibly empty, but never {@code null})
+ *
+ * @see ImageFormat
+ * @see #getOutputs
+ */
+ public int[] getInputs() {
+ final int[] inputs = new int[mInputCount];
+
+ int left = mEntry.length;
+ for (int i = 0, j = 0; i < mEntry.length; j++) {
+ final int format = mEntry[i];
+
+ left--;
+ i++;
+
+ if (left < 1) {
+ throw new AssertionError(
+ String.format("Input %x had no output format length listed", format));
+ }
+
+ final int length = mEntry[i];
+ left--;
+ i++;
+
+ if (length > 0) {
+ if (left < length) {
+ throw new AssertionError(
+ String.format(
+ "Input %x had too few output formats listed (actual: %d, " +
+ "expected: %d)", format, left, length));
+ }
+
+ i += length;
+ left -= length;
+ }
+
+ inputs[j] = format;
+ }
+
+ return StreamConfigurationMap.imageFormatToPublic(inputs);
+ }
+
+ /**
+ * Get the list of output formats that can be reprocessed into from the input {@code format}.
+ *
+ * <p>The input {@code format} must be one of the formats returned by {@link #getInputs}.</p>
+ *
+ * @param format an input format
+ *
+ * @return list of output image formats
+ *
+ * @see ImageFormat
+ * @see #getInputs
+ */
+ public int[] getOutputs(final int format) {
+
+ int left = mEntry.length;
+ for (int i = 0; i < mEntry.length; ) {
+ final int inputFormat = mEntry[i];
+
+ left--;
+ i++;
+
+ if (left < 1) {
+ throw new AssertionError(
+ String.format("Input %x had no output format length listed", format));
+ }
+
+ final int length = mEntry[i];
+ left--;
+ i++;
+
+ if (length > 0) {
+ if (left < length) {
+ throw new AssertionError(
+ String.format(
+ "Input %x had too few output formats listed (actual: %d, " +
+ "expected: %d)", format, left, length));
+ }
+ }
+
+ if (inputFormat == format) {
+ int[] outputs = new int[length];
+
+ // Copying manually faster than System.arraycopy for small arrays
+ for (int k = 0; k < length; ++k) {
+ outputs[k] = mEntry[i + k];
+ }
+
+ return StreamConfigurationMap.imageFormatToPublic(outputs);
+ }
+
+ i += length;
+ left -= length;
+
+ }
+
+ throw new IllegalArgumentException(
+ String.format("Input format %x was not one in #getInputs", format));
+ }
+
+ /**
+ * Check if this {@link ReprocessFormatsMap} is equal to another
+ * {@link ReprocessFormatsMap}.
+ *
+ * <p>These two objects are only equal if and only if each of the respective elements is equal.
+ * </p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof ReprocessFormatsMap) {
+ final ReprocessFormatsMap other = (ReprocessFormatsMap) obj;
+ // Do not compare anything besides mEntry, since the rest of the values are derived
+ return Arrays.equals(mEntry, other.mEntry);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ // Do not hash anything besides mEntry since the rest of the values are derived
+ return HashCodeHelpers.hashCode(mEntry);
+ }
+
+ private final int[] mEntry;
+ /*
+ * Dependent fields: values are derived from mEntry
+ */
+ private final int mInputCount;
+}
diff --git a/core/java/android/hardware/camera2/params/StreamConfiguration.java b/core/java/android/hardware/camera2/params/StreamConfiguration.java
new file mode 100644
index 0000000..1c6b6e9
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/StreamConfiguration.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.params;
+
+import static com.android.internal.util.Preconditions.*;
+import static android.hardware.camera2.params.StreamConfigurationMap.checkArgumentFormatInternal;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.utils.HashCodeHelpers;
+import android.graphics.PixelFormat;
+import android.util.Size;
+
+/**
+ * Immutable class to store the available stream
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS configurations} to be used
+ * when configuring streams with {@link CameraDevice#configureOutputs}.
+ * <!-- TODO: link to input stream configuration -->
+ *
+ * <p>This is the authoritative list for all input/output formats (and sizes respectively
+ * for that format) that are supported by a camera device.</p>
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ *
+ * @hide
+ */
+public final class StreamConfiguration {
+
+ /**
+ * Create a new {@link StreamConfiguration}.
+ *
+ * @param format image format
+ * @param width image width, in pixels (positive)
+ * @param height image height, in pixels (positive)
+ * @param input true if this is an input configuration, false for output configurations
+ *
+ * @throws IllegalArgumentException
+ * if width/height were not positive
+ * or if the format was not user-defined in ImageFormat/PixelFormat
+ * (IMPL_DEFINED is ok)
+ *
+ * @hide
+ */
+ public StreamConfiguration(
+ final int format, final int width, final int height, final boolean input) {
+ mFormat = checkArgumentFormatInternal(format);
+ mWidth = checkArgumentPositive(width, "width must be positive");
+ mHeight = checkArgumentPositive(height, "height must be positive");
+ mInput = input;
+ }
+
+ /**
+ * Get the internal image {@code format} in this stream configuration.
+ *
+ * @return an integer format
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public final int getFormat() {
+ return mFormat;
+ }
+
+
+ /**
+ * Return the width of the stream configuration.
+ *
+ * @return width > 0
+ */
+ public int getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * Return the height of the stream configuration.
+ *
+ * @return height > 0
+ */
+ public int getHeight() {
+ return mHeight;
+ }
+
+ /**
+ * Convenience method to return the size of this stream configuration.
+ *
+ * @return a Size with positive width and height
+ */
+ public Size getSize() {
+ return new Size(mWidth, mHeight);
+ }
+
+ /**
+ * Determines if this configuration is usable for input streams.
+ *
+ * <p>Input and output stream configurations are not interchangeable;
+ * input stream configurations must be used when configuring inputs.</p>
+ *
+ * @return {@code true} if input configuration, {@code false} otherwise
+ */
+ public boolean isInput() {
+ return mInput;
+ }
+
+ /**
+ * Determines if this configuration is usable for output streams.
+ *
+ * <p>Input and output stream configurations are not interchangeable;
+ * out stream configurations must be used when configuring outputs.</p>
+ *
+ * @return {@code true} if output configuration, {@code false} otherwise
+ *
+ * @see CameraDevice#configureOutputs
+ */
+ public boolean isOutput() {
+ return !mInput;
+ }
+
+ /**
+ * Check if this {@link StreamConfiguration} is equal to another {@link StreamConfiguration}.
+ *
+ * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof StreamConfiguration) {
+ final StreamConfiguration other = (StreamConfiguration) obj;
+ return mFormat == other.mFormat &&
+ mWidth == other.mWidth &&
+ mHeight == other.mHeight &&
+ mInput == other.mInput;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight, mInput ? 1 : 0);
+ }
+
+ private final int mFormat;
+ private final int mWidth;
+ private final int mHeight;
+ private final boolean mInput;
+}
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationDuration.java b/core/java/android/hardware/camera2/params/StreamConfigurationDuration.java
new file mode 100644
index 0000000..217059d
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationDuration.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.params;
+
+import static com.android.internal.util.Preconditions.*;
+import static android.hardware.camera2.params.StreamConfigurationMap.checkArgumentFormatInternal;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.utils.HashCodeHelpers;
+import android.graphics.PixelFormat;
+import android.util.Size;
+
+/**
+ * Immutable class to store a time duration for any given format/size combination.
+ *
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS
+ *
+ * @hide
+ */
+public final class StreamConfigurationDuration {
+
+ /**
+ * Create a new {@link StreamConfigurationDuration}.
+ *
+ * @param format image format
+ * @param width image width, in pixels (positive)
+ * @param height image height, in pixels (positive)
+ * @param durationNs duration in nanoseconds (non-negative)
+ *
+ * @throws IllegalArgumentException
+ * if width/height were not positive, or durationNs was negative
+ * or if the format was not user-defined in ImageFormat/PixelFormat
+ * (IMPL_DEFINED is OK)
+ *
+ *
+ * @hide
+ */
+ public StreamConfigurationDuration(
+ final int format, final int width, final int height, final long durationNs) {
+ mFormat = checkArgumentFormatInternal(format);
+ mWidth = checkArgumentPositive(width, "width must be positive");
+ mHeight = checkArgumentPositive(height, "height must be positive");
+ mDurationNs = checkArgumentNonnegative(durationNs, "durationNs must be non-negative");
+ }
+
+ /**
+ * Get the internal image {@code format} in this stream configuration duration
+ *
+ * @return an integer format
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public final int getFormat() {
+ return mFormat;
+ }
+
+
+ /**
+ * Return the width of the stream configuration duration.
+ *
+ * @return width > 0
+ */
+ public int getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * Return the height of the stream configuration duration
+ *
+ * @return height > 0
+ */
+ public int getHeight() {
+ return mHeight;
+ }
+
+ /**
+ * Convenience method to return the size of this stream configuration duration.
+ *
+ * @return a Size with positive width and height
+ */
+ public Size getSize() {
+ return new Size(mWidth, mHeight);
+ }
+
+ /**
+ * Get the time duration (in nanoseconds).
+ *
+ * @return long >= 0
+ */
+ public long getDuration() {
+ return mDurationNs;
+ }
+
+ /**
+ * Check if this {@link StreamConfigurationDuration} is equal to another
+ * {@link StreamConfigurationDuration}.
+ *
+ * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof StreamConfigurationDuration) {
+ final StreamConfigurationDuration other = (StreamConfigurationDuration) obj;
+ return mFormat == other.mFormat &&
+ mWidth == other.mWidth &&
+ mHeight == other.mHeight &&
+ mDurationNs == other.mDurationNs;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight,
+ (int) mDurationNs, (int)(mDurationNs >>> Integer.SIZE));
+ }
+
+ private final int mFormat;
+ private final int mWidth;
+ private final int mHeight;
+ private final long mDurationNs;
+}
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
new file mode 100644
index 0000000..4cd6d15
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -0,0 +1,949 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.params;
+
+import android.graphics.ImageFormat;
+import android.graphics.PixelFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.utils.HashCodeHelpers;
+import android.view.Surface;
+import android.util.Log;
+import android.util.Size;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Objects;
+
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Immutable class to store the available stream
+ * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP configurations} to be used
+ * when configuring streams with {@link CameraDevice#configureOutputs}.
+ * <!-- TODO: link to input stream configuration -->
+ *
+ * <p>This is the authoritative list for all <!-- input/ -->output formats (and sizes respectively
+ * for that format) that are supported by a camera device.</p>
+ *
+ * <p>This also contains the minimum frame durations and stall durations for each format/size
+ * combination that can be used to calculate effective frame rate when submitting multiple captures.
+ * </p>
+ *
+ * <p>An instance of this object is available from {@link CameraCharacteristics} using
+ * the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP} key and the
+ * {@link CameraCharacteristics#get} method.</p>
+ *
+ * <pre><code>{@code
+ * CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
+ * StreamConfigurationMap configs = characteristics.get(
+ * CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ * }</code></pre>
+ *
+ * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
+ * @see CameraDevice#configureOutputs
+ */
+public final class StreamConfigurationMap {
+
+ private static final String TAG = "StreamConfigurationMap";
+ /**
+ * Create a new {@link StreamConfigurationMap}.
+ *
+ * <p>The array parameters ownership is passed to this object after creation; do not
+ * write to them after this constructor is invoked.</p>
+ *
+ * @param configurations a non-{@code null} array of {@link StreamConfiguration}
+ * @param minFrameDurations a non-{@code null} array of {@link StreamConfigurationDuration}
+ * @param stallDurations a non-{@code null} array of {@link StreamConfigurationDuration}
+ *
+ * @throws NullPointerException if any of the arguments or subelements were {@code null}
+ *
+ * @hide
+ */
+ public StreamConfigurationMap(
+ StreamConfiguration[] configurations,
+ StreamConfigurationDuration[] minFrameDurations,
+ StreamConfigurationDuration[] stallDurations) {
+
+ mConfigurations = checkArrayElementsNotNull(configurations, "configurations");
+ mMinFrameDurations = checkArrayElementsNotNull(minFrameDurations, "minFrameDurations");
+ mStallDurations = checkArrayElementsNotNull(stallDurations, "stallDurations");
+
+ // For each format, track how many sizes there are available to configure
+ for (StreamConfiguration config : configurations) {
+ HashMap<Integer, Integer> map = config.isOutput() ? mOutputFormats : mInputFormats;
+
+ Integer count = map.get(config.getFormat());
+
+ if (count == null) {
+ count = 0;
+ }
+ count = count + 1;
+
+ map.put(config.getFormat(), count);
+ }
+
+ if (!mOutputFormats.containsKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)) {
+ throw new AssertionError(
+ "At least one stream configuration for IMPLEMENTATION_DEFINED must exist");
+ }
+ }
+
+ /**
+ * Get the image {@code format} output formats in this stream configuration.
+ *
+ * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
+ * or in {@link PixelFormat} (and there is no possibility of collision).</p>
+ *
+ * <p>Formats listed in this array are guaranteed to return true if queried with
+ * {@link #isOutputSupportedFor(int).</p>
+ *
+ * @return an array of integer format
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public final int[] getOutputFormats() {
+ return getPublicFormats(/*output*/true);
+ }
+
+ /**
+ * Get the image {@code format} input formats in this stream configuration.
+ *
+ * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
+ * or in {@link PixelFormat} (and there is no possibility of collision).</p>
+ *
+ * @return an array of integer format
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ *
+ * @hide
+ */
+ public final int[] getInputFormats() {
+ return getPublicFormats(/*output*/false);
+ }
+
+ /**
+ * Get the supported input sizes for this input format.
+ *
+ * <p>The format must have come from {@link #getInputFormats}; otherwise
+ * {@code null} is returned.</p>
+ *
+ * @param format a format from {@link #getInputFormats}
+ * @return a non-empty array of sizes, or {@code null} if the format was not available.
+ *
+ * @hide
+ */
+ public Size[] getInputSizes(final int format) {
+ return getPublicFormatSizes(format, /*output*/false);
+ }
+
+ /**
+ * Determine whether or not output streams can be
+ * {@link CameraDevice#configureOutputs configured} with a particular user-defined format.
+ *
+ * <p>This method determines that the output {@code format} is supported by the camera device;
+ * each output {@code surface} target may or may not itself support that {@code format}.
+ * Refer to the class which provides the surface for additional documentation.</p>
+ *
+ * <p>Formats for which this returns {@code true} are guaranteed to exist in the result
+ * returned by {@link #getOutputSizes}.</p>
+ *
+ * @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
+ * @return
+ * {@code true} iff using a {@code surface} with this {@code format} will be
+ * supported with {@link CameraDevice#configureOutputs}
+ *
+ * @throws IllegalArgumentException
+ * if the image format was not a defined named constant
+ * from either {@link ImageFormat} or {@link PixelFormat}
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ * @see CameraDevice#configureOutputs
+ */
+ public boolean isOutputSupportedFor(int format) {
+ checkArgumentFormat(format);
+
+ format = imageFormatToInternal(format);
+ return getFormatsMap(/*output*/true).containsKey(format);
+ }
+
+ /**
+ * Determine whether or not output streams can be configured with a particular class
+ * as a consumer.
+ *
+ * <p>The following list is generally usable for outputs:
+ * <ul>
+ * <li>{@link android.media.ImageReader} -
+ * Recommended for image processing or streaming to external resources (such as a file or
+ * network)
+ * <li>{@link android.media.MediaRecorder} -
+ * Recommended for recording video (simple to use)
+ * <li>{@link android.media.MediaCodec} -
+ * Recommended for recording video (more complicated to use, with more flexibility)
+ * <li>{@link android.renderscript.Allocation} -
+ * Recommended for image processing with {@link android.renderscript RenderScript}
+ * <li>{@link android.view.SurfaceHolder} -
+ * Recommended for low-power camera preview with {@link android.view.SurfaceView}
+ * <li>{@link android.graphics.SurfaceTexture} -
+ * Recommended for OpenGL-accelerated preview processing or compositing with
+ * {@link android.view.TextureView}
+ * </ul>
+ * </p>
+ *
+ * <p>Generally speaking this means that creating a {@link Surface} from that class <i>may</i>
+ * provide a producer endpoint that is suitable to be used with
+ * {@link CameraDevice#configureOutputs}.</p>
+ *
+ * <p>Since not all of the above classes support output of all format and size combinations,
+ * the particular combination should be queried with {@link #isOutputSupportedFor(Surface)}.</p>
+ *
+ * @param klass a non-{@code null} {@link Class} object reference
+ * @return {@code true} if this class is supported as an output, {@code false} otherwise
+ *
+ * @throws NullPointerException if {@code klass} was {@code null}
+ *
+ * @see CameraDevice#configureOutputs
+ * @see #isOutputSupportedFor(Surface)
+ */
+ public static <T> boolean isOutputSupportedFor(Class<T> klass) {
+ checkNotNull(klass, "klass must not be null");
+
+ if (klass == android.media.ImageReader.class) {
+ return true;
+ } else if (klass == android.media.MediaRecorder.class) {
+ return true;
+ } else if (klass == android.media.MediaCodec.class) {
+ return true;
+ } else if (klass == android.renderscript.Allocation.class) {
+ return true;
+ } else if (klass == android.view.SurfaceHolder.class) {
+ return true;
+ } else if (klass == android.graphics.SurfaceTexture.class) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Determine whether or not the {@code surface} in its current state is suitable to be
+ * {@link CameraDevice#configureOutputs configured} as an output.
+ *
+ * <p>Not all surfaces are usable with the {@link CameraDevice}, and not all configurations
+ * of that {@code surface} are compatible. Some classes that provide the {@code surface} are
+ * compatible with the {@link CameraDevice} in general
+ * (see {@link #isOutputSupportedFor(Class)}, but it is the caller's responsibility to put the
+ * {@code surface} into a state that will be compatible with the {@link CameraDevice}.</p>
+ *
+ * <p>Reasons for a {@code surface} being specifically incompatible might be:
+ * <ul>
+ * <li>Using a format that's not listed by {@link #getOutputFormats}
+ * <li>Using a format/size combination that's not listed by {@link #getOutputSizes}
+ * <li>The {@code surface} itself is not in a state where it can service a new producer.</p>
+ * </li>
+ * </ul>
+ *
+ * This is not an exhaustive list; see the particular class's documentation for further
+ * possible reasons of incompatibility.</p>
+ *
+ * @param surface a non-{@code null} {@link Surface} object reference
+ * @return {@code true} if this is supported, {@code false} otherwise
+ *
+ * @throws NullPointerException if {@code surface} was {@code null}
+ *
+ * @see CameraDevice#configureOutputs
+ * @see #isOutputSupportedFor(Class)
+ */
+ public boolean isOutputSupportedFor(Surface surface) {
+ checkNotNull(surface, "surface must not be null");
+
+ throw new UnsupportedOperationException("Not implemented yet");
+
+ // TODO: JNI function that checks the Surface's IGraphicBufferProducer state
+ }
+
+ /**
+ * Get a list of sizes compatible with {@code klass} to use as an output.
+ *
+ * <p>Since some of the supported classes may support additional formats beyond
+ * an opaque/implementation-defined (under-the-hood) format; this function only returns
+ * sizes for the implementation-defined format.</p>
+ *
+ * <p>Some classes such as {@link android.media.ImageReader} may only support user-defined
+ * formats; in particular {@link #isOutputSupportedFor(Class)} will return {@code true} for
+ * that class and this method will return an empty array (but not {@code null}).</p>
+ *
+ * <p>If a well-defined format such as {@code NV21} is required, use
+ * {@link #getOutputSizes(int)} instead.</p>
+ *
+ * <p>The {@code klass} should be a supported output, that querying
+ * {@code #isOutputSupportedFor(Class)} should return {@code true}.</p>
+ *
+ * @param klass
+ * a non-{@code null} {@link Class} object reference
+ * @return
+ * an array of supported sizes for implementation-defined formats,
+ * or {@code null} iff the {@code klass} is not a supported output
+ *
+ * @throws NullPointerException if {@code klass} was {@code null}
+ *
+ * @see #isOutputSupportedFor(Class)
+ */
+ public <T> Size[] getOutputSizes(Class<T> klass) {
+ if (isOutputSupportedFor(klass) == false) {
+ return null;
+ }
+
+ return getInternalFormatSizes(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, /*output*/true);
+ }
+
+ /**
+ * Get a list of sizes compatible with the requested image {@code format}.
+ *
+ * <p>The {@code format} should be a supported format (one of the formats returned by
+ * {@link #getOutputFormats}).</p>
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @return
+ * an array of supported sizes,
+ * or {@code null} if the {@code format} is not a supported output
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ * @see #getOutputFormats
+ */
+ public Size[] getOutputSizes(int format) {
+ return getPublicFormatSizes(format, /*output*/true);
+ }
+
+ /**
+ * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
+ * for the format/size combination (in nanoseconds).
+ *
+ * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p>
+ * <p>{@code size} should be one of the ones returned by
+ * {@link #getOutputSizes(int)}.</p>
+ *
+ * <p>This should correspond to the frame duration when only that stream is active, with all
+ * processing (typically in {@code android.*.mode}) set to either {@code OFF} or {@code FAST}.
+ * </p>
+ *
+ * <p>When multiple streams are used in a request, the minimum frame duration will be
+ * {@code max(individual stream min durations)}.</p>
+ *
+ * <!--
+ * TODO: uncomment after adding input stream support
+ * <p>The minimum frame duration of a stream (of a particular format, size) is the same
+ * regardless of whether the stream is input or output.</p>
+ * -->
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @param size an output-compatible size
+ * @return a minimum frame duration {@code >=} 0 in nanoseconds
+ *
+ * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} was {@code null}
+ *
+ * @see CaptureRequest#SENSOR_FRAME_DURATION
+ * @see #getOutputStallDuration(int, Size)
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public long getOutputMinFrameDuration(int format, Size size) {
+ checkNotNull(size, "size must not be null");
+ checkArgumentFormatSupported(format, /*output*/true);
+
+ return getInternalFormatDuration(imageFormatToInternal(format), size, DURATION_MIN_FRAME);
+ }
+
+ /**
+ * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
+ * for the class/size combination (in nanoseconds).
+ *
+ * <p>This assumes a the {@code klass} is set up to use an implementation-defined format.
+ * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
+ *
+ * <p>{@code klass} should be one of the ones which is supported by
+ * {@link #isOutputSupportedFor(Class)}.</p>
+ *
+ * <p>{@code size} should be one of the ones returned by
+ * {@link #getOutputSizes(int)}.</p>
+ *
+ * <p>This should correspond to the frame duration when only that stream is active, with all
+ * processing (typically in {@code android.*.mode}) set to either {@code OFF} or {@code FAST}.
+ * </p>
+ *
+ * <p>When multiple streams are used in a request, the minimum frame duration will be
+ * {@code max(individual stream min durations)}.</p>
+ *
+ * <!--
+ * TODO: uncomment after adding input stream support
+ * <p>The minimum frame duration of a stream (of a particular format, size) is the same
+ * regardless of whether the stream is input or output.</p>
+ * -->
+ *
+ * @param klass
+ * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a
+ * non-empty array returned by {@link #getOutputSizes(Class)}
+ * @param size an output-compatible size
+ * @return a minimum frame duration {@code >=} 0 in nanoseconds
+ *
+ * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
+ *
+ * @see CaptureRequest#SENSOR_FRAME_DURATION
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) {
+ if (!isOutputSupportedFor(klass)) {
+ throw new IllegalArgumentException("klass was not supported");
+ }
+
+ return getInternalFormatDuration(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+ size, DURATION_MIN_FRAME);
+ }
+
+ /**
+ * Get the stall duration for the format/size combination (in nanoseconds).
+ *
+ * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p>
+ * <p>{@code size} should be one of the ones returned by
+ * {@link #getOutputSizes(int)}.</p>
+ *
+ * <p>
+ * A stall duration is how much extra time would get added to the normal minimum frame duration
+ * for a repeating request that has streams with non-zero stall.
+ *
+ * <p>For example, consider JPEG captures which have the following characteristics:
+ *
+ * <ul>
+ * <li>JPEG streams act like processed YUV streams in requests for which they are not included;
+ * in requests in which they are directly referenced, they act as JPEG streams.
+ * This is because supporting a JPEG stream requires the underlying YUV data to always be ready
+ * for use by a JPEG encoder, but the encoder will only be used (and impact frame duration) on
+ * requests that actually reference a JPEG stream.
+ * <li>The JPEG processor can run concurrently to the rest of the camera pipeline, but cannot
+ * process more than 1 capture at a time.
+ * </ul>
+ *
+ * <p>In other words, using a repeating YUV request would result in a steady frame rate
+ * (let's say it's 30 FPS). If a single JPEG request is submitted periodically,
+ * the frame rate will stay at 30 FPS (as long as we wait for the previous JPEG to return each
+ * time). If we try to submit a repeating YUV + JPEG request, then the frame rate will drop from
+ * 30 FPS.</p>
+ *
+ * <p>In general, submitting a new request with a non-0 stall time stream will <em>not</em> cause a
+ * frame rate drop unless there are still outstanding buffers for that stream from previous
+ * requests.</p>
+ *
+ * <p>Submitting a repeating request with streams (call this {@code S}) is the same as setting
+ * the minimum frame duration from the normal minimum frame duration corresponding to {@code S},
+ * added with the maximum stall duration for {@code S}.</p>
+ *
+ * <p>If interleaving requests with and without a stall duration, a request will stall by the
+ * maximum of the remaining times for each can-stall stream with outstanding buffers.</p>
+ *
+ * <p>This means that a stalling request will not have an exposure start until the stall has
+ * completed.</p>
+ *
+ * <p>This should correspond to the stall duration when only that stream is active, with all
+ * processing (typically in {@code android.*.mode}) set to {@code FAST} or {@code OFF}.
+ * Setting any of the processing modes to {@code HIGH_QUALITY} effectively results in an
+ * indeterminate stall duration for all streams in a request (the regular stall calculation
+ * rules are ignored).</p>
+ *
+ * <p>The following formats may always have a stall duration:
+ * <ul>
+ * <li>{@link ImageFormat#JPEG JPEG}
+ * <li>{@link ImageFormat#RAW_SENSOR RAW16}
+ * </ul>
+ * </p>
+ *
+ * <p>The following formats will never have a stall duration:
+ * <ul>
+ * <li>{@link ImageFormat#YUV_420_888 YUV_420_888}
+ * <li>{@link #isOutputSupportedFor(Class) Implementation-Defined}
+ * </ul></p>
+ *
+ * <p>
+ * All other formats may or may not have an allowed stall duration on a per-capability basis;
+ * refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * android.request.availableCapabilities} for more details.</p>
+ * </p>
+ *
+ * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration}
+ * for more information about calculating the max frame rate (absent stalls).</p>
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @param size an output-compatible size
+ * @return a stall duration {@code >=} 0 in nanoseconds
+ *
+ * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} was {@code null}
+ *
+ * @see CaptureRequest#SENSOR_FRAME_DURATION
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public long getOutputStallDuration(int format, Size size) {
+ checkArgumentFormatSupported(format, /*output*/true);
+
+ return getInternalFormatDuration(imageFormatToInternal(format),
+ size, DURATION_STALL);
+ }
+
+ /**
+ * Get the stall duration for the class/size combination (in nanoseconds).
+ *
+ * <p>This assumes a the {@code klass} is set up to use an implementation-defined format.
+ * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
+ *
+ * <p>{@code klass} should be one of the ones with a non-empty array returned by
+ * {@link #getOutputSizes(Class)}.</p>
+ *
+ * <p>{@code size} should be one of the ones returned by
+ * {@link #getOutputSizes(Class)}.</p>
+ *
+ * <p>See {@link #getOutputStallDuration(int, Size)} for a definition of a
+ * <em>stall duration</em>.</p>
+ *
+ * @param klass
+ * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a
+ * non-empty array returned by {@link #getOutputSizes(Class)}
+ * @param size an output-compatible size
+ * @return a minimum frame duration {@code >=} 0 in nanoseconds
+ *
+ * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
+ *
+ * @see CaptureRequest#SENSOR_FRAME_DURATION
+ * @see ImageFormat
+ * @see PixelFormat
+ */
+ public <T> long getOutputStallDuration(final Class<T> klass, final Size size) {
+ if (!isOutputSupportedFor(klass)) {
+ throw new IllegalArgumentException("klass was not supported");
+ }
+
+ return getInternalFormatDuration(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+ size, DURATION_STALL);
+ }
+
+ /**
+ * Check if this {@link StreamConfigurationMap} is equal to another
+ * {@link StreamConfigurationMap}.
+ *
+ * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof StreamConfigurationMap) {
+ final StreamConfigurationMap other = (StreamConfigurationMap) obj;
+ // XX: do we care about order?
+ return Arrays.equals(mConfigurations, other.mConfigurations) &&
+ Arrays.equals(mMinFrameDurations, other.mMinFrameDurations) &&
+ Arrays.equals(mStallDurations, other.mStallDurations);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ // XX: do we care about order?
+ return HashCodeHelpers.hashCode(mConfigurations, mMinFrameDurations, mStallDurations);
+ }
+
+ // Check that the argument is supported by #getOutputFormats or #getInputFormats
+ private int checkArgumentFormatSupported(int format, boolean output) {
+ checkArgumentFormat(format);
+
+ int[] formats = output ? getOutputFormats() : getInputFormats();
+ for (int i = 0; i < formats.length; ++i) {
+ if (format == formats[i]) {
+ return format;
+ }
+ }
+
+ throw new IllegalArgumentException(String.format(
+ "format %x is not supported by this stream configuration map", format));
+ }
+
+ /**
+ * Ensures that the format is either user-defined or implementation defined.
+ *
+ * <p>If a format has a different internal representation than the public representation,
+ * passing in the public representation here will fail.</p>
+ *
+ * <p>For example if trying to use {@link ImageFormat#JPEG}:
+ * it has a different public representation than the internal representation
+ * {@code HAL_PIXEL_FORMAT_BLOB}, this check will fail.</p>
+ *
+ * <p>Any invalid/undefined formats will raise an exception.</p>
+ *
+ * @param format image format
+ * @return the format
+ *
+ * @throws IllegalArgumentException if the format was invalid
+ */
+ static int checkArgumentFormatInternal(int format) {
+ switch (format) {
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ case HAL_PIXEL_FORMAT_BLOB:
+ return format;
+ case ImageFormat.JPEG:
+ throw new IllegalArgumentException(
+ "ImageFormat.JPEG is an unknown internal format");
+ default:
+ return checkArgumentFormat(format);
+ }
+ }
+
+ /**
+ * Ensures that the format is publicly user-defined in either ImageFormat or PixelFormat.
+ *
+ * <p>If a format has a different public representation than the internal representation,
+ * passing in the internal representation here will fail.</p>
+ *
+ * <p>For example if trying to use {@code HAL_PIXEL_FORMAT_BLOB}:
+ * it has a different internal representation than the public representation
+ * {@link ImageFormat#JPEG}, this check will fail.</p>
+ *
+ * <p>Any invalid/undefined formats will raise an exception, including implementation-defined.
+ * </p>
+ *
+ * <p>Note that {@code @hide} and deprecated formats will not pass this check.</p>
+ *
+ * @param format image format
+ * @return the format
+ *
+ * @throws IllegalArgumentException if the format was not user-defined
+ */
+ static int checkArgumentFormat(int format) {
+ // TODO: remove this hack , CTS shouldn't have been using internal constants
+ if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
+ Log.w(TAG, "RAW_OPAQUE is not yet a published format; allowing it anyway");
+ return format;
+ }
+
+ if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
+ throw new IllegalArgumentException(String.format(
+ "format 0x%x was not defined in either ImageFormat or PixelFormat", format));
+ }
+
+ return format;
+ }
+
+ /**
+ * Convert a public-visible {@code ImageFormat} into an internal format
+ * compatible with {@code graphics.h}.
+ *
+ * <p>In particular these formats are converted:
+ * <ul>
+ * <li>HAL_PIXEL_FORMAT_BLOB => ImageFormat.JPEG
+ * </ul>
+ * </p>
+ *
+ * <p>Passing in an implementation-defined format which has no public equivalent will fail;
+ * as will passing in a public format which has a different internal format equivalent.
+ * See {@link #checkArgumentFormat} for more details about a legal public format.</p>
+ *
+ * <p>All other formats are returned as-is, no further invalid check is performed.</p>
+ *
+ * <p>This function is the dual of {@link #imageFormatToInternal}.</p>
+ *
+ * @param format image format from {@link ImageFormat} or {@link PixelFormat}
+ * @return the converted image formats
+ *
+ * @throws IllegalArgumentException
+ * if {@code format} is {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED} or
+ * {@link ImageFormat#JPEG}
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ * @see #checkArgumentFormat
+ */
+ static int imageFormatToPublic(int format) {
+ switch (format) {
+ case HAL_PIXEL_FORMAT_BLOB:
+ return ImageFormat.JPEG;
+ case ImageFormat.JPEG:
+ throw new IllegalArgumentException(
+ "ImageFormat.JPEG is an unknown internal format");
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ throw new IllegalArgumentException(
+ "IMPLEMENTATION_DEFINED must not leak to public API");
+ default:
+ return format;
+ }
+ }
+
+ /**
+ * Convert image formats from internal to public formats (in-place).
+ *
+ * @param formats an array of image formats
+ * @return {@code formats}
+ *
+ * @see #imageFormatToPublic
+ */
+ static int[] imageFormatToPublic(int[] formats) {
+ if (formats == null) {
+ return null;
+ }
+
+ for (int i = 0; i < formats.length; ++i) {
+ formats[i] = imageFormatToPublic(formats[i]);
+ }
+
+ return formats;
+ }
+
+ /**
+ * Convert a public format compatible with {@code ImageFormat} to an internal format
+ * from {@code graphics.h}.
+ *
+ * <p>In particular these formats are converted:
+ * <ul>
+ * <li>ImageFormat.JPEG => HAL_PIXEL_FORMAT_BLOB
+ * </ul>
+ * </p>
+ *
+ * <p>Passing in an implementation-defined format here will fail (it's not a public format);
+ * as will passing in an internal format which has a different public format equivalent.
+ * See {@link #checkArgumentFormat} for more details about a legal public format.</p>
+ *
+ * <p>All other formats are returned as-is, no invalid check is performed.</p>
+ *
+ * <p>This function is the dual of {@link #imageFormatToPublic}.</p>
+ *
+ * @param format public image format from {@link ImageFormat} or {@link PixelFormat}
+ * @return the converted image formats
+ *
+ * @see ImageFormat
+ * @see PixelFormat
+ *
+ * @throws IllegalArgumentException
+ * if {@code format} was {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED}
+ */
+ static int imageFormatToInternal(int format) {
+ switch (format) {
+ case ImageFormat.JPEG:
+ return HAL_PIXEL_FORMAT_BLOB;
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ throw new IllegalArgumentException(
+ "IMPLEMENTATION_DEFINED is not allowed via public API");
+ default:
+ return format;
+ }
+ }
+
+ /**
+ * Convert image formats from public to internal formats (in-place).
+ *
+ * @param formats an array of image formats
+ * @return {@code formats}
+ *
+ * @see #imageFormatToInternal
+ *
+ * @hide
+ */
+ public static int[] imageFormatToInternal(int[] formats) {
+ if (formats == null) {
+ return null;
+ }
+
+ for (int i = 0; i < formats.length; ++i) {
+ formats[i] = imageFormatToInternal(formats[i]);
+ }
+
+ return formats;
+ }
+
+ private Size[] getPublicFormatSizes(int format, boolean output) {
+ try {
+ checkArgumentFormatSupported(format, output);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+
+ format = imageFormatToInternal(format);
+
+ return getInternalFormatSizes(format, output);
+ }
+
+ private Size[] getInternalFormatSizes(int format, boolean output) {
+ HashMap<Integer, Integer> formatsMap = getFormatsMap(output);
+
+ Integer sizesCount = formatsMap.get(format);
+ if (sizesCount == null) {
+ throw new IllegalArgumentException("format not available");
+ }
+
+ int len = sizesCount;
+ Size[] sizes = new Size[len];
+ int sizeIndex = 0;
+
+ for (StreamConfiguration config : mConfigurations) {
+ if (config.getFormat() == format && config.isOutput() == output) {
+ sizes[sizeIndex++] = config.getSize();
+ }
+ }
+
+ if (sizeIndex != len) {
+ throw new AssertionError(
+ "Too few sizes (expected " + len + ", actual " + sizeIndex + ")");
+ }
+
+ return sizes;
+ }
+
+ /** Get the list of publically visible output formats; does not include IMPL_DEFINED */
+ private int[] getPublicFormats(boolean output) {
+ int[] formats = new int[getPublicFormatCount(output)];
+
+ int i = 0;
+
+ for (int format : getFormatsMap(output).keySet()) {
+ if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ formats[i++] = format;
+ }
+ }
+
+ if (formats.length != i) {
+ throw new AssertionError("Too few formats " + i + ", expected " + formats.length);
+ }
+
+ return imageFormatToPublic(formats);
+ }
+
+ /** Get the format -> size count map for either output or input formats */
+ private HashMap<Integer, Integer> getFormatsMap(boolean output) {
+ return output ? mOutputFormats : mInputFormats;
+ }
+
+ private long getInternalFormatDuration(int format, Size size, int duration) {
+ // assume format is already checked, since its internal
+
+ if (!arrayContains(getInternalFormatSizes(format, /*output*/true), size)) {
+ throw new IllegalArgumentException("size was not supported");
+ }
+
+ StreamConfigurationDuration[] durations = getDurations(duration);
+
+ for (StreamConfigurationDuration configurationDuration : durations) {
+ if (configurationDuration.getFormat() == format &&
+ configurationDuration.getWidth() == size.getWidth() &&
+ configurationDuration.getHeight() == size.getHeight()) {
+ return configurationDuration.getDuration();
+ }
+ }
+
+ return getDurationDefault(duration);
+ }
+
+ /**
+ * Get the durations array for the kind of duration
+ *
+ * @see #DURATION_MIN_FRAME
+ * @see #DURATION_STALL
+ * */
+ private StreamConfigurationDuration[] getDurations(int duration) {
+ switch (duration) {
+ case DURATION_MIN_FRAME:
+ return mMinFrameDurations;
+ case DURATION_STALL:
+ return mStallDurations;
+ default:
+ throw new IllegalArgumentException("duration was invalid");
+ }
+ }
+
+ private long getDurationDefault(int duration) {
+ switch (duration) {
+ case DURATION_MIN_FRAME:
+ throw new AssertionError("Minimum frame durations are required to be listed");
+ case DURATION_STALL:
+ return 0L; // OK. A lack of a stall duration implies a 0 stall duration
+ default:
+ throw new IllegalArgumentException("duration was invalid");
+ }
+ }
+
+ /** Count the number of publicly-visible output formats */
+ private int getPublicFormatCount(boolean output) {
+ HashMap<Integer, Integer> formatsMap = getFormatsMap(output);
+
+ int size = formatsMap.size();
+ if (formatsMap.containsKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)) {
+ size -= 1;
+ }
+ return size;
+ }
+
+ private static <T> boolean arrayContains(T[] array, T element) {
+ if (array == null) {
+ return false;
+ }
+
+ for (T el : array) {
+ if (Objects.equals(el, element)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // from system/core/include/system/graphics.h
+ private static final int HAL_PIXEL_FORMAT_BLOB = 0x21;
+ private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
+ private static final int HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24;
+
+ /**
+ * @see #getDurations(int)
+ * @see #getDurationDefault(int)
+ */
+ private static final int DURATION_MIN_FRAME = 0;
+ private static final int DURATION_STALL = 1;
+
+ private final StreamConfiguration[] mConfigurations;
+ private final StreamConfigurationDuration[] mMinFrameDurations;
+ private final StreamConfigurationDuration[] mStallDurations;
+
+ /** ImageFormat -> num output sizes mapping */
+ private final HashMap</*ImageFormat*/Integer, /*Count*/Integer> mOutputFormats =
+ new HashMap<Integer, Integer>();
+ /** ImageFormat -> num input sizes mapping */
+ private final HashMap</*ImageFormat*/Integer, /*Count*/Integer> mInputFormats =
+ new HashMap<Integer, Integer>();
+
+}
diff --git a/core/java/android/hardware/camera2/utils/HashCodeHelpers.java b/core/java/android/hardware/camera2/utils/HashCodeHelpers.java
new file mode 100644
index 0000000..b980549
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/HashCodeHelpers.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.utils;
+
+/**
+ * Provide hashing functions using the Modified Bernstein hash
+ */
+public final class HashCodeHelpers {
+
+ /**
+ * Hash every element uniformly using the Modified Bernstein hash.
+ *
+ * <p>Useful to implement a {@link Object#hashCode} for uniformly distributed data.</p>
+ *
+ * @param array a non-{@code null} array of integers
+ *
+ * @return the numeric hash code
+ */
+ public static int hashCode(int[] array) {
+ if (array == null) {
+ return 0;
+ }
+
+ /*
+ * Note that we use 31 here instead of 33 since it's preferred in Effective Java
+ * and used elsewhere in the runtime (e.g. Arrays#hashCode)
+ *
+ * That being said 33 and 31 are nearly identical in terms of their usefulness
+ * according to http://svn.apache.org/repos/asf/apr/apr/trunk/tables/apr_hash.c
+ */
+ int h = 1;
+ for (int x : array) {
+ // Strength reduction; in case the compiler has illusions about divisions being faster
+ h = ((h << 5) - h) ^ x; // (h * 31) XOR x
+ }
+
+ return h;
+ }
+
+ /**
+ * Hash every element uniformly using the Modified Bernstein hash.
+ *
+ * <p>Useful to implement a {@link Object#hashCode} for uniformly distributed data.</p>
+ *
+ * @param array a non-{@code null} array of floats
+ *
+ * @return the numeric hash code
+ */
+ public static int hashCode(float[] array) {
+ if (array == null) {
+ return 0;
+ }
+
+ int h = 1;
+ for (float f : array) {
+ int x = Float.floatToIntBits(f);
+ h = ((h << 5) - h) ^ x; // (h * 31) XOR x
+ }
+
+ return h;
+ }
+
+ /**
+ * Hash every element uniformly using the Modified Bernstein hash.
+ *
+ * <p>Useful to implement a {@link Object#hashCode} for uniformly distributed data.</p>
+ *
+ * @param array a non-{@code null} array of objects
+ *
+ * @return the numeric hash code
+ */
+ public static <T> int hashCode(T[] array) {
+ if (array == null) {
+ return 0;
+ }
+
+ int h = 1;
+ for (T o : array) {
+ int x = (o == null) ? 0 : o.hashCode();
+ h = ((h << 5) - h) ^ x; // (h * 31) XOR x
+ }
+
+ return h;
+ }
+
+ public static <T> int hashCode(T a) {
+ return (a == null) ? 0 : a.hashCode();
+ }
+
+ public static <T> int hashCode(T a, T b) {
+ int h = hashCode(a);
+
+ int x = (b == null) ? 0 : b.hashCode();
+ h = ((h << 5) - h) ^ x; // (h * 31) XOR x
+
+ return h;
+ }
+
+ public static <T> int hashCode(T a, T b, T c) {
+ int h = hashCode(a, b);
+
+ int x = (a == null) ? 0 : a.hashCode();
+ h = ((h << 5) - h) ^ x; // (h * 31) XOR x
+
+ return h;
+ }
+
+ public static int hashCode(int x) {
+ return hashCode(new int[] { x } );
+ }
+
+ public static int hashCode(int x, int y) {
+ return hashCode(new int[] { x, y } );
+ }
+
+ public static int hashCode(int x, int y, int z) {
+ return hashCode(new int[] { x, y, z } );
+ }
+
+ public static int hashCode(int x, int y, int z, int w) {
+ return hashCode(new int[] { x, y, z, w } );
+ }
+
+ public static int hashCode(int x, int y, int z, int w, int t) {
+ return hashCode(new int[] { x, y, z, w, t } );
+ }
+
+
+}
diff --git a/core/java/android/hardware/camera2/utils/LongParcelable.aidl b/core/java/android/hardware/camera2/utils/LongParcelable.aidl
new file mode 100644
index 0000000..98ad1b2
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/LongParcelable.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.utils;
+
+/** @hide */
+parcelable LongParcelable;
diff --git a/core/java/android/hardware/camera2/utils/LongParcelable.java b/core/java/android/hardware/camera2/utils/LongParcelable.java
new file mode 100644
index 0000000..c89b339
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/LongParcelable.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.utils;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+public class LongParcelable implements Parcelable {
+ private long number;
+
+ public LongParcelable() {
+ this.number = 0;
+ }
+
+ public LongParcelable(long number) {
+ this.number = number;
+ }
+
+ public static final Parcelable.Creator<LongParcelable> CREATOR =
+ new Parcelable.Creator<LongParcelable>() {
+ @Override
+ public LongParcelable createFromParcel(Parcel in) {
+ return new LongParcelable(in);
+ }
+
+ @Override
+ public LongParcelable[] newArray(int size) {
+ return new LongParcelable[size];
+ }
+ };
+
+ private LongParcelable(Parcel in) {
+ readFromParcel(in);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(number);
+ }
+
+ public void readFromParcel(Parcel in) {
+ number = in.readLong();
+ }
+
+ public long getNumber() {
+ return number;
+ }
+
+ public void setNumber(long number) {
+ this.number = number;
+ }
+
+}
diff --git a/core/java/android/hardware/camera2/utils/TypeReference.java b/core/java/android/hardware/camera2/utils/TypeReference.java
new file mode 100644
index 0000000..d0c919c
--- /dev/null
+++ b/core/java/android/hardware/camera2/utils/TypeReference.java
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.utils;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Super type token; allows capturing generic types at runtime by forcing them to be reified.
+ *
+ * <p>Usage example: <pre>{@code
+ * // using anonymous classes (preferred)
+ * TypeReference<Integer> intToken = new TypeReference<Integer>() {{ }};
+ *
+ * // using named classes
+ * class IntTypeReference extends TypeReference<Integer> {...}
+ * TypeReference<Integer> intToken = new IntTypeReference();
+ * }</p></pre>
+ *
+ * <p>Unlike the reference implementation, this bans nested TypeVariables; that is all
+ * dynamic types must equal to the static types.</p>
+ *
+ * <p>See <a href="http://gafter.blogspot.com/2007/05/limitation-of-super-type-tokens.html">
+ * http://gafter.blogspot.com/2007/05/limitation-of-super-type-tokens.html</a>
+ * for more details.</p>
+ */
+public abstract class TypeReference<T> {
+ private final Type mType;
+
+ /**
+ * Create a new type reference for {@code T}.
+ *
+ * @throws IllegalArgumentException if {@code T}'s actual type contains a type variable
+ *
+ * @see TypeReference
+ */
+ protected TypeReference() {
+ ParameterizedType thisType = (ParameterizedType)getClass().getGenericSuperclass();
+
+ // extract the "T" from TypeReference<T>
+ mType = thisType.getActualTypeArguments()[0];
+
+ /*
+ * Prohibit type references with type variables such as
+ *
+ * class GenericListToken<T> extends TypeReference<List<T>>
+ *
+ * Since the "T" there is not known without an instance of T, type equality would
+ * consider *all* Lists equal regardless of T. Allowing this would defeat
+ * some of the type safety of a type reference.
+ */
+ if (containsTypeVariable(mType)) {
+ throw new IllegalArgumentException(
+ "Including a type variable in a type reference is not allowed");
+ }
+ }
+
+ /**
+ * Return the dynamic {@link Type} corresponding to the captured type {@code T}.
+ */
+ public Type getType() {
+ return mType;
+ }
+
+ private TypeReference(Type type) {
+ mType = type;
+
+ if (containsTypeVariable(mType)) {
+ throw new IllegalArgumentException(
+ "Including a type variable in a type reference is not allowed");
+ }
+ }
+
+ private static class SpecializedTypeReference<T> extends TypeReference<T> {
+ public SpecializedTypeReference(Class<T> klass) {
+ super(klass);
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ private static class SpecializedBaseTypeReference extends TypeReference {
+ public SpecializedBaseTypeReference(Type type) {
+ super(type);
+ }
+ }
+
+ /**
+ * Create a specialized type reference from a dynamic class instance,
+ * bypassing the standard compile-time checks.
+ *
+ * <p>As with a regular type reference, the {@code klass} must not contain
+ * any type variables.</p>
+ *
+ * @param klass a non-{@code null} {@link Class} instance
+ *
+ * @return a type reference which captures {@code T} at runtime
+ *
+ * @throws IllegalArgumentException if {@code T} had any type variables
+ */
+ public static <T> TypeReference<T> createSpecializedTypeReference(Class<T> klass) {
+ return new SpecializedTypeReference<T>(klass);
+ }
+
+ /**
+ * Create a specialized type reference from a dynamic {@link Type} instance,
+ * bypassing the standard compile-time checks.
+ *
+ * <p>As with a regular type reference, the {@code type} must not contain
+ * any type variables.</p>
+ *
+ * @param type a non-{@code null} {@link Type} instance
+ *
+ * @return a type reference which captures {@code T} at runtime
+ *
+ * @throws IllegalArgumentException if {@code type} had any type variables
+ */
+ public static TypeReference<?> createSpecializedTypeReference(Type type) {
+ return new SpecializedBaseTypeReference(type);
+ }
+
+ /**
+ * Returns the raw type of T.
+ *
+ * <p><ul>
+ * <li>If T is a Class itself, T itself is returned.
+ * <li>If T is a ParameterizedType, the raw type of the parameterized type is returned.
+ * <li>If T is a GenericArrayType, the returned type is the corresponding array class.
+ * For example: {@code List<Integer>[]} => {@code List[]}.
+ * <li>If T is a type variable or a wildcard type, the raw type of the first upper bound is
+ * returned. For example: {@code <X extends Foo>} => {@code Foo}.
+ * </ul>
+ *
+ * @return the raw type of {@code T}
+ */
+ @SuppressWarnings("unchecked")
+ public final Class<? super T> getRawType() {
+ return (Class<? super T>)getRawType(mType);
+ }
+
+ private static final Class<?> getRawType(Type type) {
+ if (type == null) {
+ throw new NullPointerException("type must not be null");
+ }
+
+ if (type instanceof Class<?>) {
+ return (Class<?>)type;
+ } else if (type instanceof ParameterizedType) {
+ return (Class<?>)(((ParameterizedType)type).getRawType());
+ } else if (type instanceof GenericArrayType) {
+ return getArrayClass(getRawType(((GenericArrayType)type).getGenericComponentType()));
+ } else if (type instanceof WildcardType) {
+ // Should be at most 1 upper bound, but treat it like an array for simplicity
+ return getRawType(((WildcardType) type).getUpperBounds());
+ } else if (type instanceof TypeVariable) {
+ throw new AssertionError("Type variables are not allowed in type references");
+ } else {
+ // Impossible
+ throw new AssertionError("Unhandled branch to get raw type for type " + type);
+ }
+ }
+
+ private static final Class<?> getRawType(Type[] types) {
+ if (types == null) {
+ return null;
+ }
+
+ for (Type type : types) {
+ Class<?> klass = getRawType(type);
+ if (klass != null) {
+ return klass;
+ }
+ }
+
+ return null;
+ }
+
+ private static final Class<?> getArrayClass(Class<?> componentType) {
+ return Array.newInstance(componentType, 0).getClass();
+ }
+
+ /**
+ * Get the component type, e.g. {@code T} from {@code T[]}.
+ *
+ * @return component type, or {@code null} if {@code T} is not an array
+ */
+ public TypeReference<?> getComponentType() {
+ Type componentType = getComponentType(mType);
+
+ return (componentType != null) ?
+ createSpecializedTypeReference(componentType) :
+ null;
+ }
+
+ private static Type getComponentType(Type type) {
+ checkNotNull(type, "type must not be null");
+
+ if (type instanceof Class<?>) {
+ return ((Class<?>) type).getComponentType();
+ } else if (type instanceof ParameterizedType) {
+ return null;
+ } else if (type instanceof GenericArrayType) {
+ return ((GenericArrayType)type).getGenericComponentType();
+ } else if (type instanceof WildcardType) {
+ // Should be at most 1 upper bound, but treat it like an array for simplicity
+ throw new UnsupportedOperationException("TODO: support wild card components");
+ } else if (type instanceof TypeVariable) {
+ throw new AssertionError("Type variables are not allowed in type references");
+ } else {
+ // Impossible
+ throw new AssertionError("Unhandled branch to get component type for type " + type);
+ }
+ }
+
+ /**
+ * Compare two objects for equality.
+ *
+ * <p>A TypeReference is only equal to another TypeReference if their captured type {@code T}
+ * is also equal.</p>
+ */
+ @Override
+ public boolean equals(Object o) {
+ // Note that this comparison could inaccurately return true when comparing types
+ // with nested type variables; therefore we ban type variables in the constructor.
+ return o instanceof TypeReference<?> && mType.equals(((TypeReference<?>)o).mType);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return mType.hashCode();
+ }
+
+ /**
+ * Check if the {@code type} contains a {@link TypeVariable} recursively.
+ *
+ * <p>Intuitively, a type variable is a type in a type expression that refers to a generic
+ * type which is not known at the definition of the expression (commonly seen when
+ * type parameters are used, e.g. {@code class Foo<T>}).</p>
+ *
+ * <p>See <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.4">
+ * http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.4</a>
+ * for a more formal definition of a type variable</p>.
+ *
+ * @param type a type object ({@code null} is allowed)
+ * @return {@code true} if there were nested type variables; {@code false} otherwise
+ */
+ public static boolean containsTypeVariable(Type type) {
+ if (type == null) {
+ // Trivially false
+ return false;
+ } else if (type instanceof TypeVariable<?>) {
+ /*
+ * T -> trivially true
+ */
+ return true;
+ } else if (type instanceof Class<?>) {
+ /*
+ * class Foo -> no type variable
+ * class Foo<T> - has a type variable
+ *
+ * This also covers the case of class Foo<T> extends ... / implements ...
+ * since everything on the right hand side would either include a type variable T
+ * or have no type variables.
+ */
+ Class<?> klass = (Class<?>)type;
+
+ // Empty array => class is not generic
+ if (klass.getTypeParameters().length != 0) {
+ return true;
+ } else {
+ // Does the outer class(es) contain any type variables?
+
+ /*
+ * class Outer<T> {
+ * class Inner {
+ * T field;
+ * }
+ * }
+ *
+ * In this case 'Inner' has no type parameters itself, but it still has a type
+ * variable as part of the type definition.
+ */
+ return containsTypeVariable(klass.getDeclaringClass());
+ }
+ } else if (type instanceof ParameterizedType) {
+ /*
+ * This is the "Foo<T1, T2, T3, ... Tn>" in the scope of a
+ *
+ * // no type variables here, T1-Tn are known at this definition
+ * class X extends Foo<T1, T2, T3, ... Tn>
+ *
+ * // T1 is a type variable, T2-Tn are known at this definition
+ * class X<T1> extends Foo<T1, T2, T3, ... Tn>
+ */
+ ParameterizedType p = (ParameterizedType) type;
+
+ // This needs to be recursively checked
+ for (Type arg : p.getActualTypeArguments()) {
+ if (containsTypeVariable(arg)) {
+ return true;
+ }
+ }
+
+ return false;
+ } else if (type instanceof WildcardType) {
+ WildcardType wild = (WildcardType) type;
+
+ /*
+ * This is is the "?" inside of a
+ *
+ * Foo<?> --> unbounded; trivially no type variables
+ * Foo<? super T> --> lower bound; does T have a type variable?
+ * Foo<? extends T> --> upper bound; does T have a type variable?
+ */
+
+ /*
+ * According to JLS 4.5.1
+ * (http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.5.1):
+ *
+ * - More than 1 lower/upper bound is illegal
+ * - Both a lower and upper bound is illegal
+ *
+ * However, we use this 'array OR array' approach for readability
+ */
+ return containsTypeVariable(wild.getLowerBounds()) ||
+ containsTypeVariable(wild.getUpperBounds());
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("TypeReference<");
+ toString(getType(), builder);
+ builder.append(">");
+
+ return builder.toString();
+ }
+
+ private static void toString(Type type, StringBuilder out) {
+ if (type == null) {
+ return;
+ } else if (type instanceof TypeVariable<?>) {
+ // T
+ out.append(((TypeVariable<?>)type).getName());
+ } else if (type instanceof Class<?>) {
+ Class<?> klass = (Class<?>)type;
+
+ out.append(klass.getName());
+ toString(klass.getTypeParameters(), out);
+ } else if (type instanceof ParameterizedType) {
+ // "Foo<T1, T2, T3, ... Tn>"
+ ParameterizedType p = (ParameterizedType) type;
+
+ out.append(((Class<?>)p.getRawType()).getName());
+ toString(p.getActualTypeArguments(), out);
+ } else if (type instanceof GenericArrayType) {
+ GenericArrayType gat = (GenericArrayType)type;
+
+ toString(gat.getGenericComponentType(), out);
+ out.append("[]");
+ } else { // WildcardType, BoundedType
+ // TODO:
+ out.append(type.toString());
+ }
+ }
+
+ private static void toString(Type[] types, StringBuilder out) {
+ if (types == null) {
+ return;
+ } else if (types.length == 0) {
+ return;
+ }
+
+ out.append("<");
+
+ for (int i = 0; i < types.length; ++i) {
+ toString(types[i], out);
+ if (i != types.length - 1) {
+ out.append(", ");
+ }
+ }
+
+ out.append(">");
+ }
+
+ /**
+ * Check if any of the elements in this array contained a type variable.
+ *
+ * <p>Empty and null arrays trivially have no type variables.</p>
+ *
+ * @param typeArray an array ({@code null} is ok) of types
+ * @return true if any elements contained a type variable; false otherwise
+ */
+ private static boolean containsTypeVariable(Type[] typeArray) {
+ if (typeArray == null) {
+ return false;
+ }
+
+ for (Type type : typeArray) {
+ if (containsTypeVariable(type)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index cec90cd..e58c54d 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -156,6 +156,9 @@
// If true, enables automatic brightness control.
public boolean useAutoBrightness;
+ //If true, scales the brightness to half of desired.
+ public boolean lowPowerMode;
+
// If true, prevents the screen from completely turning on if it is currently off.
// The display does not enter a "ready" state if this flag is true and screen on is
// blocked. The window manager policy blocks screen on while it prepares the keyguard to
@@ -203,6 +206,7 @@
screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment;
useAutoBrightness = other.useAutoBrightness;
blockScreenOn = other.blockScreenOn;
+ lowPowerMode = other.lowPowerMode;
}
@Override
@@ -218,7 +222,8 @@
&& screenBrightness == other.screenBrightness
&& screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment
&& useAutoBrightness == other.useAutoBrightness
- && blockScreenOn == other.blockScreenOn;
+ && blockScreenOn == other.blockScreenOn
+ && lowPowerMode == other.lowPowerMode;
}
@Override
@@ -233,7 +238,8 @@
+ ", screenBrightness=" + screenBrightness
+ ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment
+ ", useAutoBrightness=" + useAutoBrightness
- + ", blockScreenOn=" + blockScreenOn;
+ + ", blockScreenOn=" + blockScreenOn
+ + ", lowPowerMode=" + lowPowerMode;
}
}
diff --git a/core/java/android/net/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java
index 804f8ee..79db389 100644
--- a/core/java/android/net/BaseNetworkStateTracker.java
+++ b/core/java/android/net/BaseNetworkStateTracker.java
@@ -44,7 +44,8 @@
protected NetworkInfo mNetworkInfo;
protected LinkProperties mLinkProperties;
- protected LinkCapabilities mLinkCapabilities;
+ protected NetworkCapabilities mNetworkCapabilities;
+ protected Network mNetwork = new Network(ConnectivityManager.INVALID_NET_ID);
private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
@@ -54,7 +55,7 @@
mNetworkInfo = new NetworkInfo(
networkType, -1, ConnectivityManager.getNetworkTypeName(networkType), null);
mLinkProperties = new LinkProperties();
- mLinkCapabilities = new LinkCapabilities();
+ mNetworkCapabilities = new NetworkCapabilities();
}
protected BaseNetworkStateTracker() {
@@ -98,8 +99,8 @@
}
@Override
- public LinkCapabilities getLinkCapabilities() {
- return new LinkCapabilities(mLinkCapabilities);
+ public NetworkCapabilities getNetworkCapabilities() {
+ return new NetworkCapabilities(mNetworkCapabilities);
}
@Override
@@ -201,4 +202,14 @@
public void stopSampling(SamplingDataTracker.SamplingSnapshot s) {
// nothing to do
}
+
+ @Override
+ public void setNetId(int netId) {
+ mNetwork = new Network(netId);
+ }
+
+ @Override
+ public Network getNetwork() {
+ return mNetwork;
+ }
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 30d7043..a414421 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -13,26 +13,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package android.net;
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.app.PendingIntent;
import android.content.Context;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.INetworkActivityListener;
import android.os.INetworkManagementService;
+import android.os.Looper;
+import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.util.ArrayMap;
+import android.util.Log;
import java.net.InetAddress;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.HashMap;
+
+import com.android.internal.util.Protocol;
/**
* Class that answers queries about the state of network connectivity. It also
@@ -408,6 +417,11 @@
*/
public static final int CONNECTIVITY_CHANGE_DELAY_DEFAULT = 3000;
+ /**
+ * @hide
+ */
+ public final static int INVALID_NET_ID = 0;
+
private final IConnectivityManager mService;
private final String mPackageName;
@@ -529,26 +543,21 @@
/**
* Specifies the preferred network type. When the device has more
* than one type available the preferred network type will be used.
- * Note that this made sense when we only had 2 network types,
- * but with more and more default networks we need an array to list
- * their ordering. This will be deprecated soon.
*
* @param preference the network type to prefer over all others. It is
* unspecified what happens to the old preferred network in the
* overall ordering.
*/
public void setNetworkPreference(int preference) {
- try {
- mService.setNetworkPreference(preference);
- } catch (RemoteException e) {
- }
+ // TODO - deprecate with:
+ // @deprecated Functionality has been removed as it no longer makes sense,
+ // with many more than two networks - we'd need an array to express
+ // preference. Instead we use dynamic network properties of
+ // the networks to describe their precedence.
}
/**
* Retrieves the current preferred network type.
- * Note that this made sense when we only had 2 network types,
- * but with more and more default networks we need an array to list
- * their ordering. This will be deprecated soon.
*
* @return an integer representing the preferred network type
*
@@ -556,11 +565,12 @@
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
*/
public int getNetworkPreference() {
- try {
- return mService.getNetworkPreference();
- } catch (RemoteException e) {
- return -1;
- }
+ // TODO - deprecate with:
+ // @deprecated Functionality has been removed as it no longer makes sense,
+ // with many more than two networks - we'd need an array to express
+ // preference. Instead we use dynamic network properties of
+ // the networks to describe their precedence.
+ return -1;
}
/**
@@ -700,7 +710,25 @@
*/
public LinkProperties getLinkProperties(int networkType) {
try {
- return mService.getLinkProperties(networkType);
+ return mService.getLinkPropertiesForType(networkType);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /** {@hide} */
+ public LinkProperties getLinkProperties(Network network) {
+ try {
+ return mService.getLinkProperties(network);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /** {@hide} */
+ public NetworkCapabilities getNetworkCapabilities(Network network) {
+ try {
+ return mService.getNetworkCapabilities(network);
} catch (RemoteException e) {
return null;
}
@@ -718,13 +746,14 @@
* {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
* {@hide}
*/
- public boolean setRadios(boolean turnOn) {
- try {
- return mService.setRadios(turnOn);
- } catch (RemoteException e) {
- return false;
- }
- }
+// TODO - check for any callers and remove
+// public boolean setRadios(boolean turnOn) {
+// try {
+// return mService.setRadios(turnOn);
+// } catch (RemoteException e) {
+// return false;
+// }
+// }
/**
* Tells a given networkType to set its radio power state as directed.
@@ -738,13 +767,14 @@
* {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
* {@hide}
*/
- public boolean setRadio(int networkType, boolean turnOn) {
- try {
- return mService.setRadio(networkType, turnOn);
- } catch (RemoteException e) {
- return false;
- }
- }
+// TODO - check for any callers and remove
+// public boolean setRadio(int networkType, boolean turnOn) {
+// try {
+// return mService.setRadio(networkType, turnOn);
+// } catch (RemoteException e) {
+// return false;
+// }
+// }
/**
* Tells the underlying networking system that the caller wants to
@@ -1302,6 +1332,22 @@
}
/**
+ * Report a problem network to the framework. This will cause the framework
+ * to evaluate the situation and try to fix any problems. Note that false
+ * may be subsequently ignored.
+ *
+ * @param network The Network the application was attempting to use or null
+ * to indicate the current default network.
+ * {@hide}
+ */
+ public void reportBadNetwork(Network network) {
+ try {
+ mService.reportBadNetwork(network);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Set a network-independent global http proxy. This is not normally what you want
* for typical HTTP proxies - they are general network dependent. However if you're
* doing something unusual like general internal filtering this may be useful. On
@@ -1582,4 +1628,440 @@
} catch (RemoteException e) {
}
}
+
+ /** {@hide} */
+ public void registerNetworkFactory(Messenger messenger) {
+ try {
+ mService.registerNetworkFactory(messenger);
+ } catch (RemoteException e) { }
+ }
+
+ /** {@hide} */
+ public void registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
+ NetworkCapabilities nc, int score) {
+ try {
+ mService.registerNetworkAgent(messenger, ni, lp, nc, score);
+ } catch (RemoteException e) { }
+ }
+
+ /**
+ * Interface for NetworkRequest callbacks. Used for notifications about network
+ * changes.
+ * @hide
+ */
+ public static class NetworkCallbacks {
+ /** @hide */
+ public static final int PRECHECK = 1;
+ /** @hide */
+ public static final int AVAILABLE = 2;
+ /** @hide */
+ public static final int LOSING = 3;
+ /** @hide */
+ public static final int LOST = 4;
+ /** @hide */
+ public static final int UNAVAIL = 5;
+ /** @hide */
+ public static final int CAP_CHANGED = 6;
+ /** @hide */
+ public static final int PROP_CHANGED = 7;
+ /** @hide */
+ public static final int CANCELED = 8;
+
+ /**
+ * @hide
+ * Called whenever the framework connects to a network that it may use to
+ * satisfy this request
+ */
+ public void onPreCheck(NetworkRequest networkRequest, Network network) {}
+
+ /**
+ * Called when the framework connects and has validated the new network.
+ */
+ public void onAvailable(NetworkRequest networkRequest, Network network) {}
+
+ /**
+ * Called when the framework is losing the network. Often paired with an
+ * onAvailable call with the new replacement network for graceful handover.
+ * This may not be called if we have a hard loss (loss without warning).
+ * This may be followed by either an onLost call or an onAvailable call for this
+ * network depending on if we lose or regain it.
+ */
+ public void onLosing(NetworkRequest networkRequest, Network network, int maxSecToLive) {}
+
+ /**
+ * Called when the framework has a hard loss of the network or when the
+ * graceful failure ends. Note applications should only request this callback
+ * if the application is willing to track the Available and Lost callbacks
+ * together, else the application may think it has no network when it
+ * really does (A Avail, B Avail, A Lost.. still have B).
+ */
+ public void onLost(NetworkRequest networkRequest, Network network) {}
+
+ /**
+ * Called if no network is found in the given timeout time. If no timeout is given,
+ * this will not be called.
+ */
+ public void onUnavailable(NetworkRequest networkRequest) {}
+
+ /**
+ * Called when the network the framework connected to for this request
+ * changes capabilities but still satisfies the stated need.
+ */
+ public void onNetworkCapabilitiesChanged(NetworkRequest networkRequest, Network network,
+ NetworkCapabilities networkCapabilities) {}
+
+ /**
+ * Called when the network the framework connected to for this request
+ * changes LinkProperties.
+ */
+ public void onLinkPropertiesChanged(NetworkRequest networkRequest, Network network,
+ LinkProperties linkProperties) {}
+
+ /**
+ * Called when a releaseNetworkRequest call concludes and the registered callbacks will
+ * no longer be used.
+ */
+ public void onReleased(NetworkRequest networkRequest) {}
+ }
+
+ private static final int BASE = Protocol.BASE_CONNECTIVITY_MANAGER;
+ /** @hide obj = pair(NetworkRequest, Network) */
+ public static final int CALLBACK_PRECHECK = BASE + 1;
+ /** @hide obj = pair(NetworkRequest, Network) */
+ public static final int CALLBACK_AVAILABLE = BASE + 2;
+ /** @hide obj = pair(NetworkRequest, Network), arg1 = ttl */
+ public static final int CALLBACK_LOSING = BASE + 3;
+ /** @hide obj = pair(NetworkRequest, Network) */
+ public static final int CALLBACK_LOST = BASE + 4;
+ /** @hide obj = NetworkRequest */
+ public static final int CALLBACK_UNAVAIL = BASE + 5;
+ /** @hide obj = pair(NetworkRequest, Network) */
+ public static final int CALLBACK_CAP_CHANGED = BASE + 6;
+ /** @hide obj = pair(NetworkRequest, Network) */
+ public static final int CALLBACK_IP_CHANGED = BASE + 7;
+ /** @hide obj = NetworkRequest */
+ public static final int CALLBACK_RELEASED = BASE + 8;
+ /** @hide */
+ public static final int CALLBACK_EXIT = BASE + 9;
+
+ private static class CallbackHandler extends Handler {
+ private final HashMap<NetworkRequest, NetworkCallbacks>mCallbackMap;
+ private final AtomicInteger mRefCount;
+ private static final String TAG = "ConnectivityManager.CallbackHandler";
+ private final ConnectivityManager mCm;
+
+ CallbackHandler(Looper looper, HashMap<NetworkRequest, NetworkCallbacks>callbackMap,
+ AtomicInteger refCount, ConnectivityManager cm) {
+ super(looper);
+ mCallbackMap = callbackMap;
+ mRefCount = refCount;
+ mCm = cm;
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ Log.d(TAG, "CM callback handler got msg " + message.what);
+ switch (message.what) {
+ case CALLBACK_PRECHECK: {
+ NetworkRequest request = getNetworkRequest(message);
+ NetworkCallbacks callbacks = getCallbacks(request);
+ if (callbacks != null) {
+ callbacks.onPreCheck(request, getNetwork(message));
+ } else {
+ Log.e(TAG, "callback not found for PRECHECK message");
+ }
+ break;
+ }
+ case CALLBACK_AVAILABLE: {
+ NetworkRequest request = getNetworkRequest(message);
+ NetworkCallbacks callbacks = getCallbacks(request);
+ if (callbacks != null) {
+ callbacks.onAvailable(request, getNetwork(message));
+ } else {
+ Log.e(TAG, "callback not found for AVAILABLE message");
+ }
+ break;
+ }
+ case CALLBACK_LOSING: {
+ NetworkRequest request = getNetworkRequest(message);
+ NetworkCallbacks callbacks = getCallbacks(request);
+ if (callbacks != null) {
+ callbacks.onLosing(request, getNetwork(message), message.arg1);
+ } else {
+ Log.e(TAG, "callback not found for LOSING message");
+ }
+ break;
+ }
+ case CALLBACK_LOST: {
+ NetworkRequest request = getNetworkRequest(message);
+ NetworkCallbacks callbacks = getCallbacks(request);
+ if (callbacks != null) {
+ callbacks.onLost(request, getNetwork(message));
+ } else {
+ Log.e(TAG, "callback not found for LOST message");
+ }
+ break;
+ }
+ case CALLBACK_UNAVAIL: {
+ NetworkRequest req = (NetworkRequest)message.obj;
+ NetworkCallbacks callbacks = null;
+ synchronized(mCallbackMap) {
+ callbacks = mCallbackMap.get(req);
+ }
+ if (callbacks != null) {
+ callbacks.onUnavailable(req);
+ } else {
+ Log.e(TAG, "callback not found for UNAVAIL message");
+ }
+ break;
+ }
+ case CALLBACK_CAP_CHANGED: {
+ NetworkRequest request = getNetworkRequest(message);
+ NetworkCallbacks callbacks = getCallbacks(request);
+ if (callbacks != null) {
+ Network network = getNetwork(message);
+ NetworkCapabilities cap = mCm.getNetworkCapabilities(network);
+
+ callbacks.onNetworkCapabilitiesChanged(request, network, cap);
+ } else {
+ Log.e(TAG, "callback not found for CHANGED message");
+ }
+ break;
+ }
+ case CALLBACK_IP_CHANGED: {
+ NetworkRequest request = getNetworkRequest(message);
+ NetworkCallbacks callbacks = getCallbacks(request);
+ if (callbacks != null) {
+ Network network = getNetwork(message);
+ LinkProperties lp = mCm.getLinkProperties(network);
+
+ callbacks.onLinkPropertiesChanged(request, network, lp);
+ } else {
+ Log.e(TAG, "callback not found for CHANGED message");
+ }
+ break;
+ }
+ case CALLBACK_RELEASED: {
+ NetworkRequest req = (NetworkRequest)message.obj;
+ NetworkCallbacks callbacks = null;
+ synchronized(mCallbackMap) {
+ callbacks = mCallbackMap.remove(req);
+ }
+ if (callbacks != null) {
+ callbacks.onReleased(req);
+ } else {
+ Log.e(TAG, "callback not found for CANCELED message");
+ }
+ synchronized(mRefCount) {
+ if (mRefCount.decrementAndGet() == 0) {
+ getLooper().quit();
+ }
+ }
+ break;
+ }
+ case CALLBACK_EXIT: {
+ Log.d(TAG, "Listener quiting");
+ getLooper().quit();
+ break;
+ }
+ }
+ }
+
+ private NetworkRequest getNetworkRequest(Message msg) {
+ return (NetworkRequest)(msg.obj);
+ }
+ private NetworkCallbacks getCallbacks(NetworkRequest req) {
+ synchronized(mCallbackMap) {
+ return mCallbackMap.get(req);
+ }
+ }
+ private Network getNetwork(Message msg) {
+ return new Network(msg.arg2);
+ }
+ private NetworkCallbacks removeCallbacks(Message msg) {
+ NetworkRequest req = (NetworkRequest)msg.obj;
+ synchronized(mCallbackMap) {
+ return mCallbackMap.remove(req);
+ }
+ }
+ }
+
+ private void addCallbackListener() {
+ synchronized(sCallbackRefCount) {
+ if (sCallbackRefCount.incrementAndGet() == 1) {
+ // TODO - switch this over to a ManagerThread or expire it when done
+ HandlerThread callbackThread = new HandlerThread("ConnectivityManager");
+ callbackThread.start();
+ sCallbackHandler = new CallbackHandler(callbackThread.getLooper(),
+ sNetworkCallbacks, sCallbackRefCount, this);
+ }
+ }
+ }
+
+ private void removeCallbackListener() {
+ synchronized(sCallbackRefCount) {
+ if (sCallbackRefCount.decrementAndGet() == 0) {
+ sCallbackHandler.obtainMessage(CALLBACK_EXIT).sendToTarget();
+ sCallbackHandler = null;
+ }
+ }
+ }
+
+ static final HashMap<NetworkRequest, NetworkCallbacks> sNetworkCallbacks =
+ new HashMap<NetworkRequest, NetworkCallbacks>();
+ static final AtomicInteger sCallbackRefCount = new AtomicInteger(0);
+ static CallbackHandler sCallbackHandler = null;
+
+ private final static int LISTEN = 1;
+ private final static int REQUEST = 2;
+
+ private NetworkRequest somethingForNetwork(NetworkCapabilities need,
+ NetworkCallbacks networkCallbacks, int timeoutSec, int action) {
+ NetworkRequest networkRequest = null;
+ if (networkCallbacks == null) throw new IllegalArgumentException("null NetworkCallbacks");
+ if (need == null) throw new IllegalArgumentException("null NetworkCapabilities");
+ try {
+ addCallbackListener();
+ if (action == LISTEN) {
+ networkRequest = mService.listenForNetwork(need, new Messenger(sCallbackHandler),
+ new Binder());
+ } else {
+ networkRequest = mService.requestNetwork(need, new Messenger(sCallbackHandler),
+ timeoutSec, new Binder());
+ }
+ if (networkRequest != null) {
+ synchronized(sNetworkCallbacks) {
+ sNetworkCallbacks.put(networkRequest, networkCallbacks);
+ }
+ }
+ } catch (RemoteException e) {}
+ if (networkRequest == null) removeCallbackListener();
+ return networkRequest;
+ }
+
+ /**
+ * Request a network to satisfy a set of {@link NetworkCapabilities}.
+ *
+ * This {@link NetworkRequest} will live until released via
+ * {@link releaseNetworkRequest} or the calling application exits.
+ * Status of the request can be follwed by listening to the various
+ * callbacks described in {@link NetworkCallbacks}. The {@link Network}
+ * can be used by using the {@link bindSocketToNetwork},
+ * {@link bindApplicationToNetwork} and {@link getAddrInfoOnNetwork} functions.
+ *
+ * @param need {@link NetworkCapabilities} required by this request.
+ * @param networkCallbacks The callbacks to be utilized for this request. Note
+ * the callbacks can be shared by multiple requests and
+ * the NetworkRequest token utilized to determine to which
+ * request the callback relates.
+ * @return A {@link NetworkRequest} object identifying the request.
+ * @hide
+ */
+ public NetworkRequest requestNetwork(NetworkCapabilities need,
+ NetworkCallbacks networkCallbacks) {
+ return somethingForNetwork(need, networkCallbacks, 0, REQUEST);
+ }
+
+ /**
+ * Request a network to satisfy a set of {@link NetworkCapabilities}, limited
+ * by a timeout.
+ *
+ * This function behaves identically, but if a suitable network is not found
+ * within the given time (in Seconds) the {@link NetworkCallbacks#unavailable}
+ * callback is called. The request must still be released normally by
+ * calling {@link releaseNetworkRequest}.
+ * @param need {@link NetworkCapabilities} required by this request.
+ * @param networkCallbacks The callbacks to be utilized for this request. Note
+ * the callbacks can be shared by multiple requests and
+ * the NetworkRequest token utilized to determine to which
+ * request the callback relates.
+ * @param timeoutSec The time in seconds to attempt looking for a suitable network
+ * before {@link NetworkCallbacks#unavailable} is called.
+ * @return A {@link NetworkRequest} object identifying the request.
+ * @hide
+ */
+ public NetworkRequest requestNetwork(NetworkCapabilities need,
+ NetworkCallbacks networkCallbacks, int timeoutSec) {
+ return somethingForNetwork(need, networkCallbacks, timeoutSec, REQUEST);
+ }
+
+ /**
+ * The maximum number of seconds the framework will look for a suitable network
+ * during a timeout-equiped call to {@link requestNetwork}.
+ * {@hide}
+ */
+ public final static int MAX_NETWORK_REQUEST_TIMEOUT_SEC = 100 * 60;
+
+ /**
+ * Request a network to satisfy a set of {@link NetworkCapabilities}.
+ *
+ * This function behavies identically, but instead of {@link NetworkCallbacks}
+ * a {@link PendingIntent} is used. This means the request may outlive the
+ * calling application and get called back when a suitable network is found.
+ * <p>
+ * The operation is an Intent broadcast that goes to a broadcast receiver that
+ * you registered with {@link Context#registerReceiver} or through the
+ * <receiver> tag in an AndroidManifest.xml file
+ * <p>
+ * The operation Intent is delivered with two extras, a {@link Network} typed
+ * extra called {@link EXTRA_NETWORK_REQUEST_NETWORK} and a {@link NetworkCapabilities}
+ * typed extra called {@link EXTRA_NETWORK_REQUEST_NETWORK_CAPABILTIES} containing
+ * the original requests parameters. It is important to create a new,
+ * {@link NetworkCallbacks} based request before completing the processing of the
+ * Intent to reserve the network or it will be released shortly after the Intent
+ * is processed.
+ * <p>
+ * If there is already an request for this Intent registered (with the equality of
+ * two Intents defined by {@link Intent#filterEquals}), then it will be removed and
+ * replace by this one, effectively releasing the previous {@link NetworkRequest}.
+ * <p>
+ * The request may be released normally by calling {@link releaseNetworkRequest}.
+ *
+ * @param need {@link NetworkCapabilties} required by this request.
+ * @param operation Action to perform when the network is available (corresponds
+ * to the {@link NetworkCallbacks#onAvailable} call. Typically
+ * comes from {@link PendingIntent#getBroadcast}.
+ * @return A {@link NetworkRequest} object identifying the request.
+ * @hide
+ */
+ public NetworkRequest requestNetwork(NetworkCapabilities need, PendingIntent operation) {
+ try {
+ return mService.pendingRequestForNetwork(need, operation);
+ } catch (RemoteException e) {}
+ return null;
+ }
+
+ /**
+ * Registers to receive notifications about all networks which satisfy the given
+ * {@link NetworkCapabilities}. The callbacks will continue to be called until
+ * either the application exits or the request is released using
+ * {@link releaseNetworkRequest}.
+ *
+ * @param need {@link NetworkCapabilities} required by this request.
+ * @param networkCallbacks The {@link NetworkCallbacks} to be called as suitable
+ * networks change state.
+ * @return A {@link NetworkRequest} object identifying the request.
+ * @hide
+ */
+ public NetworkRequest listenForNetwork(NetworkCapabilities need,
+ NetworkCallbacks networkCallbacks) {
+ return somethingForNetwork(need, networkCallbacks, 0, LISTEN);
+ }
+
+ /**
+ * Releases a {NetworkRequest} generated either through a {@link requestNetwork}
+ * or a {@link listenForNetwork} call. The {@link NetworkCallbacks} given in the
+ * earlier call may continue receiving calls until the {@link NetworkCallbacks#onReleased}
+ * function is called, signifiying the end of the request.
+ *
+ * @param networkRequest The {@link NetworkRequest} generated by an earlier call to
+ * {@link requestNetwork} or {@link listenForNetwork}.
+ * @hide
+ */
+ public void releaseNetworkRequest(NetworkRequest networkRequest) {
+ if (networkRequest == null) throw new IllegalArgumentException("null NetworkRequest");
+ try {
+ mService.releaseNetworkRequest(networkRequest);
+ } catch (RemoteException e) {}
+ }
}
diff --git a/core/java/android/net/ConnectivityServiceProtocol.java b/core/java/android/net/ConnectivityServiceProtocol.java
new file mode 100644
index 0000000..74096b4
--- /dev/null
+++ b/core/java/android/net/ConnectivityServiceProtocol.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static com.android.internal.util.Protocol.BASE_CONNECTIVITY_SERVICE;
+
+/**
+ * Describes the Internal protocols used to communicate with ConnectivityService.
+ * @hide
+ */
+public class ConnectivityServiceProtocol {
+
+ private static final int BASE = BASE_CONNECTIVITY_SERVICE;
+
+ private ConnectivityServiceProtocol() {}
+
+ /**
+ * This is a contract between ConnectivityService and various bearers.
+ * A NetworkFactory is an abstract entity that creates NetworkAgent objects.
+ * The bearers register with ConnectivityService using
+ * ConnectivityManager.registerNetworkFactory, where they pass in a Messenger
+ * to be used to deliver the following Messages.
+ */
+ public static class NetworkFactoryProtocol {
+ private NetworkFactoryProtocol() {}
+ /**
+ * Pass a network request to the bearer. If the bearer believes it can
+ * satisfy the request it should connect to the network and create a
+ * NetworkAgent. Once the NetworkAgent is fully functional it will
+ * register itself with ConnectivityService using registerNetworkAgent.
+ * If the bearer cannot immediately satisfy the request (no network,
+ * user disabled the radio, lower-scored network) it should remember
+ * any NetworkRequests it may be able to satisfy in the future. It may
+ * disregard any that it will never be able to service, for example
+ * those requiring a different bearer.
+ * msg.obj = NetworkRequest
+ * msg.arg1 = score - the score of the any network currently satisfying this
+ * request. If this bearer knows in advance it cannot
+ * exceed this score it should not try to connect, holding the request
+ * for the future.
+ * Note that subsequent events may give a different (lower
+ * or higher) score for this request, transmitted to each
+ * NetworkFactory through additional CMD_REQUEST_NETWORK msgs
+ * with the same NetworkRequest but an updated score.
+ * Also, network conditions may change for this bearer
+ * allowing for a better score in the future.
+ */
+ public static final int CMD_REQUEST_NETWORK = BASE;
+
+ /**
+ * Cancel a network request
+ * msg.obj = NetworkRequest
+ */
+ public static final int CMD_CANCEL_REQUEST = BASE + 1;
+ }
+}
diff --git a/core/java/android/net/DummyDataStateTracker.java b/core/java/android/net/DummyDataStateTracker.java
index a5d059e..eff9f9f 100644
--- a/core/java/android/net/DummyDataStateTracker.java
+++ b/core/java/android/net/DummyDataStateTracker.java
@@ -190,13 +190,6 @@
return new LinkProperties(mLinkProperties);
}
- /**
- * @see android.net.NetworkStateTracker#getLinkCapabilities()
- */
- public LinkCapabilities getLinkCapabilities() {
- return new LinkCapabilities(mLinkCapabilities);
- }
-
public void setDependencyMet(boolean met) {
// not supported on this network
}
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index 10b5d0b..c1afc9b 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -103,7 +103,7 @@
private EthernetDataTracker() {
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORKTYPE, "");
mLinkProperties = new LinkProperties();
- mLinkCapabilities = new LinkCapabilities();
+ mNetworkCapabilities = new NetworkCapabilities();
}
private void interfaceUpdated() {
@@ -372,16 +372,6 @@
return new LinkProperties(mLinkProperties);
}
- /**
- * A capability is an Integer/String pair, the capabilities
- * are defined in the class LinkSocket#Key.
- *
- * @return a copy of this connections capabilities, may be empty but never null.
- */
- public LinkCapabilities getLinkCapabilities() {
- return new LinkCapabilities(mLinkCapabilities);
- }
-
/**
* Fetch default gateway address for the network
*/
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index d53a856..885b8b6 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -16,10 +16,14 @@
package android.net;
+import android.app.PendingIntent;
import android.net.LinkQualityInfo;
import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkQuotaInfo;
+import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.ProxyInfo;
import android.os.IBinder;
@@ -41,10 +45,6 @@
// Keep this in sync with framework/native/services/connectivitymanager/ConnectivityManager.h
void markSocketAsUser(in ParcelFileDescriptor socket, int uid);
- void setNetworkPreference(int pref);
-
- int getNetworkPreference();
-
NetworkInfo getActiveNetworkInfo();
NetworkInfo getActiveNetworkInfoForUid(int uid);
NetworkInfo getNetworkInfo(int networkType);
@@ -55,17 +55,16 @@
boolean isNetworkSupported(int networkType);
LinkProperties getActiveLinkProperties();
- LinkProperties getLinkProperties(int networkType);
+ LinkProperties getLinkPropertiesForType(int networkType);
+ LinkProperties getLinkProperties(in Network network);
+
+ NetworkCapabilities getNetworkCapabilities(in Network network);
NetworkState[] getAllNetworkState();
NetworkQuotaInfo getActiveNetworkQuotaInfo();
boolean isActiveNetworkMetered();
- boolean setRadios(boolean onOff);
-
- boolean setRadio(int networkType, boolean turnOn);
-
int startUsingNetworkFeature(int networkType, in String feature,
in IBinder binder);
@@ -107,6 +106,8 @@
void reportInetCondition(int networkType, int percentage);
+ void reportBadNetwork(in Network network);
+
ProxyInfo getGlobalProxy();
void setGlobalProxy(in ProxyInfo p);
@@ -147,7 +148,27 @@
LinkQualityInfo[] getAllLinkQualityInfo();
- void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url);
+ void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo,
+ in String url);
void setAirplaneMode(boolean enable);
+
+ void registerNetworkFactory(in Messenger messenger);
+
+ void registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
+ in NetworkCapabilities nc, int score);
+
+ NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities,
+ in Messenger messenger, int timeoutSec, in IBinder binder);
+
+ NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities,
+ in PendingIntent operation);
+
+ NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities,
+ in Messenger messenger, in IBinder binder);
+
+ void pendingListenForNetwork(in NetworkCapabilities networkCapabilities,
+ in PendingIntent operation);
+
+ void releaseNetworkRequest(in NetworkRequest networkRequest);
}
diff --git a/core/java/android/net/LinkCapabilities.aidl b/core/java/android/net/LinkCapabilities.aidl
deleted file mode 100644
index df72599..0000000
--- a/core/java/android/net/LinkCapabilities.aidl
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
-**
-** Copyright (C) 2010 The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.net;
-
-parcelable LinkCapabilities;
-
diff --git a/core/java/android/net/LinkCapabilities.java b/core/java/android/net/LinkCapabilities.java
deleted file mode 100644
index fb444ea..0000000
--- a/core/java/android/net/LinkCapabilities.java
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.os.Parcelable;
-import android.os.Parcel;
-import android.util.Log;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-/**
- * A class representing the capabilities of a link
- *
- * @hide
- */
-public class LinkCapabilities implements Parcelable {
- private static final String TAG = "LinkCapabilities";
- private static final boolean DBG = false;
-
- /** The Map of Keys to Values */
- private HashMap<Integer, String> mCapabilities;
-
-
- /**
- * The set of keys defined for a links capabilities.
- *
- * Keys starting with RW are read + write, i.e. the application
- * can request for a certain requirement corresponding to that key.
- * Keys starting with RO are read only, i.e. the the application
- * can read the value of that key from the socket but cannot request
- * a corresponding requirement.
- *
- * TODO: Provide a documentation technique for concisely and precisely
- * define the syntax for each value string associated with a key.
- */
- public static final class Key {
- /** No constructor */
- private Key() {}
-
- /**
- * An integer representing the network type.
- * @see ConnectivityManager
- */
- public final static int RO_NETWORK_TYPE = 1;
-
- /**
- * Desired minimum forward link (download) bandwidth for the
- * in kilobits per second (kbps). Values should be strings such
- * "50", "100", "1500", etc.
- */
- public final static int RW_DESIRED_FWD_BW = 2;
-
- /**
- * Required minimum forward link (download) bandwidth, in
- * per second (kbps), below which the socket cannot function.
- * Values should be strings such as "50", "100", "1500", etc.
- */
- public final static int RW_REQUIRED_FWD_BW = 3;
-
- /**
- * Available forward link (download) bandwidth for the socket.
- * This value is in kilobits per second (kbps).
- * Values will be strings such as "50", "100", "1500", etc.
- */
- public final static int RO_AVAILABLE_FWD_BW = 4;
-
- /**
- * Desired minimum reverse link (upload) bandwidth for the socket
- * in kilobits per second (kbps).
- * Values should be strings such as "50", "100", "1500", etc.
- * <p>
- * This key is set via the needs map.
- */
- public final static int RW_DESIRED_REV_BW = 5;
-
- /**
- * Required minimum reverse link (upload) bandwidth, in kilobits
- * per second (kbps), below which the socket cannot function.
- * If a rate is not specified, the default rate of kbps will be
- * Values should be strings such as "50", "100", "1500", etc.
- */
- public final static int RW_REQUIRED_REV_BW = 6;
-
- /**
- * Available reverse link (upload) bandwidth for the socket.
- * This value is in kilobits per second (kbps).
- * Values will be strings such as "50", "100", "1500", etc.
- */
- public final static int RO_AVAILABLE_REV_BW = 7;
-
- /**
- * Maximum latency for the socket, in milliseconds, above which
- * socket cannot function.
- * Values should be strings such as "50", "300", "500", etc.
- */
- public final static int RW_MAX_ALLOWED_LATENCY = 8;
-
- /**
- * Interface that the socket is bound to. This can be a virtual
- * interface (e.g. VPN or Mobile IP) or a physical interface
- * (e.g. wlan0 or rmnet0).
- * Values will be strings such as "wlan0", "rmnet0"
- */
- public final static int RO_BOUND_INTERFACE = 9;
-
- /**
- * Physical interface that the socket is routed on.
- * This can be different from BOUND_INTERFACE in cases such as
- * VPN or Mobile IP. The physical interface may change over time
- * if seamless mobility is supported.
- * Values will be strings such as "wlan0", "rmnet0"
- */
- public final static int RO_PHYSICAL_INTERFACE = 10;
- }
-
- /**
- * Role informs the LinkSocket about the data usage patterns of your
- * application.
- * <P>
- * {@code Role.DEFAULT} is the default role, and is used whenever
- * a role isn't set.
- */
- public static final class Role {
- /** No constructor */
- private Role() {}
-
- // examples only, discuss which roles should be defined, and then
- // code these to match
-
- /** Default Role */
- public static final String DEFAULT = "default";
- /** Bulk down load */
- public static final String BULK_DOWNLOAD = "bulk.download";
- /** Bulk upload */
- public static final String BULK_UPLOAD = "bulk.upload";
-
- /** VoIP Application at 24kbps */
- public static final String VOIP_24KBPS = "voip.24k";
- /** VoIP Application at 32kbps */
- public static final String VOIP_32KBPS = "voip.32k";
-
- /** Video Streaming at 480p */
- public static final String VIDEO_STREAMING_480P = "video.streaming.480p";
- /** Video Streaming at 720p */
- public static final String VIDEO_STREAMING_720I = "video.streaming.720i";
-
- /** Video Chat Application at 360p */
- public static final String VIDEO_CHAT_360P = "video.chat.360p";
- /** Video Chat Application at 480p */
- public static final String VIDEO_CHAT_480P = "video.chat.480i";
- }
-
- /**
- * Constructor
- */
- public LinkCapabilities() {
- mCapabilities = new HashMap<Integer, String>();
- }
-
- /**
- * Copy constructor.
- *
- * @param source
- */
- public LinkCapabilities(LinkCapabilities source) {
- if (source != null) {
- mCapabilities = new HashMap<Integer, String>(source.mCapabilities);
- } else {
- mCapabilities = new HashMap<Integer, String>();
- }
- }
-
- /**
- * Create the {@code LinkCapabilities} with values depending on role type.
- * @param applicationRole a {@code LinkSocket.Role}
- * @return the {@code LinkCapabilities} associated with the applicationRole, empty if none
- */
- public static LinkCapabilities createNeedsMap(String applicationRole) {
- if (DBG) log("createNeededCapabilities(applicationRole) EX");
- return new LinkCapabilities();
- }
-
- /**
- * Remove all capabilities
- */
- public void clear() {
- mCapabilities.clear();
- }
-
- /**
- * Returns whether this map is empty.
- */
- public boolean isEmpty() {
- return mCapabilities.isEmpty();
- }
-
- /**
- * Returns the number of elements in this map.
- *
- * @return the number of elements in this map.
- */
- public int size() {
- return mCapabilities.size();
- }
-
- /**
- * Given the key return the capability string
- *
- * @param key
- * @return the capability string
- */
- public String get(int key) {
- return mCapabilities.get(key);
- }
-
- /**
- * Store the key/value capability pair
- *
- * @param key
- * @param value
- */
- public void put(int key, String value) {
- mCapabilities.put(key, value);
- }
-
- /**
- * Returns whether this map contains the specified key.
- *
- * @param key to search for.
- * @return {@code true} if this map contains the specified key,
- * {@code false} otherwise.
- */
- public boolean containsKey(int key) {
- return mCapabilities.containsKey(key);
- }
-
- /**
- * Returns whether this map contains the specified value.
- *
- * @param value to search for.
- * @return {@code true} if this map contains the specified value,
- * {@code false} otherwise.
- */
- public boolean containsValue(String value) {
- return mCapabilities.containsValue(value);
- }
-
- /**
- * Returns a set containing all of the mappings in this map. Each mapping is
- * an instance of {@link Map.Entry}. As the set is backed by this map,
- * changes in one will be reflected in the other.
- *
- * @return a set of the mappings.
- */
- public Set<Entry<Integer, String>> entrySet() {
- return mCapabilities.entrySet();
- }
-
- /**
- * @return the set of the keys.
- */
- public Set<Integer> keySet() {
- return mCapabilities.keySet();
- }
-
- /**
- * @return the set of values
- */
- public Collection<String> values() {
- return mCapabilities.values();
- }
-
- /**
- * Implement the Parcelable interface
- * @hide
- */
- public int describeContents() {
- return 0;
- }
-
- /**
- * Convert to string for debugging
- */
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("{");
- boolean firstTime = true;
- for (Entry<Integer, String> entry : mCapabilities.entrySet()) {
- if (firstTime) {
- firstTime = false;
- } else {
- sb.append(",");
- }
- sb.append(entry.getKey());
- sb.append(":\"");
- sb.append(entry.getValue());
- sb.append("\"");
- }
- sb.append("}");
- return sb.toString();
- }
-
- /**
- * Implement the Parcelable interface.
- * @hide
- */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mCapabilities.size());
- for (Entry<Integer, String> entry : mCapabilities.entrySet()) {
- dest.writeInt(entry.getKey().intValue());
- dest.writeString(entry.getValue());
- }
- }
-
- /**
- * Implement the Parcelable interface.
- * @hide
- */
- public static final Creator<LinkCapabilities> CREATOR =
- new Creator<LinkCapabilities>() {
- public LinkCapabilities createFromParcel(Parcel in) {
- LinkCapabilities capabilities = new LinkCapabilities();
- int size = in.readInt();
- while (size-- != 0) {
- int key = in.readInt();
- String value = in.readString();
- capabilities.mCapabilities.put(key, value);
- }
- return capabilities;
- }
-
- public LinkCapabilities[] newArray(int size) {
- return new LinkCapabilities[size];
- }
- };
-
- /**
- * Debug logging
- */
- protected static void log(String s) {
- Log.d(TAG, s);
- }
-}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 2dcc544..0a09fcb 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -642,6 +642,35 @@
return result;
}
+ /**
+ * Compares all interface names in this LinkProperties with another
+ * LinkProperties, examining both the the base link and all stacked links.
+ *
+ * @param target a LinkProperties with the new list of interface names
+ * @return the differences between the interface names.
+ * @hide
+ */
+ public CompareResult<String> compareAllInterfaceNames(LinkProperties target) {
+ /*
+ * Duplicate the interface names into removed, we will be removing
+ * interface names which are common between this and target
+ * leaving the interface names that are different. And interface names which
+ * are in target but not in this are placed in added.
+ */
+ CompareResult<String> result = new CompareResult<String>();
+
+ result.removed = getAllInterfaceNames();
+ result.added.clear();
+ if (target != null) {
+ for (String r : target.getAllInterfaceNames()) {
+ if (! result.removed.remove(r)) {
+ result.added.add(r);
+ }
+ }
+ }
+ return result;
+ }
+
@Override
/**
diff --git a/core/java/android/net/LinkSocket.java b/core/java/android/net/LinkSocket.java
deleted file mode 100644
index 5aa6451..0000000
--- a/core/java/android/net/LinkSocket.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.net.LinkCapabilities;
-import android.net.LinkProperties;
-import android.net.LinkSocketNotifier;
-
-import android.util.Log;
-
-import java.io.IOException;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.net.SocketTimeoutException;
-import java.net.UnknownHostException;
-import java.util.HashSet;
-import java.util.Set;
-
-/** @hide */
-public class LinkSocket extends Socket {
- private final static String TAG = "LinkSocket";
- private final static boolean DBG = true;
-
- /**
- * Default constructor
- */
- public LinkSocket() {
- if (DBG) log("LinkSocket() EX");
- }
-
- /**
- * Creates a new unconnected socket.
- * @param notifier a reference to a class that implements {@code LinkSocketNotifier}
- */
- public LinkSocket(LinkSocketNotifier notifier) {
- if (DBG) log("LinkSocket(notifier) EX");
- }
-
- /**
- * Creates a new unconnected socket usign the given proxy type.
- * @param notifier a reference to a class that implements {@code LinkSocketNotifier}
- * @param proxy the specified proxy for this socket
- * @throws IllegalArgumentException if the argument proxy is null or of an invalid type.
- * @throws SecurityException if a security manager exists and it denies the permission
- * to connect to the given proxy.
- */
- public LinkSocket(LinkSocketNotifier notifier, Proxy proxy) {
- if (DBG) log("LinkSocket(notifier, proxy) EX");
- }
-
- /**
- * @return the {@code LinkProperties} for the socket
- */
- public LinkProperties getLinkProperties() {
- if (DBG) log("LinkProperties() EX");
- return new LinkProperties();
- }
-
- /**
- * Set the {@code LinkCapabilies} needed for this socket. If the socket is already connected
- * or is a duplicate socket the request is ignored and {@code false} will
- * be returned. A needs map can be created via the {@code createNeedsMap} static
- * method.
- * @param needs the needs of the socket
- * @return {@code true} if needs are successfully set, {@code false} otherwise
- */
- public boolean setNeededCapabilities(LinkCapabilities needs) {
- if (DBG) log("setNeeds() EX");
- return false;
- }
-
- /**
- * @return the LinkCapabilites set by setNeededCapabilities, empty if none has been set
- */
- public LinkCapabilities getNeededCapabilities() {
- if (DBG) log("getNeeds() EX");
- return null;
- }
-
- /**
- * @return all of the {@code LinkCapabilities} of the link used by this socket
- */
- public LinkCapabilities getCapabilities() {
- if (DBG) log("getCapabilities() EX");
- return null;
- }
-
- /**
- * Returns this LinkSockets set of capabilities, filtered according to
- * the given {@code Set}. Capabilities in the Set but not available from
- * the link will not be reported in the results. Capabilities of the link
- * but not listed in the Set will also not be reported in the results.
- * @param capabilities {@code Set} of capabilities requested
- * @return the filtered {@code LinkCapabilities} of this LinkSocket, may be empty
- */
- public LinkCapabilities getCapabilities(Set<Integer> capabilities) {
- if (DBG) log("getCapabilities(capabilities) EX");
- return new LinkCapabilities();
- }
-
- /**
- * Provide the set of capabilities the application is interested in tracking
- * for this LinkSocket.
- * @param capabilities a {@code Set} of capabilities to track
- */
- public void setTrackedCapabilities(Set<Integer> capabilities) {
- if (DBG) log("setTrackedCapabilities(capabilities) EX");
- }
-
- /**
- * @return the {@code LinkCapabilities} that are tracked, empty if none has been set.
- */
- public Set<Integer> getTrackedCapabilities() {
- if (DBG) log("getTrackedCapabilities(capabilities) EX");
- return new HashSet<Integer>();
- }
-
- /**
- * Connects this socket to the given remote host address and port specified
- * by dstName and dstPort.
- * @param dstName the address of the remote host to connect to
- * @param dstPort the port to connect to on the remote host
- * @param timeout the timeout value in milliseconds or 0 for infinite timeout
- * @throws UnknownHostException if the given dstName is invalid
- * @throws IOException if the socket is already connected or an error occurs
- * while connecting
- * @throws SocketTimeoutException if the timeout fires
- */
- public void connect(String dstName, int dstPort, int timeout)
- throws UnknownHostException, IOException, SocketTimeoutException {
- if (DBG) log("connect(dstName, dstPort, timeout) EX");
- }
-
- /**
- * Connects this socket to the given remote host address and port specified
- * by dstName and dstPort.
- * @param dstName the address of the remote host to connect to
- * @param dstPort the port to connect to on the remote host
- * @throws UnknownHostException if the given dstName is invalid
- * @throws IOException if the socket is already connected or an error occurs
- * while connecting
- */
- public void connect(String dstName, int dstPort)
- throws UnknownHostException, IOException {
- if (DBG) log("connect(dstName, dstPort, timeout) EX");
- }
-
- /**
- * Connects this socket to the given remote host address and port specified
- * by the SocketAddress with the specified timeout.
- * @deprecated Use {@code connect(String dstName, int dstPort, int timeout)}
- * instead. Using this method may result in reduced functionality.
- * @param remoteAddr the address and port of the remote host to connect to
- * @throws IllegalArgumentException if the given SocketAddress is invalid
- * @throws IOException if the socket is already connected or an error occurs
- * while connecting
- * @throws SocketTimeoutException if the timeout expires
- */
- @Override
- @Deprecated
- public void connect(SocketAddress remoteAddr, int timeout)
- throws IOException, SocketTimeoutException {
- if (DBG) log("connect(remoteAddr, timeout) EX DEPRECATED");
- }
-
- /**
- * Connects this socket to the given remote host address and port specified
- * by the SocketAddress.
- * TODO add comment on all these that the network selection happens during connect
- * and may take 30 seconds
- * @deprecated Use {@code connect(String dstName, int dstPort)}
- * Using this method may result in reduced functionality.
- * @param remoteAddr the address and port of the remote host to connect to.
- * @throws IllegalArgumentException if the SocketAddress is invalid or not supported.
- * @throws IOException if the socket is already connected or an error occurs
- * while connecting
- */
- @Override
- @Deprecated
- public void connect(SocketAddress remoteAddr) throws IOException {
- if (DBG) log("connect(remoteAddr) EX DEPRECATED");
- }
-
- /**
- * Connect a duplicate socket socket to the same remote host address and port
- * as the original with a timeout parameter.
- * @param timeout the timeout value in milliseconds or 0 for infinite timeout
- * @throws IOException if the socket is already connected or an error occurs
- * while connecting
- */
- public void connect(int timeout) throws IOException {
- if (DBG) log("connect(timeout) EX");
- }
-
- /**
- * Connect a duplicate socket socket to the same remote host address and port
- * as the original.
- * @throws IOException if the socket is already connected or an error occurs
- * while connecting
- */
- public void connect() throws IOException {
- if (DBG) log("connect() EX");
- }
-
- /**
- * Closes the socket. It is not possible to reconnect or rebind to this
- * socket thereafter which means a new socket instance has to be created.
- * @throws IOException if an error occurs while closing the socket
- */
- @Override
- public synchronized void close() throws IOException {
- if (DBG) log("close() EX");
- }
-
- /**
- * Request that a new LinkSocket be created using a different radio
- * (such as WiFi or 3G) than the current LinkSocket. If a different
- * radio is available a call back will be made via {@code onBetterLinkAvail}.
- * If unable to find a better radio, application will be notified via
- * {@code onNewLinkUnavailable}
- * @see LinkSocketNotifier#onBetterLinkAvailable(LinkSocket, LinkSocket)
- * @param linkRequestReason reason for requesting a new link.
- */
- public void requestNewLink(LinkRequestReason linkRequestReason) {
- if (DBG) log("requestNewLink(linkRequestReason) EX");
- }
-
- /**
- * @deprecated LinkSocket will automatically pick the optimum interface
- * to bind to
- * @param localAddr the specific address and port on the local machine
- * to bind to
- * @throws IOException always as this method is deprecated for LinkSocket
- */
- @Override
- @Deprecated
- public void bind(SocketAddress localAddr) throws UnsupportedOperationException {
- if (DBG) log("bind(localAddr) EX throws IOException");
- throw new UnsupportedOperationException("bind is deprecated for LinkSocket");
- }
-
- /**
- * Reason codes an application can specify when requesting for a new link.
- * TODO: need better documentation
- */
- public static final class LinkRequestReason {
- /** No constructor */
- private LinkRequestReason() {}
-
- /** This link is working properly */
- public static final int LINK_PROBLEM_NONE = 0;
- /** This link has an unknown issue */
- public static final int LINK_PROBLEM_UNKNOWN = 1;
- }
-
- /**
- * Debug logging
- */
- protected static void log(String s) {
- Log.d(TAG, s);
- }
-}
diff --git a/core/java/android/net/LinkSocketNotifier.java b/core/java/android/net/LinkSocketNotifier.java
deleted file mode 100644
index e2429d8..0000000
--- a/core/java/android/net/LinkSocketNotifier.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-/**
- * Interface used to get feedback about a {@link android.net.LinkSocket}. Instance is optionally
- * passed when a LinkSocket is constructed. Multiple LinkSockets may use the same notifier.
- * @hide
- */
-public interface LinkSocketNotifier {
- /**
- * This callback function will be called if a better link
- * becomes available.
- * TODO - this shouldn't be checked for all cases - what's the conditional
- * flag?
- * If the duplicate socket is accepted, the original will be marked invalid
- * and additional use will throw exceptions.
- * @param original the original LinkSocket
- * @param duplicate the new LinkSocket that better meets the application
- * requirements
- * @return {@code true} if the application intends to use this link
- *
- * REM
- * TODO - how agressive should we be?
- * At a minimum CS tracks which LS have this turned on and tracks the requirements
- * When a new link becomes available, automatically check if any of the LinkSockets
- * will care.
- * If found, grab a refcount on the link so it doesn't go away and send notification
- * Optionally, periodically setup connection on available networks to check for better links
- * Maybe pass this info into the LinkFactories so condition changes can be acted on more quickly
- */
- public boolean onBetterLinkAvailable(LinkSocket original, LinkSocket duplicate);
-
- /**
- * This callback function will be called when a LinkSocket no longer has
- * an active link.
- * @param socket the LinkSocket that lost its link
- *
- * REM
- * NetworkStateTracker tells us it is disconnected
- * CS checks the table for LS on that link
- * CS calls each callback (need to work out p2p cross process callback)
- */
- public void onLinkLost(LinkSocket socket);
-
- /**
- * This callback function will be called when an application calls
- * requestNewLink on a LinkSocket but the LinkSocket is unable to find
- * a suitable new link.
- * @param socket the LinkSocket for which a new link was not found
- * TODO - why the diff between initial request (sync) and requestNewLink?
- *
- * REM
- * CS process of trying to find a new link must track the LS that started it
- * on failure, call callback
- */
- public void onNewLinkUnavailable(LinkSocket socket);
-
- /**
- * This callback function will be called when any of the notification-marked
- * capabilities of the LinkSocket (e.g. upstream bandwidth) have changed.
- * @param socket the linkSocet for which capabilities have changed
- * @param changedCapabilities the set of capabilities that the application
- * is interested in and have changed (with new values)
- *
- * REM
- * Maybe pass the interesting capabilities into the Links.
- * Get notified of every capability change
- * check for LinkSockets on that Link that are interested in that Capability - call them
- */
- public void onCapabilitiesChanged(LinkSocket socket, LinkCapabilities changedCapabilities);
-}
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 30b61c5..535bbe24 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -66,7 +66,6 @@
private Handler mTarget;
private Context mContext;
private LinkProperties mLinkProperties;
- private LinkCapabilities mLinkCapabilities;
private boolean mPrivateDnsRouteSet = false;
private boolean mDefaultRouteSet = false;
@@ -200,11 +199,11 @@
}
mLinkProperties.setMtu(mContext.getResources().getInteger(
com.android.internal.R.integer.config_mobile_mtu));
- mLinkCapabilities = intent.getParcelableExtra(
- PhoneConstants.DATA_LINK_CAPABILITIES_KEY);
- if (mLinkCapabilities == null) {
- loge("CONNECTED event did not supply link capabilities.");
- mLinkCapabilities = new LinkCapabilities();
+ mNetworkCapabilities = intent.getParcelableExtra(
+ PhoneConstants.DATA_NETWORK_CAPABILITIES_KEY);
+ if (mNetworkCapabilities == null) {
+ loge("CONNECTED event did not supply network capabilities.");
+ mNetworkCapabilities = new NetworkCapabilities();
}
}
@@ -316,10 +315,10 @@
Slog.d(TAG, "LinkProperties = " );
}
- if (mLinkCapabilities != null) {
- Slog.d(TAG, "LinkCapabilities = " + mLinkCapabilities);
+ if (mNetworkCapabilities != null) {
+ Slog.d(TAG, mNetworkCapabilities.toString());
} else {
- Slog.d(TAG, "LinkCapabilities = " );
+ Slog.d(TAG, "NetworkCapabilities = " );
}
}
@@ -750,14 +749,6 @@
return new LinkProperties(mLinkProperties);
}
- /**
- * @see android.net.NetworkStateTracker#getLinkCapabilities()
- */
- @Override
- public LinkCapabilities getLinkCapabilities() {
- return new LinkCapabilities(mLinkCapabilities);
- }
-
public void supplyMessenger(Messenger messenger) {
if (VDBG) log(mApnType + " got supplyMessenger");
AsyncChannel ac = new AsyncChannel();
diff --git a/core/java/android/net/Network.aidl b/core/java/android/net/Network.aidl
new file mode 100644
index 0000000..73ba1af
--- /dev/null
+++ b/core/java/android/net/Network.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright (C) 2014 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+parcelable Network;
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
new file mode 100644
index 0000000..ac1289b
--- /dev/null
+++ b/core/java/android/net/Network.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Identifies the Network.
+ * @hide
+ */
+public class Network implements Parcelable {
+
+ public final int netId;
+
+ public Network(int netId) {
+ this.netId = netId;
+ }
+
+ public Network(Network that) {
+ this.netId = that.netId;
+ }
+
+ /**
+ * Operates the same as {@code InetAddress.getAllByName} except that host
+ * resolution is done on this network.
+ *
+ * @param host the hostname or literal IP string to be resolved.
+ * @return the array of addresses associated with the specified host.
+ * @throws UnknownHostException if the address lookup fails.
+ */
+ public InetAddress[] getAllByName(String host) throws UnknownHostException {
+ return InetAddress.getAllByNameOnNet(host, netId);
+ }
+
+ /**
+ * Operates the same as {@code InetAddress.getByName} except that host
+ * resolution is done on this network.
+ *
+ * @param host
+ * the hostName to be resolved to an address or {@code null}.
+ * @return the {@code InetAddress} instance representing the host.
+ * @throws UnknownHostException
+ * if the address lookup fails.
+ */
+ public InetAddress getByName(String host) throws UnknownHostException {
+ return InetAddress.getByNameOnNet(host, netId);
+ }
+
+ // implement the Parcelable interface
+ public int describeContents() {
+ return 0;
+ }
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(netId);
+ }
+
+ public static final Creator<Network> CREATOR =
+ new Creator<Network>() {
+ public Network createFromParcel(Parcel in) {
+ int netId = in.readInt();
+
+ return new Network(netId);
+ }
+
+ public Network[] newArray(int size) {
+ return new Network[size];
+ }
+ };
+}
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
new file mode 100644
index 0000000..4b85398
--- /dev/null
+++ b/core/java/android/net/NetworkAgent.java
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * A Utility class for handling NetworkRequests.
+ *
+ * Created by bearer-specific code to handle tracking requests, scores,
+ * network data and handle communicating with ConnectivityService. Two
+ * abstract methods: connect and disconnect are used to act on the
+ * underlying bearer code. Connect is called when we have a NetworkRequest
+ * and our score is better than the current handling network's score, while
+ * disconnect is used when ConnectivityService requests a disconnect.
+ *
+ * A bearer may have more than one NetworkAgent if it can simultaneously
+ * support separate networks (IMS / Internet / MMS Apns on cellular, or
+ * perhaps connections with different SSID or P2P for Wi-Fi). The bearer
+ * code should pass its NetworkAgents the NetworkRequests each NetworkAgent
+ * can handle, demultiplexing for different network types. The bearer code
+ * can also filter out requests it can never handle.
+ *
+ * Each NetworkAgent needs to be given a score and NetworkCapabilities for
+ * their potential network. While disconnected, the NetworkAgent will check
+ * each time its score changes or a NetworkRequest changes to see if
+ * the NetworkAgent can provide a higher scored network for a NetworkRequest
+ * that the NetworkAgent's NetworkCapabilties can satisfy. This condition will
+ * trigger a connect request via connect(). After connection, connection data
+ * should be given to the NetworkAgent by the bearer, including LinkProperties
+ * NetworkCapabilties and NetworkInfo. After that the NetworkAgent will register
+ * with ConnectivityService and forward the data on.
+ * @hide
+ */
+public abstract class NetworkAgent extends Handler {
+ private final SparseArray<NetworkRequestAndScore> mNetworkRequests = new SparseArray<>();
+ private boolean mConnectionRequested = false;
+
+ private AsyncChannel mAsyncChannel;
+ private final String LOG_TAG;
+ private static final boolean DBG = true;
+ // TODO - this class shouldn't cache data or it runs the risk of getting out of sync
+ // Make the API require each of these when any is updated so we have the data we need,
+ // without caching.
+ private LinkProperties mLinkProperties;
+ private NetworkInfo mNetworkInfo;
+ private NetworkCapabilities mNetworkCapabilities;
+ private int mNetworkScore;
+ private boolean mRegistered = false;
+ private final Context mContext;
+ private AtomicBoolean mHasRequests = new AtomicBoolean(false);
+
+ // TODO - add a name member for logging purposes.
+
+ protected final Object mLockObj = new Object();
+
+
+ private static final int BASE = Protocol.BASE_NETWORK_AGENT;
+
+ /**
+ * Sent by self to queue up a new/modified request.
+ * obj = NetworkRequestAndScore
+ */
+ private static final int CMD_ADD_REQUEST = BASE + 1;
+
+ /**
+ * Sent by self to queue up the removal of a request.
+ * obj = NetworkRequest
+ */
+ private static final int CMD_REMOVE_REQUEST = BASE + 2;
+
+ /**
+ * Sent by ConnectivityService to the NetworkAgent to inform it of
+ * suspected connectivity problems on its network. The NetworkAgent
+ * should take steps to verify and correct connectivity.
+ */
+ public static final int CMD_SUSPECT_BAD = BASE + 3;
+
+ /**
+ * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to
+ * ConnectivityService to pass the current NetworkInfo (connection state).
+ * Sent when the NetworkInfo changes, mainly due to change of state.
+ * obj = NetworkInfo
+ */
+ public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 4;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to pass the current
+ * NetworkCapabilties.
+ * obj = NetworkCapabilities
+ */
+ public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 5;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to pass the current
+ * NetworkProperties.
+ * obj = NetworkProperties
+ */
+ public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 6;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to pass the current
+ * network score.
+ * arg1 = network score int
+ */
+ public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 7;
+
+ public NetworkAgent(Looper looper, Context context, String logTag) {
+ super(looper);
+ LOG_TAG = logTag;
+ mContext = context;
+ }
+
+ /**
+ * When conditions are right, register with ConnectivityService.
+ * Connditions include having a well defined network and a request
+ * that justifies it. The NetworkAgent will remain registered until
+ * disconnected.
+ * TODO - this should have all data passed in rather than caching
+ */
+ private void registerSelf() {
+ synchronized(mLockObj) {
+ if (!mRegistered && mConnectionRequested &&
+ mNetworkInfo != null && mNetworkInfo.isConnected() &&
+ mNetworkCapabilities != null &&
+ mLinkProperties != null &&
+ mNetworkScore != 0) {
+ if (DBG) log("Registering NetworkAgent");
+ mRegistered = true;
+ ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(mNetworkInfo),
+ new LinkProperties(mLinkProperties),
+ new NetworkCapabilities(mNetworkCapabilities), mNetworkScore);
+ } else if (DBG && !mRegistered) {
+ String err = "Not registering due to ";
+ if (mConnectionRequested == false) err += "no Connect requested ";
+ if (mNetworkInfo == null) err += "null NetworkInfo ";
+ if (mNetworkInfo != null && mNetworkInfo.isConnected() == false) {
+ err += "NetworkInfo disconnected ";
+ }
+ if (mLinkProperties == null) err += "null LinkProperties ";
+ if (mNetworkCapabilities == null) err += "null NetworkCapabilities ";
+ if (mNetworkScore == 0) err += "null NetworkScore";
+ log(err);
+ }
+ }
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
+ synchronized (mLockObj) {
+ if (mAsyncChannel != null) {
+ log("Received new connection while already connected!");
+ } else {
+ if (DBG) log("NetworkAgent fully connected");
+ mAsyncChannel = new AsyncChannel();
+ mAsyncChannel.connected(null, this, msg.replyTo);
+ mAsyncChannel.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
+ AsyncChannel.STATUS_SUCCESSFUL);
+ }
+ }
+ break;
+ }
+ case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
+ if (DBG) log("CMD_CHANNEL_DISCONNECT");
+ if (mAsyncChannel != null) mAsyncChannel.disconnect();
+ break;
+ }
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+ if (DBG) log("NetworkAgent channel lost");
+ disconnect();
+ clear();
+ break;
+ }
+ case CMD_SUSPECT_BAD: {
+ log("Unhandled Message " + msg);
+ break;
+ }
+ case CMD_ADD_REQUEST: {
+ handleAddRequest(msg);
+ break;
+ }
+ case CMD_REMOVE_REQUEST: {
+ handleRemoveRequest(msg);
+ break;
+ }
+ }
+ }
+
+ private void clear() {
+ synchronized(mLockObj) {
+ mNetworkRequests.clear();
+ mHasRequests.set(false);
+ mConnectionRequested = false;
+ mAsyncChannel = null;
+ mRegistered = false;
+ }
+ }
+
+ private static class NetworkRequestAndScore {
+ NetworkRequest req;
+ int score;
+
+ NetworkRequestAndScore(NetworkRequest networkRequest, int score) {
+ req = networkRequest;
+ this.score = score;
+ }
+ }
+
+ private void handleAddRequest(Message msg) {
+ NetworkRequestAndScore n = (NetworkRequestAndScore)msg.obj;
+ // replaces old request, updating score
+ mNetworkRequests.put(n.req.requestId, n);
+ mHasRequests.set(true);
+ evalScores();
+ }
+
+ private void handleRemoveRequest(Message msg) {
+ NetworkRequest networkRequest = (NetworkRequest)msg.obj;
+
+ if (mNetworkRequests.get(networkRequest.requestId) != null) {
+ mNetworkRequests.remove(networkRequest.requestId);
+ if (mNetworkRequests.size() == 0) mHasRequests.set(false);
+ evalScores();
+ }
+ }
+
+ /**
+ * called to go through our list of requests and see if we're
+ * good enough to try connecting.
+ *
+ * Only does connects - we disconnect when requested via
+ * CMD_CHANNEL_DISCONNECTED, generated by either a loss of connection
+ * between modules (bearer or ConnectivityService dies) or more commonly
+ * when the NetworkInfo reports to ConnectivityService it is disconnected.
+ */
+ private void evalScores() {
+ if (mConnectionRequested) {
+ // already trying
+ return;
+ }
+ for (int i=0; i < mNetworkRequests.size(); i++) {
+ int score = mNetworkRequests.valueAt(i).score;
+ if (score < mNetworkScore) {
+ // have a request that has a lower scored network servicing it
+ // (or no network) than we could provide, so lets connect!
+ mConnectionRequested = true;
+ connect();
+ return;
+ }
+ }
+ }
+
+ public void addNetworkRequest(NetworkRequest networkRequest, int score) {
+ if (DBG) log("adding NetworkRequest " + networkRequest + " with score " + score);
+ sendMessage(obtainMessage(CMD_ADD_REQUEST,
+ new NetworkRequestAndScore(networkRequest, score)));
+ }
+
+ public void removeNetworkRequest(NetworkRequest networkRequest) {
+ if (DBG) log("removing NetworkRequest " + networkRequest);
+ sendMessage(obtainMessage(CMD_REMOVE_REQUEST, networkRequest));
+ }
+
+ /**
+ * Called by the bearer code when it has new LinkProperties data.
+ * If we're a registered NetworkAgent, this new data will get forwarded on,
+ * otherwise we store a copy in anticipation of registering. This call
+ * may also prompt registration if it causes the NetworkAgent to meet
+ * the conditions (fully configured, connected, satisfys a request and
+ * has sufficient score).
+ */
+ public void sendLinkProperties(LinkProperties linkProperties) {
+ linkProperties = new LinkProperties(linkProperties);
+ synchronized(mLockObj) {
+ mLinkProperties = linkProperties;
+ if (mAsyncChannel != null) {
+ mAsyncChannel.sendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, linkProperties);
+ } else {
+ registerSelf();
+ }
+ }
+ }
+
+ /**
+ * Called by the bearer code when it has new NetworkInfo data.
+ * If we're a registered NetworkAgent, this new data will get forwarded on,
+ * otherwise we store a copy in anticipation of registering. This call
+ * may also prompt registration if it causes the NetworkAgent to meet
+ * the conditions (fully configured, connected, satisfys a request and
+ * has sufficient score).
+ */
+ public void sendNetworkInfo(NetworkInfo networkInfo) {
+ networkInfo = new NetworkInfo(networkInfo);
+ synchronized(mLockObj) {
+ mNetworkInfo = networkInfo;
+ if (mAsyncChannel != null) {
+ mAsyncChannel.sendMessage(EVENT_NETWORK_INFO_CHANGED, networkInfo);
+ } else {
+ registerSelf();
+ }
+ }
+ }
+
+ /**
+ * Called by the bearer code when it has new NetworkCapabilities data.
+ * If we're a registered NetworkAgent, this new data will get forwarded on,
+ * otherwise we store a copy in anticipation of registering. This call
+ * may also prompt registration if it causes the NetworkAgent to meet
+ * the conditions (fully configured, connected, satisfys a request and
+ * has sufficient score).
+ * Note that if these capabilities make the network non-useful,
+ * ConnectivityServce will tear this network down.
+ */
+ public void sendNetworkCapabilities(NetworkCapabilities networkCapabilities) {
+ networkCapabilities = new NetworkCapabilities(networkCapabilities);
+ synchronized(mLockObj) {
+ mNetworkCapabilities = networkCapabilities;
+ if (mAsyncChannel != null) {
+ mAsyncChannel.sendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, networkCapabilities);
+ } else {
+ registerSelf();
+ }
+ }
+ }
+
+ public NetworkCapabilities getNetworkCapabilities() {
+ synchronized(mLockObj) {
+ return new NetworkCapabilities(mNetworkCapabilities);
+ }
+ }
+
+ /**
+ * Called by the bearer code when it has a new score for this network.
+ * If we're a registered NetworkAgent, this new data will get forwarded on,
+ * otherwise we store a copy.
+ */
+ public synchronized void sendNetworkScore(int score) {
+ synchronized(mLockObj) {
+ mNetworkScore = score;
+ evalScores();
+ if (mAsyncChannel != null) {
+ mAsyncChannel.sendMessage(EVENT_NETWORK_SCORE_CHANGED, mNetworkScore);
+ } else {
+ registerSelf();
+ }
+ }
+ }
+
+ public boolean hasRequests() {
+ return mHasRequests.get();
+ }
+
+ public boolean isConnectionRequested() {
+ synchronized(mLockObj) {
+ return mConnectionRequested;
+ }
+ }
+
+
+ abstract protected void connect();
+ abstract protected void disconnect();
+
+ protected void log(String s) {
+ Log.d(LOG_TAG, "NetworkAgent: " + s);
+ }
+}
diff --git a/core/java/android/net/NetworkCapabilities.aidl b/core/java/android/net/NetworkCapabilities.aidl
new file mode 100644
index 0000000..cd7d71c
--- /dev/null
+++ b/core/java/android/net/NetworkCapabilities.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright (C) 2014 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.net;
+
+parcelable NetworkCapabilities;
+
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
new file mode 100644
index 0000000..8005e5c
--- /dev/null
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.lang.IllegalArgumentException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * A class representing the capabilities of a network
+ * @hide
+ */
+public final class NetworkCapabilities implements Parcelable {
+ private static final String TAG = "NetworkCapabilities";
+ private static final boolean DBG = false;
+
+
+ /**
+ * Represents the network's capabilities. If any are specified they will be satisfied
+ * by any Network that matches all of them.
+ */
+ private long mNetworkCapabilities = (1 << NET_CAPABILITY_NOT_RESTRICTED);
+
+ /**
+ * Values for NetworkCapabilities. Roughly matches/extends deprecated
+ * ConnectivityManager TYPE_*
+ */
+ public static final int NET_CAPABILITY_MMS = 0;
+ public static final int NET_CAPABILITY_SUPL = 1;
+ public static final int NET_CAPABILITY_DUN = 2;
+ public static final int NET_CAPABILITY_FOTA = 3;
+ public static final int NET_CAPABILITY_IMS = 4;
+ public static final int NET_CAPABILITY_CBS = 5;
+ public static final int NET_CAPABILITY_WIFI_P2P = 6;
+ public static final int NET_CAPABILITY_IA = 7;
+ public static final int NET_CAPABILITY_RCS = 8;
+ public static final int NET_CAPABILITY_XCAP = 9;
+ public static final int NET_CAPABILITY_EIMS = 10;
+ public static final int NET_CAPABILITY_NOT_METERED = 11;
+ public static final int NET_CAPABILITY_INTERNET = 12;
+ /** Set by default */
+ public static final int NET_CAPABILITY_NOT_RESTRICTED = 13;
+
+ private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
+ private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_RESTRICTED;
+
+ public void addNetworkCapability(int networkCapability) {
+ if (networkCapability < MIN_NET_CAPABILITY ||
+ networkCapability > MAX_NET_CAPABILITY) {
+ throw new IllegalArgumentException("NetworkCapability out of range");
+ }
+ mNetworkCapabilities |= 1 << networkCapability;
+ }
+ public void removeNetworkCapability(int networkCapability) {
+ if (networkCapability < MIN_NET_CAPABILITY ||
+ networkCapability > MAX_NET_CAPABILITY) {
+ throw new IllegalArgumentException("NetworkCapability out of range");
+ }
+ mNetworkCapabilities &= ~(1 << networkCapability);
+ }
+ public Collection<Integer> getNetworkCapabilities() {
+ return enumerateBits(mNetworkCapabilities);
+ }
+ public boolean hasCapability(int networkCapability) {
+ if (networkCapability < MIN_NET_CAPABILITY ||
+ networkCapability > MAX_NET_CAPABILITY) {
+ return false;
+ }
+ return ((mNetworkCapabilities & (1 << networkCapability)) != 0);
+ }
+
+ private Collection<Integer> enumerateBits(long val) {
+ ArrayList<Integer> result = new ArrayList<Integer>();
+ int resource = 0;
+ while (val > 0) {
+ if ((val & 1) == 1) result.add(resource);
+ val = val >> 1;
+ resource++;
+ }
+ return result;
+ }
+
+ private void combineNetCapabilities(NetworkCapabilities nc) {
+ this.mNetworkCapabilities |= nc.mNetworkCapabilities;
+ }
+
+ private boolean satisfiedByNetCapabilities(NetworkCapabilities nc) {
+ return ((nc.mNetworkCapabilities & this.mNetworkCapabilities) == this.mNetworkCapabilities);
+ }
+
+ private boolean equalsNetCapabilities(NetworkCapabilities nc) {
+ return (nc.mNetworkCapabilities == this.mNetworkCapabilities);
+ }
+
+ /**
+ * Representing the transport type. Apps should generally not care about transport. A
+ * request for a fast internet connection could be satisfied by a number of different
+ * transports. If any are specified here it will be satisfied a Network that matches
+ * any of them. If a caller doesn't care about the transport it should not specify any.
+ */
+ private long mTransportTypes;
+
+ /**
+ * Values for TransportType
+ */
+ public static final int TRANSPORT_CELLULAR = 0;
+ public static final int TRANSPORT_WIFI = 1;
+ public static final int TRANSPORT_BLUETOOTH = 2;
+ public static final int TRANSPORT_ETHERNET = 3;
+
+ private static final int MIN_TRANSPORT = TRANSPORT_CELLULAR;
+ private static final int MAX_TRANSPORT = TRANSPORT_ETHERNET;
+
+ public void addTransportType(int transportType) {
+ if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
+ throw new IllegalArgumentException("TransportType out of range");
+ }
+ mTransportTypes |= 1 << transportType;
+ }
+ public void removeTransportType(int transportType) {
+ if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
+ throw new IllegalArgumentException("TransportType out of range");
+ }
+ mTransportTypes &= ~(1 << transportType);
+ }
+ public Collection<Integer> getTransportTypes() {
+ return enumerateBits(mTransportTypes);
+ }
+ public boolean hasTransport(int transportType) {
+ if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
+ return false;
+ }
+ return ((mTransportTypes & (1 << transportType)) != 0);
+ }
+
+ private void combineTransportTypes(NetworkCapabilities nc) {
+ this.mTransportTypes |= nc.mTransportTypes;
+ }
+ private boolean satisfiedByTransportTypes(NetworkCapabilities nc) {
+ return ((this.mTransportTypes == 0) ||
+ ((this.mTransportTypes & nc.mTransportTypes) != 0));
+ }
+ private boolean equalsTransportTypes(NetworkCapabilities nc) {
+ return (nc.mTransportTypes == this.mTransportTypes);
+ }
+
+ /**
+ * Passive link bandwidth. This is a rough guide of the expected peak bandwidth
+ * for the first hop on the given transport. It is not measured, but may take into account
+ * link parameters (Radio technology, allocated channels, etc).
+ */
+ private int mLinkUpBandwidthKbps;
+ private int mLinkDownBandwidthKbps;
+
+ public void setLinkUpstreamBandwidthKbps(int upKbps) {
+ mLinkUpBandwidthKbps = upKbps;
+ }
+ public int getLinkUpstreamBandwidthKbps() {
+ return mLinkUpBandwidthKbps;
+ }
+ public void setLinkDownstreamBandwidthKbps(int downKbps) {
+ mLinkDownBandwidthKbps = downKbps;
+ }
+ public int getLinkDownstreamBandwidthKbps() {
+ return mLinkDownBandwidthKbps;
+ }
+
+ private void combineLinkBandwidths(NetworkCapabilities nc) {
+ this.mLinkUpBandwidthKbps =
+ Math.max(this.mLinkUpBandwidthKbps, nc.mLinkUpBandwidthKbps);
+ this.mLinkDownBandwidthKbps =
+ Math.max(this.mLinkDownBandwidthKbps, nc.mLinkDownBandwidthKbps);
+ }
+ private boolean satisfiedByLinkBandwidths(NetworkCapabilities nc) {
+ return !(this.mLinkUpBandwidthKbps > nc.mLinkUpBandwidthKbps ||
+ this.mLinkDownBandwidthKbps > nc.mLinkDownBandwidthKbps);
+ }
+ private boolean equalsLinkBandwidths(NetworkCapabilities nc) {
+ return (this.mLinkUpBandwidthKbps == nc.mLinkUpBandwidthKbps &&
+ this.mLinkDownBandwidthKbps == nc.mLinkDownBandwidthKbps);
+ }
+
+ /**
+ * Combine a set of Capabilities to this one. Useful for coming up with the complete set
+ * {@hide}
+ */
+ public void combineCapabilities(NetworkCapabilities nc) {
+ combineNetCapabilities(nc);
+ combineTransportTypes(nc);
+ combineLinkBandwidths(nc);
+ }
+
+ /**
+ * Check if our requirements are satisfied by the given Capabilities.
+ * {@hide}
+ */
+ public boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc) {
+ return (nc != null &&
+ satisfiedByNetCapabilities(nc) &&
+ satisfiedByTransportTypes(nc) &&
+ satisfiedByLinkBandwidths(nc));
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || (obj instanceof NetworkCapabilities == false)) return false;
+ NetworkCapabilities that = (NetworkCapabilities)obj;
+ return (equalsNetCapabilities(that) &&
+ equalsTransportTypes(that) &&
+ equalsLinkBandwidths(that));
+ }
+
+ @Override
+ public int hashCode() {
+ return ((int)(mNetworkCapabilities & 0xFFFFFFFF) +
+ ((int)(mNetworkCapabilities >> 32) * 3) +
+ ((int)(mTransportTypes & 0xFFFFFFFF) * 5) +
+ ((int)(mTransportTypes >> 32) * 7) +
+ (mLinkUpBandwidthKbps * 11) +
+ (mLinkDownBandwidthKbps * 13));
+ }
+
+ public NetworkCapabilities() {
+ }
+
+ public NetworkCapabilities(NetworkCapabilities nc) {
+ if (nc != null) {
+ mNetworkCapabilities = nc.mNetworkCapabilities;
+ mTransportTypes = nc.mTransportTypes;
+ mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
+ mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
+ }
+ }
+
+ // Parcelable
+ public int describeContents() {
+ return 0;
+ }
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(mNetworkCapabilities);
+ dest.writeLong(mTransportTypes);
+ dest.writeInt(mLinkUpBandwidthKbps);
+ dest.writeInt(mLinkDownBandwidthKbps);
+ }
+ public static final Creator<NetworkCapabilities> CREATOR =
+ new Creator<NetworkCapabilities>() {
+ public NetworkCapabilities createFromParcel(Parcel in) {
+ NetworkCapabilities netCap = new NetworkCapabilities();
+
+ netCap.mNetworkCapabilities = in.readLong();
+ netCap.mTransportTypes = in.readLong();
+ netCap.mLinkUpBandwidthKbps = in.readInt();
+ netCap.mLinkDownBandwidthKbps = in.readInt();
+ return netCap;
+ }
+ public NetworkCapabilities[] newArray(int size) {
+ return new NetworkCapabilities[size];
+ }
+ };
+
+ public String toString() {
+ Collection<Integer> types = getTransportTypes();
+ String transports = (types.size() > 0 ? " Transports: " : "");
+ Iterator<Integer> i = types.iterator();
+ while (i.hasNext()) {
+ switch (i.next()) {
+ case TRANSPORT_CELLULAR: transports += "CELLULAR"; break;
+ case TRANSPORT_WIFI: transports += "WIFI"; break;
+ case TRANSPORT_BLUETOOTH: transports += "BLUETOOTH"; break;
+ case TRANSPORT_ETHERNET: transports += "ETHERNET"; break;
+ }
+ if (i.hasNext()) transports += "|";
+ }
+
+ types = getNetworkCapabilities();
+ String capabilities = (types.size() > 0 ? " Capabilities: " : "");
+ i = types.iterator();
+ while (i.hasNext()) {
+ switch (i.next().intValue()) {
+ case NET_CAPABILITY_MMS: capabilities += "MMS"; break;
+ case NET_CAPABILITY_SUPL: capabilities += "SUPL"; break;
+ case NET_CAPABILITY_DUN: capabilities += "DUN"; break;
+ case NET_CAPABILITY_FOTA: capabilities += "FOTA"; break;
+ case NET_CAPABILITY_IMS: capabilities += "IMS"; break;
+ case NET_CAPABILITY_CBS: capabilities += "CBS"; break;
+ case NET_CAPABILITY_WIFI_P2P: capabilities += "WIFI_P2P"; break;
+ case NET_CAPABILITY_IA: capabilities += "IA"; break;
+ case NET_CAPABILITY_RCS: capabilities += "RCS"; break;
+ case NET_CAPABILITY_XCAP: capabilities += "XCAP"; break;
+ case NET_CAPABILITY_EIMS: capabilities += "EIMS"; break;
+ case NET_CAPABILITY_NOT_METERED: capabilities += "NOT_METERED"; break;
+ case NET_CAPABILITY_INTERNET: capabilities += "INTERNET"; break;
+ case NET_CAPABILITY_NOT_RESTRICTED: capabilities += "NOT_RESTRICTED"; break;
+ }
+ if (i.hasNext()) capabilities += "&";
+ }
+
+ String upBand = ((mLinkUpBandwidthKbps > 0) ? " LinkUpBandwidth>=" +
+ mLinkUpBandwidthKbps + "Kbps" : "");
+ String dnBand = ((mLinkDownBandwidthKbps > 0) ? " LinkDnBandwidth>=" +
+ mLinkDownBandwidthKbps + "Kbps" : "");
+
+ return "[" + transports + capabilities + upBand + dnBand + "]";
+ }
+}
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 53b1308..9e656ee 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -420,7 +420,7 @@
@Override
public String toString() {
synchronized (this) {
- StringBuilder builder = new StringBuilder("NetworkInfo: ");
+ StringBuilder builder = new StringBuilder("[");
builder.append("type: ").append(getTypeName()).append("[").append(getSubtypeName()).
append("], state: ").append(mState).append("/").append(mDetailedState).
append(", reason: ").append(mReason == null ? "(unspecified)" : mReason).
@@ -429,7 +429,8 @@
append(", failover: ").append(mIsFailover).
append(", isAvailable: ").append(mIsAvailable).
append(", isConnectedToProvisioningNetwork: ").
- append(mIsConnectedToProvisioningNetwork);
+ append(mIsConnectedToProvisioningNetwork).
+ append("]");
return builder.toString();
}
}
diff --git a/core/java/android/net/NetworkRequest.aidl b/core/java/android/net/NetworkRequest.aidl
new file mode 100644
index 0000000..508defc
--- /dev/null
+++ b/core/java/android/net/NetworkRequest.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable NetworkRequest;
+
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
new file mode 100644
index 0000000..b3ae3f5
--- /dev/null
+++ b/core/java/android/net/NetworkRequest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @hide
+ */
+public class NetworkRequest implements Parcelable {
+ /**
+ * The NetworkCapabilities that define this request
+ */
+ public final NetworkCapabilities networkCapabilities;
+
+ /**
+ * Identifies the request. NetworkRequests should only be constructed by
+ * the Framework and given out to applications as tokens to be used to identify
+ * the request.
+ * TODO - make sure this input is checked whenever a NR is passed in a public API
+ */
+ public final int requestId;
+
+ /**
+ * Set for legacy requests and the default.
+ * Causes CONNECTIVITY_ACTION broadcasts to be sent.
+ * @hide
+ */
+ public final boolean needsBroadcasts;
+
+ private static final AtomicInteger sNextRequestId = new AtomicInteger(1);
+
+ /**
+ * @hide
+ */
+ public NetworkRequest(NetworkCapabilities nc) {
+ this(nc, false, sNextRequestId.getAndIncrement());
+ }
+
+ /**
+ * @hide
+ */
+ public NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts) {
+ this(nc, needsBroadcasts, sNextRequestId.getAndIncrement());
+ }
+
+ /**
+ * @hide
+ */
+ private NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts, int rId) {
+ requestId = rId;
+ networkCapabilities = nc;
+ this.needsBroadcasts = needsBroadcasts;
+ }
+
+ public NetworkRequest(NetworkRequest that) {
+ networkCapabilities = new NetworkCapabilities(that.networkCapabilities);
+ requestId = that.requestId;
+ needsBroadcasts = that.needsBroadcasts;
+ }
+
+ // implement the Parcelable interface
+ public int describeContents() {
+ return 0;
+ }
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(networkCapabilities, flags);
+ dest.writeInt(needsBroadcasts ? 1 : 0);
+ dest.writeInt(requestId);
+ }
+ public static final Creator<NetworkRequest> CREATOR =
+ new Creator<NetworkRequest>() {
+ public NetworkRequest createFromParcel(Parcel in) {
+ NetworkCapabilities nc = (NetworkCapabilities)in.readParcelable(null);
+ boolean needsBroadcasts = (in.readInt() == 1);
+ int requestId = in.readInt();
+ NetworkRequest result = new NetworkRequest(nc, needsBroadcasts, requestId);
+ return result;
+ }
+ public NetworkRequest[] newArray(int size) {
+ return new NetworkRequest[size];
+ }
+ };
+
+ public String toString() {
+ return "NetworkRequest [ id=" + requestId + ", needsBroadcasts=" + needsBroadcasts +
+ ", " + networkCapabilities.toString() + " ]";
+ }
+
+ public boolean equals(Object obj) {
+ if (obj instanceof NetworkRequest == false) return false;
+ NetworkRequest that = (NetworkRequest)obj;
+ return (that.needsBroadcasts == this.needsBroadcasts &&
+ that.requestId == this.requestId &&
+ ((that.networkCapabilities == null && this.networkCapabilities == null) ||
+ (that.networkCapabilities != null &&
+ that.networkCapabilities.equals(this.networkCapabilities))));
+ }
+
+ public int hashCode() {
+ return requestId + (needsBroadcasts ? 1013 : 2026) +
+ (networkCapabilities.hashCode() * 1051);
+ }
+}
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index fbe1f82..2e0e9e4 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -28,21 +28,21 @@
public final NetworkInfo networkInfo;
public final LinkProperties linkProperties;
- public final LinkCapabilities linkCapabilities;
+ public final NetworkCapabilities networkCapabilities;
/** Currently only used by testing. */
public final String subscriberId;
public final String networkId;
public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
- LinkCapabilities linkCapabilities) {
- this(networkInfo, linkProperties, linkCapabilities, null, null);
+ NetworkCapabilities networkCapabilities) {
+ this(networkInfo, linkProperties, networkCapabilities, null, null);
}
public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
- LinkCapabilities linkCapabilities, String subscriberId, String networkId) {
+ NetworkCapabilities networkCapabilities, String subscriberId, String networkId) {
this.networkInfo = networkInfo;
this.linkProperties = linkProperties;
- this.linkCapabilities = linkCapabilities;
+ this.networkCapabilities = networkCapabilities;
this.subscriberId = subscriberId;
this.networkId = networkId;
}
@@ -50,7 +50,7 @@
public NetworkState(Parcel in) {
networkInfo = in.readParcelable(null);
linkProperties = in.readParcelable(null);
- linkCapabilities = in.readParcelable(null);
+ networkCapabilities = in.readParcelable(null);
subscriberId = in.readString();
networkId = in.readString();
}
@@ -64,7 +64,7 @@
public void writeToParcel(Parcel out, int flags) {
out.writeParcelable(networkInfo, flags);
out.writeParcelable(linkProperties, flags);
- out.writeParcelable(linkCapabilities, flags);
+ out.writeParcelable(networkCapabilities, flags);
out.writeString(subscriberId);
out.writeString(networkId);
}
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index c49b1d1..35500cc 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -111,12 +111,9 @@
public LinkProperties getLinkProperties();
/**
- * A capability is an Integer/String pair, the capabilities
- * are defined in the class LinkSocket#Key.
- *
* @return a copy of this connections capabilities, may be empty but never null.
*/
- public LinkCapabilities getLinkCapabilities();
+ public NetworkCapabilities getNetworkCapabilities();
/**
* Get interesting information about this network link
@@ -250,4 +247,14 @@
*/
public void stopSampling(SamplingDataTracker.SamplingSnapshot s);
+ /*
+ * Record the current netId
+ */
+ public void setNetId(int netId);
+
+ /*
+ * ?
+ */
+ public Network getNetwork();
+
}
diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java
index 8f41e85..6a78c29 100644
--- a/core/java/android/net/Proxy.java
+++ b/core/java/android/net/Proxy.java
@@ -273,19 +273,19 @@
String host = null;
String port = null;
String exclList = null;
- String pacFileUrl = null;
+ Uri pacFileUrl = Uri.EMPTY;
if (p != null) {
host = p.getHost();
port = Integer.toString(p.getPort());
exclList = p.getExclusionListAsString();
- pacFileUrl = p.getPacFileUrl().toString();
+ pacFileUrl = p.getPacFileUrl();
}
setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
}
/** @hide */
public static final void setHttpProxySystemProperty(String host, String port, String exclList,
- String pacFileUrl) {
+ Uri pacFileUrl) {
if (exclList != null) exclList = exclList.replace(",", "|");
if (false) Log.d(TAG, "setHttpProxySystemProperty :"+host+":"+port+" - "+exclList);
if (host != null) {
@@ -309,7 +309,7 @@
System.clearProperty("http.nonProxyHosts");
System.clearProperty("https.nonProxyHosts");
}
- if (!TextUtils.isEmpty(pacFileUrl)) {
+ if (!Uri.EMPTY.equals(pacFileUrl)) {
ProxySelector.setDefault(new PacProxySelector());
} else {
ProxySelector.setDefault(sDefaultProxySelector);
diff --git a/core/java/android/net/ProxyDataTracker.java b/core/java/android/net/ProxyDataTracker.java
index 461e8b8..4973b3d 100644
--- a/core/java/android/net/ProxyDataTracker.java
+++ b/core/java/android/net/ProxyDataTracker.java
@@ -104,7 +104,7 @@
public ProxyDataTracker() {
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_PROXY, 0, NETWORK_TYPE, "");
mLinkProperties = new LinkProperties();
- mLinkCapabilities = new LinkCapabilities();
+ mNetworkCapabilities = new NetworkCapabilities();
mNetworkInfo.setIsAvailable(true);
try {
mLinkProperties.addDns(InetAddress.getByName(DNS1));
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index b40941f..ceedd98 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -44,7 +44,7 @@
private String mExclusionList;
private String[] mParsedExclusionList;
- private String mPacFileUrl;
+ private Uri mPacFileUrl;
/**
*@hide
*/
@@ -85,7 +85,7 @@
* at the specified URL.
*/
public static ProxyInfo buildPacProxy(Uri pacUri) {
- return new ProxyInfo(pacUri.toString());
+ return new ProxyInfo(pacUri);
}
/**
@@ -96,6 +96,21 @@
mHost = host;
mPort = port;
setExclusionList(exclList);
+ mPacFileUrl = Uri.EMPTY;
+ }
+
+ /**
+ * Create a ProxyProperties that points at a PAC URL.
+ * @hide
+ */
+ public ProxyInfo(Uri pacFileUrl) {
+ mHost = LOCAL_HOST;
+ mPort = LOCAL_PORT;
+ setExclusionList(LOCAL_EXCL_LIST);
+ if (pacFileUrl == null) {
+ throw new NullPointerException();
+ }
+ mPacFileUrl = pacFileUrl;
}
/**
@@ -106,17 +121,20 @@
mHost = LOCAL_HOST;
mPort = LOCAL_PORT;
setExclusionList(LOCAL_EXCL_LIST);
- mPacFileUrl = pacFileUrl;
+ mPacFileUrl = Uri.parse(pacFileUrl);
}
/**
* Only used in PacManager after Local Proxy is bound.
* @hide
*/
- public ProxyInfo(String pacFileUrl, int localProxyPort) {
+ public ProxyInfo(Uri pacFileUrl, int localProxyPort) {
mHost = LOCAL_HOST;
mPort = localProxyPort;
setExclusionList(LOCAL_EXCL_LIST);
+ if (pacFileUrl == null) {
+ throw new NullPointerException();
+ }
mPacFileUrl = pacFileUrl;
}
@@ -125,7 +143,7 @@
mPort = port;
mExclusionList = exclList;
mParsedExclusionList = parsedExclList;
- mPacFileUrl = null;
+ mPacFileUrl = Uri.EMPTY;
}
// copy constructor instead of clone
@@ -137,8 +155,13 @@
mHost = source.getHost();
mPort = source.getPort();
mPacFileUrl = source.mPacFileUrl;
+ if (mPacFileUrl == null) {
+ mPacFileUrl = Uri.EMPTY;
+ }
mExclusionList = source.getExclusionListAsString();
mParsedExclusionList = source.mParsedExclusionList;
+ } else {
+ mPacFileUrl = Uri.EMPTY;
}
}
@@ -158,10 +181,7 @@
* no PAC script.
*/
public Uri getPacFileUrl() {
- if (TextUtils.isEmpty(mPacFileUrl)) {
- return null;
- }
- return Uri.parse(mPacFileUrl);
+ return mPacFileUrl;
}
/**
@@ -210,7 +230,7 @@
* @hide
*/
public boolean isValid() {
- if (!TextUtils.isEmpty(mPacFileUrl)) return true;
+ if (!Uri.EMPTY.equals(mPacFileUrl)) return true;
return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost,
mPort == 0 ? "" : Integer.toString(mPort),
mExclusionList == null ? "" : mExclusionList);
@@ -234,7 +254,7 @@
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- if (mPacFileUrl != null) {
+ if (!Uri.EMPTY.equals(mPacFileUrl)) {
sb.append("PAC Script: ");
sb.append(mPacFileUrl);
} else if (mHost != null) {
@@ -257,13 +277,15 @@
ProxyInfo p = (ProxyInfo)o;
// If PAC URL is present in either then they must be equal.
// Other parameters will only be for fall back.
- if (!TextUtils.isEmpty(mPacFileUrl)) {
+ if (!Uri.EMPTY.equals(mPacFileUrl)) {
return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort;
}
- if (!TextUtils.isEmpty(p.mPacFileUrl)) {
+ if (!Uri.EMPTY.equals(p.mPacFileUrl)) {
return false;
}
- if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) return false;
+ if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) {
+ return false;
+ }
if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) {
return false;
}
@@ -296,9 +318,9 @@
* @hide
*/
public void writeToParcel(Parcel dest, int flags) {
- if (mPacFileUrl != null) {
+ if (!Uri.EMPTY.equals(mPacFileUrl)) {
dest.writeByte((byte)1);
- dest.writeString(mPacFileUrl);
+ mPacFileUrl.writeToParcel(dest, 0);
dest.writeInt(mPort);
return;
} else {
@@ -325,7 +347,7 @@
String host = null;
int port = 0;
if (in.readByte() != 0) {
- String url = in.readString();
+ Uri url = Uri.CREATOR.createFromParcel(in);
int localPort = in.readInt();
return new ProxyInfo(url, localPort);
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 8b7467f..4857533 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -21,6 +21,7 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.Formatter;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -30,6 +31,8 @@
import android.text.format.DateFormat;
import android.util.Printer;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.util.TimeUtils;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
@@ -537,6 +540,7 @@
public static final byte CMD_START = 4;
public static final byte CMD_CURRENT_TIME = 5;
public static final byte CMD_OVERFLOW = 6;
+ public static final byte CMD_RESET = 7;
public byte cmd = CMD_NULL;
@@ -620,6 +624,8 @@
public static final int EVENT_SYNC = 0x0004;
// Number of event types.
public static final int EVENT_COUNT = 0x0005;
+ // Mask to extract out only the type part of the event.
+ public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
public static final int EVENT_PROC_START = EVENT_PROC | EVENT_FLAG_START;
public static final int EVENT_PROC_FINISH = EVENT_PROC | EVENT_FLAG_FINISH;
@@ -684,7 +690,7 @@
dest.writeInt(eventCode);
eventTag.writeToParcel(dest, flags);
}
- if (cmd == CMD_CURRENT_TIME) {
+ if (cmd == CMD_CURRENT_TIME || cmd == CMD_RESET) {
dest.writeLong(currentTime);
}
}
@@ -722,7 +728,7 @@
eventCode = EVENT_NONE;
eventTag = null;
}
- if (cmd == CMD_CURRENT_TIME) {
+ if (cmd == CMD_CURRENT_TIME || cmd == CMD_RESET) {
currentTime = src.readLong();
} else {
currentTime = 0;
@@ -833,7 +839,59 @@
return true;
}
}
-
+
+ public final static class HistoryEventTracker {
+ private final HashMap<String, SparseIntArray>[] mActiveEvents
+ = (HashMap<String, SparseIntArray>[]) new HashMap[HistoryItem.EVENT_COUNT];
+
+ public boolean updateState(int code, String name, int uid, int poolIdx) {
+ if ((code&HistoryItem.EVENT_FLAG_START) != 0) {
+ int idx = code&HistoryItem.EVENT_TYPE_MASK;
+ HashMap<String, SparseIntArray> active = mActiveEvents[idx];
+ if (active == null) {
+ active = new HashMap<String, SparseIntArray>();
+ mActiveEvents[idx] = active;
+ }
+ SparseIntArray uids = active.get(name);
+ if (uids == null) {
+ uids = new SparseIntArray();
+ active.put(name, uids);
+ }
+ if (uids.indexOfKey(uid) >= 0) {
+ // Already set, nothing to do!
+ return false;
+ }
+ uids.put(uid, poolIdx);
+ } else if ((code&HistoryItem.EVENT_FLAG_FINISH) != 0) {
+ int idx = code&HistoryItem.EVENT_TYPE_MASK;
+ HashMap<String, SparseIntArray> active = mActiveEvents[idx];
+ if (active == null) {
+ // not currently active, nothing to do.
+ return false;
+ }
+ SparseIntArray uids = active.get(name);
+ if (uids == null) {
+ // not currently active, nothing to do.
+ return false;
+ }
+ idx = uids.indexOfKey(uid);
+ if (idx < 0) {
+ // not currently active, nothing to do.
+ return false;
+ }
+ uids.removeAt(idx);
+ if (uids.size() <= 0) {
+ active.remove(name);
+ }
+ }
+ return true;
+ }
+
+ public HashMap<String, SparseIntArray> getStateForEvent(int code) {
+ return mActiveEvents[code];
+ }
+ }
+
public static final class BitDescription {
public final int mask;
public final int shift;
@@ -861,7 +919,7 @@
this.shortValues = shortValues;
}
}
-
+
public abstract int getHistoryTotalSize();
public abstract int getHistoryUsedSize();
@@ -2958,10 +3016,14 @@
pw.print(":");
}
pw.println("START");
- } else if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) {
+ } else if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
+ || rec.cmd == HistoryItem.CMD_RESET) {
if (checkin) {
pw.print(":");
}
+ if (rec.cmd == HistoryItem.CMD_RESET) {
+ pw.print("RESET:");
+ }
pw.print("TIME:");
if (checkin) {
pw.println(rec.currentTime);
@@ -3187,6 +3249,86 @@
public static final int DUMP_INCLUDE_HISTORY = 1<<3;
public static final int DUMP_VERBOSE = 1<<4;
+ private void dumpHistoryLocked(PrintWriter pw, int flags, long histStart, boolean checkin) {
+ final HistoryPrinter hprinter = new HistoryPrinter();
+ final HistoryItem rec = new HistoryItem();
+ long lastTime = -1;
+ long baseTime = -1;
+ boolean printed = false;
+ HistoryEventTracker tracker = null;
+ while (getNextHistoryLocked(rec)) {
+ lastTime = rec.time;
+ if (baseTime < 0) {
+ baseTime = lastTime;
+ }
+ if (rec.time >= histStart) {
+ if (histStart >= 0 && !printed) {
+ if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
+ || rec.cmd == HistoryItem.CMD_RESET) {
+ printed = true;
+ } else if (rec.currentTime != 0) {
+ printed = true;
+ byte cmd = rec.cmd;
+ rec.cmd = HistoryItem.CMD_CURRENT_TIME;
+ if (checkin) {
+ pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+ pw.print(HISTORY_DATA); pw.print(',');
+ }
+ hprinter.printNextItem(pw, rec, baseTime, checkin,
+ (flags&DUMP_VERBOSE) != 0);
+ rec.cmd = cmd;
+ }
+ if (tracker != null) {
+ int oldCode = rec.eventCode;
+ HistoryTag oldTag = rec.eventTag;
+ rec.eventTag = new HistoryTag();
+ for (int i=0; i<HistoryItem.EVENT_COUNT; i++) {
+ HashMap<String, SparseIntArray> active
+ = tracker.getStateForEvent(i);
+ if (active == null) {
+ continue;
+ }
+ for (HashMap.Entry<String, SparseIntArray> ent
+ : active.entrySet()) {
+ SparseIntArray uids = ent.getValue();
+ for (int j=0; j<uids.size(); j++) {
+ rec.eventCode = i;
+ rec.eventTag.string = ent.getKey();
+ rec.eventTag.uid = uids.keyAt(j);
+ rec.eventTag.poolIdx = uids.valueAt(j);
+ if (checkin) {
+ pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+ pw.print(HISTORY_DATA); pw.print(',');
+ }
+ hprinter.printNextItem(pw, rec, baseTime, checkin,
+ (flags&DUMP_VERBOSE) != 0);
+ }
+ }
+ }
+ rec.eventCode = oldCode;
+ rec.eventTag = oldTag;
+ tracker = null;
+ }
+ }
+ if (checkin) {
+ pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+ pw.print(HISTORY_DATA); pw.print(',');
+ }
+ hprinter.printNextItem(pw, rec, baseTime, checkin,
+ (flags&DUMP_VERBOSE) != 0);
+ } else if (rec.eventCode != HistoryItem.EVENT_NONE) {
+ if (tracker == null) {
+ tracker = new HistoryEventTracker();
+ }
+ tracker.updateState(rec.eventCode, rec.eventTag.string,
+ rec.eventTag.uid, rec.eventTag.poolIdx);
+ }
+ }
+ if (histStart >= 0) {
+ pw.print(checkin ? "NEXT: " : " NEXT: "); pw.println(lastTime+1);
+ }
+ }
+
/**
* Dumps a human-readable summary of the battery statistics to the given PrintWriter.
*
@@ -3200,9 +3342,6 @@
(flags&(DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) != 0;
if ((flags&DUMP_HISTORY_ONLY) != 0 || !filtering) {
- long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
-
- final HistoryItem rec = new HistoryItem();
final long historyTotalSize = getHistoryTotalSize();
final long historyUsedSize = getHistoryUsedSize();
if (startIteratingHistoryLocked()) {
@@ -3218,35 +3357,7 @@
pw.print(" strings using ");
printSizeValue(pw, getHistoryStringPoolBytes());
pw.println("):");
- HistoryPrinter hprinter = new HistoryPrinter();
- long lastTime = -1;
- long baseTime = -1;
- boolean printed = false;
- while (getNextHistoryLocked(rec)) {
- lastTime = rec.time;
- if (baseTime < 0) {
- baseTime = lastTime;
- }
- if (rec.time >= histStart) {
- if (histStart >= 0 && !printed) {
- if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) {
- printed = true;
- } else if (rec.currentTime != 0) {
- printed = true;
- byte cmd = rec.cmd;
- rec.cmd = HistoryItem.CMD_CURRENT_TIME;
- hprinter.printNextItem(pw, rec, baseTime, false,
- (flags&DUMP_VERBOSE) != 0);
- rec.cmd = cmd;
- }
- }
- hprinter.printNextItem(pw, rec, baseTime, false,
- (flags&DUMP_VERBOSE) != 0);
- }
- }
- if (histStart >= 0) {
- pw.print(" NEXT: "); pw.println(lastTime+1);
- }
+ dumpHistoryLocked(pw, flags, histStart, false);
pw.println();
} finally {
finishIteratingHistoryLocked();
@@ -3255,6 +3366,7 @@
if (startIteratingOldHistoryLocked()) {
try {
+ final HistoryItem rec = new HistoryItem();
pw.println("Old battery History:");
HistoryPrinter hprinter = new HistoryPrinter();
long baseTime = -1;
@@ -3348,7 +3460,6 @@
(flags&(DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) != 0;
if ((flags&DUMP_INCLUDE_HISTORY) != 0 || (flags&DUMP_HISTORY_ONLY) != 0) {
- final HistoryItem rec = new HistoryItem();
if (startIteratingHistoryLocked()) {
try {
for (int i=0; i<getHistoryStringPoolSize(); i++) {
@@ -3365,37 +3476,7 @@
pw.print("\"");
pw.println();
}
- HistoryPrinter hprinter = new HistoryPrinter();
- long lastTime = -1;
- long baseTime = -1;
- boolean printed = false;
- while (getNextHistoryLocked(rec)) {
- lastTime = rec.time;
- if (baseTime < 0) {
- baseTime = lastTime;
- }
- if (rec.time >= histStart) {
- if (histStart >= 0 && !printed) {
- if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) {
- printed = true;
- } else if (rec.currentTime != 0) {
- printed = true;
- byte cmd = rec.cmd;
- rec.cmd = HistoryItem.CMD_CURRENT_TIME;
- pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
- pw.print(HISTORY_DATA); pw.print(',');
- hprinter.printNextItem(pw, rec, baseTime, true, false);
- rec.cmd = cmd;
- }
- }
- pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
- pw.print(HISTORY_DATA); pw.print(',');
- hprinter.printNextItem(pw, rec, baseTime, true, false);
- }
- }
- if (histStart >= 0) {
- pw.print("NEXT: "); pw.println(lastTime+1);
- }
+ dumpHistoryLocked(pw, flags, histStart, true);
} finally {
finishIteratingHistoryLocked();
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 1ca6b90..a7485b4 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -88,7 +88,8 @@
*
* @hide
*/
- public static final String[] SUPPORTED_ABIS = getString("ro.product.cpu.abilist").split(",");
+ public static final String[] SUPPORTED_ABIS = SystemProperties.get("ro.product.cpu.abilist")
+ .split(",");
/**
* An ordered list of <b>32 bit</b> ABIs supported by this device. The most preferred ABI
@@ -98,8 +99,8 @@
*
* @hide
*/
- public static final String[] SUPPORTED_32_BIT_ABIS = getString("ro.product.cpu.abilist32")
- .split(",");
+ public static final String[] SUPPORTED_32_BIT_ABIS =
+ SystemProperties.get("ro.product.cpu.abilist32").split(",");
/**
* An ordered list of <b>64 bit</b> ABIs supported by this device. The most preferred ABI
@@ -109,8 +110,8 @@
*
* @hide
*/
- public static final String[] SUPPORTED_64_BIT_ABIS = getString("ro.product.cpu.abilist64")
- .split(",");
+ public static final String[] SUPPORTED_64_BIT_ABIS =
+ SystemProperties.get("ro.product.cpu.abilist64").split(",");
/** Various version strings. */
@@ -515,9 +516,16 @@
public static final int KITKAT = 19;
/**
- * Android 4.5: KitKat for watches, snacks on the run.
+ * Android 4.4W: KitKat for watches, snacks on the run.
+ *
+ * <p>Applications targeting this or a later release will get these
+ * new changes in behavior:</p>
+ * <ul>
+ * <li>{@link android.app.AlertDialog} might not have a default background if the theme does
+ * not specify one.</li>
+ * </ul>
*/
- public static final int KITKAT_WATCH = CUR_DEVELOPMENT; // STOPSHIP: update API level
+ public static final int KITKAT_WATCH = 20;
/**
* L!
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index d71c3e6..1dba77d 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -17,6 +17,7 @@
package android.os;
import android.system.ErrnoException;
+import android.text.TextUtils;
import android.system.Os;
import android.system.OsConstants;
import android.util.Log;
@@ -382,4 +383,32 @@
}
return filePath.startsWith(dirPath);
}
+
+ public static void deleteContents(File dir) {
+ File[] files = dir.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ if (file.isDirectory()) {
+ deleteContents(file);
+ }
+ file.delete();
+ }
+ }
+ }
+
+ /**
+ * Assert that given filename is valid on ext4.
+ */
+ public static boolean isValidExtFilename(String name) {
+ if (TextUtils.isEmpty(name) || ".".equals(name) || "..".equals(name)) {
+ return false;
+ }
+ for (int i = 0; i < name.length(); i++) {
+ final char c = name.charAt(i);
+ if (c == '\0' || c == '/') {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index f5ff185..eb9ba13 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -99,24 +99,12 @@
/**
* Add the specified route to the interface.
*/
- void addRoute(String iface, in RouteInfo route);
+ void addRoute(int netId, in RouteInfo route);
/**
* Remove the specified route from the interface.
*/
- void removeRoute(String iface, in RouteInfo route);
-
- /**
- * Add the specified route to a secondary interface
- * This will go into a special route table to be accessed
- * via ip rules
- */
- void addSecondaryRoute(String iface, in RouteInfo route);
-
- /**
- * Remove the specified secondary route.
- */
- void removeSecondaryRoute(String iface, in RouteInfo route);
+ void removeRoute(int netId, in RouteInfo route);
/**
* Set the specified MTU size
@@ -320,24 +308,14 @@
void removeIdleTimer(String iface);
/**
- * Sets the name of the default interface in the DNS resolver.
+ * Bind name servers to a network in the DNS resolver.
*/
- void setDefaultInterfaceForDns(String iface);
+ void setDnsServersForNetwork(int netId, in String[] servers, String domains);
/**
- * Bind name servers to an interface in the DNS resolver.
+ * Flush the DNS cache associated with the specified network.
*/
- void setDnsServersForInterface(String iface, in String[] servers, String domains);
-
- /**
- * Flush the DNS cache associated with the default interface.
- */
- void flushDefaultDnsCache();
-
- /**
- * Flush the DNS cache associated with the specified interface.
- */
- void flushInterfaceDnsCache(String iface);
+ void flushNetworkDnsCache(int netId);
void setFirewallEnabled(boolean enabled);
boolean isFirewallEnabled();
@@ -350,7 +328,7 @@
* Set all packets from users [uid_start,uid_end] to go through interface iface
* iface must already be set for marked forwarding by {@link setMarkedForwarding}
*/
- void setUidRangeRoute(String iface, int uid_start, int uid_end);
+ void setUidRangeRoute(String iface, int uid_start, int uid_end, boolean forward_dns);
/**
* Clears the special routing rules for users [uid_start,uid_end]
@@ -402,31 +380,6 @@
void clearHostExemption(in LinkAddress host);
/**
- * Set a process (pid) to use the name servers associated with the specified interface.
- */
- void setDnsInterfaceForPid(String iface, int pid);
-
- /**
- * Clear a process (pid) from being associated with an interface.
- */
- void clearDnsInterfaceForPid(int pid);
-
- /**
- * Set a range of user ids to use the name servers associated with the specified interface.
- */
- void setDnsInterfaceForUidRange(String iface, int uid_start, int uid_end);
-
- /**
- * Clear a user range from being associated with an interface.
- */
- void clearDnsInterfaceForUidRange(String iface, int uid_start, int uid_end);
-
- /**
- * Clear the mappings from pid to Dns interface and from uid range to Dns interface.
- */
- void clearDnsInterfaceMaps();
-
- /**
* Start the clatd (464xlat) service
*/
void startClatd(String interfaceName);
@@ -455,4 +408,33 @@
* Check whether the mobile radio is currently active.
*/
boolean isNetworkActive();
+
+ /**
+ * Setup a new network.
+ */
+ void createNetwork(int netId);
+
+ /**
+ * Remove a network.
+ */
+ void removeNetwork(int netId);
+
+ /**
+ * Add an interface to a network.
+ */
+ void addInterfaceToNetwork(String iface, int netId);
+
+ /**
+ * Remove an Interface from a network.
+ */
+ void removeInterfaceFromNetwork(String iface, int netId);
+
+ void addLegacyRouteForNetId(int netId, in RouteInfo routeInfo, int uid);
+ void removeLegacyRouteForNetId(int netId, in RouteInfo routeInfo, int uid);
+
+ void setDefaultNetId(int netId);
+ void clearDefaultNetId();
+
+ void setPermission(boolean internal, boolean changeNetState, in int[] uids);
+ void clearPermission(in int[] uids);
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index f8d7c3e..5b2c8db 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -366,15 +366,6 @@
}
/**
- * Returns true if the screen auto-brightness adjustment setting should
- * be available in the UI. This setting is experimental and disabled by default.
- * @hide
- */
- public static boolean useScreenAutoBrightnessAdjustmentFeature() {
- return SystemProperties.getBoolean("persist.power.useautobrightadj", false);
- }
-
- /**
* Returns true if the twilight service should be used to adjust screen brightness
* policy. This setting is experimental and disabled by default.
* @hide
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 1b3aa0a..112ec1d 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -31,13 +31,17 @@
import java.util.List;
/*package*/ class ZygoteStartFailedEx extends Exception {
- /**
- * Something prevented the zygote process startup from happening normally
- */
+ ZygoteStartFailedEx(String s) {
+ super(s);
+ }
- ZygoteStartFailedEx() {};
- ZygoteStartFailedEx(String s) {super(s);}
- ZygoteStartFailedEx(Throwable cause) {super(cause);}
+ ZygoteStartFailedEx(Throwable cause) {
+ super(cause);
+ }
+
+ ZygoteStartFailedEx(String s, Throwable cause) {
+ super(s, cause);
+ }
}
/**
@@ -46,9 +50,15 @@
public class Process {
private static final String LOG_TAG = "Process";
- private static final String ZYGOTE_SOCKET = "zygote";
+ /**
+ * @hide for internal use only.
+ */
+ public static final String ZYGOTE_SOCKET = "zygote";
- private static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";
+ /**
+ * @hide for internal use only.
+ */
+ public static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";
/**
* Defines the UID/GID under which system code runs.
@@ -338,8 +348,10 @@
/**
* State for communicating with the zygote process.
+ *
+ * @hide for internal use only.
*/
- static class ZygoteState {
+ public static class ZygoteState {
final LocalSocket socket;
final DataInputStream inputStream;
final BufferedWriter writer;
@@ -355,55 +367,26 @@
this.abiList = abiList;
}
- static ZygoteState connect(String socketAddress, int tries) throws ZygoteStartFailedEx {
- LocalSocket zygoteSocket = null;
+ public static ZygoteState connect(String socketAddress) throws IOException {
DataInputStream zygoteInputStream = null;
BufferedWriter zygoteWriter = null;
+ final LocalSocket zygoteSocket = new LocalSocket();
- /*
- * See bug #811181: Sometimes runtime can make it up before zygote.
- * Really, we'd like to do something better to avoid this condition,
- * but for now just wait a bit...
- *
- * TODO: This bug was filed in 2007. Get rid of this code. The zygote
- * forks the system_server so it shouldn't be possible for the zygote
- * socket to be brought up after the system_server is.
- */
- for (int i = 0; i < tries; i++) {
- if (i > 0) {
- try {
- Log.i(LOG_TAG, "Zygote not up yet, sleeping...");
- Thread.sleep(ZYGOTE_RETRY_MILLIS);
- } catch (InterruptedException ex) {
- throw new ZygoteStartFailedEx(ex);
- }
- }
+ try {
+ zygoteSocket.connect(new LocalSocketAddress(socketAddress,
+ LocalSocketAddress.Namespace.RESERVED));
+ zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
+
+ zygoteWriter = new BufferedWriter(new OutputStreamWriter(
+ zygoteSocket.getOutputStream()), 256);
+ } catch (IOException ex) {
try {
- zygoteSocket = new LocalSocket();
- zygoteSocket.connect(new LocalSocketAddress(socketAddress,
- LocalSocketAddress.Namespace.RESERVED));
-
- zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
-
- zygoteWriter = new BufferedWriter(new OutputStreamWriter(
- zygoteSocket.getOutputStream()), 256);
- break;
- } catch (IOException ex) {
- if (zygoteSocket != null) {
- try {
- zygoteSocket.close();
- } catch (IOException ex2) {
- Log.e(LOG_TAG,"I/O exception on close after exception", ex2);
- }
- }
-
- zygoteSocket = null;
+ zygoteSocket.close();
+ } catch (IOException ignore) {
}
- }
- if (zygoteSocket == null) {
- throw new ZygoteStartFailedEx("connect failed");
+ throw ex;
}
String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
@@ -417,7 +400,7 @@
return abiList.contains(abi);
}
- void close() {
+ public void close() {
try {
socket.close();
} catch (IOException ex) {
@@ -503,27 +486,22 @@
* @throws ZygoteStartFailedEx if the query failed.
*/
private static String getAbiList(BufferedWriter writer, DataInputStream inputStream)
- throws ZygoteStartFailedEx {
- try {
+ throws IOException {
+ // Each query starts with the argument count (1 in this case)
+ writer.write("1");
+ // ... followed by a new-line.
+ writer.newLine();
+ // ... followed by our only argument.
+ writer.write("--query-abi-list");
+ writer.newLine();
+ writer.flush();
- // Each query starts with the argument count (1 in this case)
- writer.write("1");
- // ... followed by a new-line.
- writer.newLine();
- // ... followed by our only argument.
- writer.write("--query-abi-list");
- writer.newLine();
- writer.flush();
+ // The response is a length prefixed stream of ASCII bytes.
+ int numBytes = inputStream.readInt();
+ byte[] bytes = new byte[numBytes];
+ inputStream.readFully(bytes);
- // The response is a length prefixed stream of ASCII bytes.
- int numBytes = inputStream.readInt();
- byte[] bytes = new byte[numBytes];
- inputStream.readFully(bytes);
-
- return new String(bytes, StandardCharsets.US_ASCII);
- } catch (IOException ioe) {
- throw new ZygoteStartFailedEx(ioe);
- }
+ return new String(bytes, StandardCharsets.US_ASCII);
}
/**
@@ -677,30 +655,16 @@
}
/**
- * Returns the number of times we attempt a connection to the zygote. We
- * sleep for {@link #ZYGOTE_RETRY_MILLIS} milliseconds between each try.
- *
- * This could probably be removed, see TODO in {@code ZygoteState#connect}.
- */
- private static int getNumTries(ZygoteState state) {
- // Retry 10 times for the first connection to each zygote.
- if (state == null) {
- return 11;
- }
-
- // This means the connection has already been established, but subsequently
- // closed, possibly due to an IOException. We retry just once if that's the
- // case.
- return 1;
- }
-
- /**
* Tries to open socket to Zygote process if not already open. If
* already open, does nothing. May block and retry.
*/
private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
- primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET, getNumTries(primaryZygoteState));
+ try {
+ primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
+ } catch (IOException ioe) {
+ throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
+ }
}
if (primaryZygoteState.matches(abi)) {
@@ -709,8 +673,11 @@
// The primary zygote didn't match. Try the secondary.
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
- secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET,
- getNumTries(secondaryZygoteState));
+ try {
+ secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
+ } catch (IOException ioe) {
+ throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
+ }
}
if (secondaryZygoteState.matches(abi)) {
diff --git a/core/java/android/os/RemoteException.java b/core/java/android/os/RemoteException.java
index e30d24f..98d7523 100644
--- a/core/java/android/os/RemoteException.java
+++ b/core/java/android/os/RemoteException.java
@@ -28,4 +28,9 @@
public RemoteException(String message) {
super(message);
}
+
+ /** {@hide} */
+ public RuntimeException rethrowAsRuntimeException() {
+ throw new RuntimeException(this);
+ }
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1847b55..89f4388 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2503,6 +2503,14 @@
NOTIFICATION_SOUND
};
+ /**
+ * When to use Wi-Fi calling
+ *
+ * @see android.telephony.TelephonyManager.WifiCallingChoices
+ * @hide
+ */
+ public static final String WHEN_TO_MAKE_WIFI_CALLS = "when_to_make_wifi_calls";
+
// Settings moved to Settings.Secure
/**
@@ -3838,22 +3846,11 @@
/**
* Setting that specifies whether display color inversion is enabled.
- *
- * @hide
*/
public static final String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED =
"accessibility_display_inversion_enabled";
/**
- * Integer property that specifies the type of color inversion to
- * perform. Valid values are defined in AccessibilityManager.
- *
- * @hide
- */
- public static final String ACCESSIBILITY_DISPLAY_INVERSION =
- "accessibility_display_inversion";
-
- /**
* Setting that specifies whether the quick setting tile for display
* color space adjustment is enabled.
*
@@ -3881,44 +3878,6 @@
"accessibility_display_daltonizer";
/**
- * Setting that specifies whether the quick setting tile for display
- * contrast enhancement is enabled.
- *
- * @hide
- */
- public static final String ACCESSIBILITY_DISPLAY_CONTRAST_QUICK_SETTING_ENABLED =
- "accessibility_display_contrast_quick_setting_enabled";
-
- /**
- * Setting that specifies whether display contrast enhancement is
- * enabled.
- *
- * @hide
- */
- public static final String ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED =
- "accessibility_display_contrast_enabled";
-
- /**
- * Floating point property that specifies display contrast adjustment.
- * Valid range is [0, ...] where 0 is gray, 1 is normal, and higher
- * values indicate enhanced contrast.
- *
- * @hide
- */
- public static final String ACCESSIBILITY_DISPLAY_CONTRAST =
- "accessibility_display_contrast";
-
- /**
- * Floating point property that specifies display brightness adjustment.
- * Valid range is [-1, 1] where -1 is black, 0 is default, and 1 is
- * white.
- *
- * @hide
- */
- public static final String ACCESSIBILITY_DISPLAY_BRIGHTNESS =
- "accessibility_display_brightness";
-
- /**
* The timout for considering a press to be a long press in milliseconds.
* @hide
*/
@@ -6196,6 +6155,13 @@
/** @hide */ public static final int HEADS_UP_ON = 1;
/**
+ * The name of the device
+ *
+ * @hide
+ */
+ public static final String DEVICE_NAME = "device_name";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
diff --git a/core/java/android/provider/TvContract.java b/core/java/android/provider/TvContract.java
index 62252be..5ffffb5 100644
--- a/core/java/android/provider/TvContract.java
+++ b/core/java/android/provider/TvContract.java
@@ -20,6 +20,7 @@
import android.content.ContentResolver;
import android.content.ContentUris;
import android.net.Uri;
+import android.tv.TvInputService;
import java.util.List;
@@ -139,9 +140,9 @@
*
* @param channelUri The URI of the channel to return programs for.
* @param startTime The start time used to filter programs. The returned programs should have
- * {@link Programs#END_TIME_UTC_MILLIS} that is greater than this time.
+ * {@link Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this time.
* @param endTime The end time used to filter programs. The returned programs should have
- * {@link Programs#START_TIME_UTC_MILLIS} that is less than this time.
+ * {@link Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time.
*/
public static final Uri buildProgramsUriForChannel(Uri channelUri, long startTime,
long endTime) {
@@ -161,7 +162,7 @@
}
/**
- * Extracts the {@link Channels#PACKAGE_NAME} from a given URI.
+ * Extracts the {@link Channels#COLUMN_PACKAGE_NAME} from a given URI.
*
* @param channelsUri A URI constructed by {@link #buildChannelsUriForInput(ComponentName)} or
* {@link #buildChannelsUriForInput(ComponentName, boolean)}.
@@ -179,7 +180,7 @@
}
/**
- * Extracts the {@link Channels#SERVICE_NAME} from a given URI.
+ * Extracts the {@link Channels#COLUMN_SERVICE_NAME} from a given URI.
*
* @param channelsUri A URI constructed by {@link #buildChannelsUriForInput(ComponentName)} or
* {@link #buildChannelsUriForInput(ComponentName, boolean)}.
@@ -231,7 +232,7 @@
* Type: TEXT
* </p>
*/
- public static final String PACKAGE_NAME = "package_name";
+ public static final String COLUMN_PACKAGE_NAME = "package_name";
}
/** Column definitions for the TV channels table. */
@@ -279,14 +280,14 @@
/** The channel type for DVB-SH (satellite). */
public static final int TYPE_DVB_SH = 0x00020400;
- /** The channel type for ATSC (terrestrial/cable). */
- public static final int TYPE_ATSC = 0x00030000;
+ /** The channel type for ATSC (terrestrial). */
+ public static final int TYPE_ATSC_T = 0x00030000;
- /** The channel type for ATSC 2.0. */
- public static final int TYPE_ATSC_2_0 = 0x00030001;
+ /** The channel type for ATSC (cable). */
+ public static final int TYPE_ATSC_C = 0x00030200;
/** The channel type for ATSC-M/H (mobile/handheld). */
- public static final int TYPE_ATSC_M_H = 0x00030100;
+ public static final int TYPE_ATSC_M_H = 0x00030200;
/** The channel type for ISDB-T (terrestrial). */
public static final int TYPE_ISDB_T = 0x00040000;
@@ -315,49 +316,124 @@
/** The channel type for S-DMB (satellite). */
public static final int TYPE_S_DMB = 0x00060100;
+ /** A generic service type. */
+ public static final int SERVICE_TYPE_OTHER = 0x0;
+
+ /** The service type for regular TV channels. */
+ public static final int SERVICE_TYPE_TV = 0x1;
+
+ /** The service type for radio channels. */
+ public static final int SERVICE_TYPE_RADIO = 0x2;
+
/**
- * The name of the TV input service that provides this TV channel.
+ * The name of the {@link TvInputService} subclass that provides this TV channel. This
+ * should be a fully qualified class name (such as, "com.example.project.TvInputService").
* <p>
* This is a required field.
* </p><p>
* Type: TEXT
* </p>
*/
- public static final String SERVICE_NAME = "service_name";
+ public static final String COLUMN_SERVICE_NAME = "service_name";
/**
* The predefined type of this TV channel.
* <p>
- * This is used to indicate which broadcast standard (e.g. ATSC, DVB or ISDB) the current
- * channel conforms to.
+ * This is primarily used to indicate which broadcast standard (e.g. ATSC, DVB or ISDB) the
+ * current channel conforms to, with an exception being {@link #TYPE_PASSTHROUGH}, which is
+ * a special channel type used only by pass-through inputs such as HDMI. The value should
+ * match to one of the followings: {@link #TYPE_OTHER}, {@link #TYPE_PASSTHROUGH},
+ * {@link #TYPE_DVB_T}, {@link #TYPE_DVB_T2}, {@link #TYPE_DVB_S}, {@link #TYPE_DVB_S2},
+ * {@link #TYPE_DVB_C}, {@link #TYPE_DVB_C2}, {@link #TYPE_DVB_H}, {@link #TYPE_DVB_SH},
+ * {@link #TYPE_ATSC_T}, {@link #TYPE_ATSC_C}, {@link #TYPE_ATSC_M_H}, {@link #TYPE_ISDB_T},
+ * {@link #TYPE_ISDB_TB}, {@link #TYPE_ISDB_S}, {@link #TYPE_ISDB_C} {@link #TYPE_1SEG},
+ * {@link #TYPE_DTMB}, {@link #TYPE_CMMB}, {@link #TYPE_T_DMB}, {@link #TYPE_S_DMB}
* </p><p>
* This is a required field.
* </p><p>
* Type: INTEGER
* </p>
*/
- public static final String TYPE = "type";
+ public static final String COLUMN_TYPE = "type";
/**
- * The transport stream ID as appeared in various broadcast standards.
+ * The predefined service type of this TV channel.
* <p>
- * This is not a required field but if provided, can significantly increase the accuracy of
- * channel identification.
+ * This is primarily used to indicate whether the current channel is a regular TV channel or
+ * a radio-like channel. Use the same coding for {@code service_type} in the underlying
+ * broadcast standard if it is defined there (e.g. ATSC A/53, ETSI EN 300 468 and ARIB
+ * STD-B10). Otherwise use one of the followings: {@link #SERVICE_TYPE_OTHER},
+ * {@link #SERVICE_TYPE_TV}, {@link #SERVICE_TYPE_RADIO}
+ * </p><p>
+ * This is a required field.
* </p><p>
* Type: INTEGER
* </p>
*/
- public static final String TRANSPORT_STREAM_ID = "transport_stream_id";
+ public static final String COLUMN_SERVICE_TYPE = "service_type";
+
+ /**
+ * The original network ID of this TV channel.
+ * <p>
+ * This is used to identify the originating delivery system, if applicable. Use the same
+ * coding for {@code origianal_network_id} in the underlying broadcast standard if it is
+ * defined there (e.g. ETSI EN 300 468/TR 101 211 and ARIB STD-B10). If channels cannot be
+ * globally identified by 2-tuple {{@link #COLUMN_TRANSPORT_STREAM_ID},
+ * {@link #COLUMN_SERVICE_ID}}, one must carefully assign a value to this field to form a
+ * unique 3-tuple identification {{@link #COLUMN_ORIGINAL_NETWORK_ID},
+ * {@link #COLUMN_TRANSPORT_STREAM_ID}, {@link #COLUMN_SERVICE_ID}} for its channels.
+ * </p><p>
+ * This is a required field if the channel cannot be uniquely identified by a 2-tuple
+ * {{@link #COLUMN_TRANSPORT_STREAM_ID}, {@link #COLUMN_SERVICE_ID}}.
+ * </p><p>
+ * Type: INTEGER
+ * </p>
+ */
+ public static final String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
+
+ /**
+ * The transport stream ID of this channel.
+ * <p>
+ * This is used to identify the Transport Stream that contains the current channel from any
+ * other multiplex within a network, if applicable. Use the same coding for
+ * {@code transport_stream_id} defined in ISO/IEC 13818-1 if the channel is transmitted via
+ * the MPEG Transport Stream as is the case for many digital broadcast standards.
+ * </p><p>
+ * This is a required field if the current channel is transmitted via the MPEG Transport
+ * Stream.
+ * </p><p>
+ * Type: INTEGER
+ * </p>
+ */
+ public static final String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
+
+ /**
+ * The service ID of this channel.
+ * <p>
+ * This is used to identify the current service (roughly equivalent to channel) from any
+ * other service within the Transport Stream, if applicable. Use the same coding for
+ * {@code service_id} in the underlying broadcast standard if it is defined there (e.g. ETSI
+ * EN 300 468 and ARIB STD-B10) or {@code program_number} (which usually has the same value
+ * as {@code service_id}) in ISO/IEC 13818-1 if the channel is transmitted via the MPEG
+ * Transport Stream.
+ * </p><p>
+ * This is a required field if the current channel is transmitted via the MPEG Transport
+ * Stream.
+ * </p><p>
+ * Type: INTEGER
+ * </p>
+ */
+ public static final String COLUMN_SERVICE_ID = "service_id";
/**
* The channel number that is displayed to the user.
* <p>
* The format can vary depending on broadcast standard and product specification.
* </p><p>
- * Type: INTEGER
+ * Type: TEXT
* </p>
*/
- public static final String DISPLAY_NUMBER = "display_number";
+ public static final String COLUMN_DISPLAY_NUMBER = "display_number";
/**
* The channel name that is displayed to the user.
@@ -369,7 +445,7 @@
* Type: TEXT
* </p>
*/
- public static final String DISPLAY_NAME = "display_name";
+ public static final String COLUMN_DISPLAY_NAME = "display_name";
/**
* The description of this TV channel.
@@ -379,7 +455,7 @@
* Type: TEXT
* </p>
*/
- public static final String DESCRIPTION = "description";
+ public static final String COLUMN_DESCRIPTION = "description";
/**
* The flag indicating whether this TV channel is browsable or not.
@@ -391,7 +467,7 @@
* Type: INTEGER (boolean)
* </p>
*/
- public static final String BROWSABLE = "browsable";
+ public static final String COLUMN_BROWSABLE = "browsable";
/**
* Generic data used by individual TV input services.
@@ -399,7 +475,7 @@
* Type: BLOB
* </p>
*/
- public static final String DATA = "data";
+ public static final String COLUMN_DATA = "data";
/**
@@ -413,7 +489,7 @@
* Type: INTEGER
* </p>
*/
- public static final String VERSION_NUMBER = "version_number";
+ public static final String COLUMN_VERSION_NUMBER = "version_number";
private Channels() {}
}
@@ -441,7 +517,7 @@
* Type: INTEGER (long)
* </p>
*/
- public static final String CHANNEL_ID = "channel_id";
+ public static final String COLUMN_CHANNEL_ID = "channel_id";
/**
* The title of this TV program.
@@ -449,7 +525,7 @@
* Type: TEXT
* </p>
**/
- public static final String TITLE = "title";
+ public static final String COLUMN_TITLE = "title";
/**
* The start time of this TV program, in milliseconds since the epoch.
@@ -457,7 +533,7 @@
* Type: INTEGER (long)
* </p>
*/
- public static final String START_TIME_UTC_MILLIS = "start_time_utc_millis";
+ public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
/**
* The end time of this TV program, in milliseconds since the epoch.
@@ -465,7 +541,7 @@
* Type: INTEGER (long)
* </p>
*/
- public static final String END_TIME_UTC_MILLIS = "end_time_utc_millis";
+ public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
/**
* The description of this TV program that is displayed to the user by default.
@@ -475,19 +551,19 @@
* Type: TEXT
* </p>
*/
- public static final String DESCRIPTION = "description";
+ public static final String COLUMN_DESCRIPTION = "description";
/**
* The detailed, lengthy description of this TV program that is displayed only when the user
* wants to see more information.
* <p>
* TV input services should leave this field empty if they have no additional
- * details beyond {@link #DESCRIPTION}.
+ * details beyond {@link #COLUMN_DESCRIPTION}.
* </p><p>
* Type: TEXT
* </p>
*/
- public static final String LONG_DESCRIPTION = "long_description";
+ public static final String COLUMN_LONG_DESCRIPTION = "long_description";
/**
* Generic data used by TV input services.
@@ -495,7 +571,7 @@
* Type: BLOB
* </p>
*/
- public static final String DATA = "data";
+ public static final String COLUMN_DATA = "data";
/**
* The version number of this row entry used by TV input services.
@@ -508,7 +584,7 @@
* Type: INTEGER
* </p>
*/
- public static final String VERSION_NUMBER = "version_number";
+ public static final String COLUMN_VERSION_NUMBER = "version_number";
private Programs() {}
}
@@ -540,7 +616,8 @@
* Type: INTEGER (long)
* </p>
*/
- public static final String WATCH_START_TIME_UTC_MILLIS = "watch_start_time_utc_millis";
+ public static final String COLUMN_WATCH_START_TIME_UTC_MILLIS =
+ "watch_start_time_utc_millis";
/**
* The UTC time that the user stopped watching this TV program, in milliseconds since the
@@ -549,7 +626,7 @@
* Type: INTEGER (long)
* </p>
*/
- public static final String WATCH_END_TIME_UTC_MILLIS = "watch_end_time_utc_millis";
+ public static final String COLUMN_WATCH_END_TIME_UTC_MILLIS = "watch_end_time_utc_millis";
/**
* The channel ID that contains this TV program.
@@ -557,7 +634,7 @@
* Type: INTEGER (long)
* </p>
*/
- public static final String CHANNEL_ID = "channel_id";
+ public static final String COLUMN_CHANNEL_ID = "channel_id";
/**
* The title of this TV program.
@@ -565,7 +642,7 @@
* Type: TEXT
* </p>
*/
- public static final String TITLE = "title";
+ public static final String COLUMN_TITLE = "title";
/**
* The start time of this TV program, in milliseconds since the epoch.
@@ -573,7 +650,7 @@
* Type: INTEGER (long)
* </p>
*/
- public static final String START_TIME_UTC_MILLIS = "start_time_utc_millis";
+ public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
/**
* The end time of this TV program, in milliseconds since the epoch.
@@ -581,7 +658,7 @@
* Type: INTEGER (long)
* </p>
*/
- public static final String END_TIME_UTC_MILLIS = "end_time_utc_millis";
+ public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
/**
* The description of this TV program.
@@ -589,7 +666,7 @@
* Type: TEXT
* </p>
*/
- public static final String DESCRIPTION = "description";
+ public static final String COLUMN_DESCRIPTION = "description";
private WatchedPrograms() {}
}
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index d4b29d8..d4919eb 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -17,11 +17,15 @@
package android.service.notification;
import android.service.notification.StatusBarNotification;
+import android.service.notification.NotificationOrderUpdate;
/** @hide */
oneway interface INotificationListener
{
- void onListenerConnected(in String[] notificationKeys);
- void onNotificationPosted(in StatusBarNotification notification);
- void onNotificationRemoved(in StatusBarNotification notification);
+ void onListenerConnected(in NotificationOrderUpdate update);
+ void onNotificationPosted(in StatusBarNotification notification,
+ in NotificationOrderUpdate update);
+ void onNotificationRemoved(in StatusBarNotification notification,
+ in NotificationOrderUpdate update);
+ void onNotificationOrderUpdate(in NotificationOrderUpdate update);
}
\ No newline at end of file
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 3673f03..a94f45a 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -22,10 +22,13 @@
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.UserHandle;
import android.util.Log;
+import java.util.Comparator;
+import java.util.HashMap;
+
/**
* A service that receives calls from the system when new notifications are posted or removed.
* <p>To extend this class, you must declare the service in your manifest file with
@@ -46,6 +49,7 @@
+ "[" + getClass().getSimpleName() + "]";
private INotificationListenerWrapper mWrapper = null;
+ private String[] mNotificationKeys;
private INotificationManager mNoMan;
@@ -95,6 +99,15 @@
// optional
}
+ /**
+ * Implement this method to be notified when the notification order cahnges.
+ *
+ * Call {@link #getOrderedNotificationKeys()} to retrieve the new order.
+ */
+ public void onNotificationOrderUpdate() {
+ // optional
+ }
+
private final INotificationManager getNotificationInterface() {
if (mNoMan == null) {
mNoMan = INotificationManager.Stub.asInterface(
@@ -202,7 +215,7 @@
* Request the list of outstanding notifications (that is, those that are visible to the
* current user). Useful when you don't know what's already been posted.
*
- * @return An array of active notifications.
+ * @return An array of active notifications, sorted in natural order.
*/
public StatusBarNotification[] getActiveNotifications() {
return getActiveNotifications(null /*all*/);
@@ -213,7 +226,8 @@
* current user). Useful when you don't know what's already been posted.
*
* @param keys A specific list of notification keys, or {@code null} for all.
- * @return An array of active notifications.
+ * @return An array of active notifications, sorted in natural order
+ * if {@code keys} is {@code null}.
*/
public StatusBarNotification[] getActiveNotifications(String[] keys) {
if (!isBound()) return null;
@@ -226,21 +240,15 @@
}
/**
- * Request the list of outstanding notification keys(that is, those that are visible to the
- * current user). You can use the notification keys for subsequent retrieval via
+ * Request the list of notification keys in their current natural order.
+ * You can use the notification keys for subsequent retrieval via
* {@link #getActiveNotifications(String[]) or dismissal via
* {@link #cancelNotifications(String[]).
*
- * @return An array of active notification keys.
+ * @return An array of active notification keys, in their natural order.
*/
- public String[] getActiveNotificationKeys() {
- if (!isBound()) return null;
- try {
- return getNotificationInterface().getActiveNotificationKeysFromListener(mWrapper);
- } catch (android.os.RemoteException ex) {
- Log.v(TAG, "Unable to contact notification manager", ex);
- }
- return null;
+ public String[] getOrderedNotificationKeys() {
+ return mNotificationKeys;
}
@Override
@@ -261,28 +269,60 @@
private class INotificationListenerWrapper extends INotificationListener.Stub {
@Override
- public void onNotificationPosted(StatusBarNotification sbn) {
+ public void onNotificationPosted(StatusBarNotification sbn,
+ NotificationOrderUpdate update) {
try {
- NotificationListenerService.this.onNotificationPosted(sbn);
+ // protect subclass from concurrent modifications of (@link mNotificationKeys}.
+ synchronized (mWrapper) {
+ updateNotificationKeys(update);
+ NotificationListenerService.this.onNotificationPosted(sbn);
+ }
} catch (Throwable t) {
- Log.w(TAG, "Error running onNotificationPosted", t);
+ Log.w(TAG, "Error running onOrderedNotificationPosted", t);
}
}
@Override
- public void onNotificationRemoved(StatusBarNotification sbn) {
+ public void onNotificationRemoved(StatusBarNotification sbn,
+ NotificationOrderUpdate update) {
try {
- NotificationListenerService.this.onNotificationRemoved(sbn);
+ // protect subclass from concurrent modifications of (@link mNotificationKeys}.
+ synchronized (mWrapper) {
+ updateNotificationKeys(update);
+ NotificationListenerService.this.onNotificationRemoved(sbn);
+ }
} catch (Throwable t) {
Log.w(TAG, "Error running onNotificationRemoved", t);
}
}
@Override
- public void onListenerConnected(String[] notificationKeys) {
+ public void onListenerConnected(NotificationOrderUpdate update) {
try {
- NotificationListenerService.this.onListenerConnected(notificationKeys);
+ // protect subclass from concurrent modifications of (@link mNotificationKeys}.
+ synchronized (mWrapper) {
+ updateNotificationKeys(update);
+ NotificationListenerService.this.onListenerConnected(mNotificationKeys);
+ }
} catch (Throwable t) {
Log.w(TAG, "Error running onListenerConnected", t);
}
}
+ @Override
+ public void onNotificationOrderUpdate(NotificationOrderUpdate update)
+ throws RemoteException {
+ try {
+ // protect subclass from concurrent modifications of (@link mNotificationKeys}.
+ synchronized (mWrapper) {
+ updateNotificationKeys(update);
+ NotificationListenerService.this.onNotificationOrderUpdate();
+ }
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onNotificationOrderUpdate", t);
+ }
+ }
+ }
+
+ private void updateNotificationKeys(NotificationOrderUpdate update) {
+ // TODO: avoid garbage by comparing the lists
+ mNotificationKeys = update.getOrderedKeys();
}
}
diff --git a/core/java/android/service/notification/NotificationOrderUpdate.aidl b/core/java/android/service/notification/NotificationOrderUpdate.aidl
new file mode 100644
index 0000000..5d50641
--- /dev/null
+++ b/core/java/android/service/notification/NotificationOrderUpdate.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.notification;
+
+parcelable NotificationOrderUpdate;
diff --git a/core/java/android/service/notification/NotificationOrderUpdate.java b/core/java/android/service/notification/NotificationOrderUpdate.java
new file mode 100644
index 0000000..20e19a3
--- /dev/null
+++ b/core/java/android/service/notification/NotificationOrderUpdate.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.notification;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class NotificationOrderUpdate implements Parcelable {
+ // TODO replace this with an update instead of the whole array
+ private final String[] mKeys;
+
+ /** @hide */
+ public NotificationOrderUpdate(String[] keys) {
+ this.mKeys = keys;
+ }
+
+ public NotificationOrderUpdate(Parcel in) {
+ this.mKeys = in.readStringArray();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeStringArray(this.mKeys);
+ }
+
+ public static final Parcelable.Creator<NotificationOrderUpdate> CREATOR
+ = new Parcelable.Creator<NotificationOrderUpdate>() {
+ public NotificationOrderUpdate createFromParcel(Parcel parcel) {
+ return new NotificationOrderUpdate(parcel);
+ }
+
+ public NotificationOrderUpdate[] newArray(int size) {
+ return new NotificationOrderUpdate[size];
+ }
+ };
+
+ /**
+ * @hide
+ * @return ordered list of keys
+ */
+ String[] getOrderedKeys() {
+ return mKeys;
+ }
+}
diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java
index 4f996cd..9b929a3 100644
--- a/core/java/android/speech/tts/TtsEngines.java
+++ b/core/java/android/speech/tts/TtsEngines.java
@@ -307,6 +307,24 @@
}
/**
+ * True if a given TTS engine uses the default phone locale as a default locale. Attempts to
+ * read the value from {@link Settings.Secure#TTS_DEFAULT_LOCALE}, failing which the
+ * old style value from {@link Settings.Secure#TTS_DEFAULT_LANG} is read. If
+ * both these values are empty, this methods returns true.
+ *
+ * @param engineName the engine to return the locale for.
+ */
+ public boolean isLocaleSetToDefaultForEngine(String engineName) {
+ return (TextUtils.isEmpty(parseEnginePrefFromList(
+ getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE),
+ engineName)) &&
+ TextUtils.isEmpty(
+ Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.TTS_DEFAULT_LANG)));
+ }
+
+
+ /**
* Parses a locale preference value delimited by {@link #LOCALE_DELIMITER}.
* Varies from {@link String#split} in that it will always return an array
* of length 3 with non null values.
diff --git a/core/java/android/transition/MoveImage.java b/core/java/android/transition/MoveImage.java
index 183cdd2..6f1b6f7 100644
--- a/core/java/android/transition/MoveImage.java
+++ b/core/java/android/transition/MoveImage.java
@@ -64,7 +64,13 @@
if (!(view instanceof ImageView) || view.getVisibility() != View.VISIBLE) {
return;
}
+ ImageView imageView = (ImageView) view;
+ Drawable drawable = imageView.getDrawable();
+ if (drawable == null) {
+ return;
+ }
Map<String, Object> values = transitionValues.values;
+ values.put(PROPNAME_DRAWABLE, drawable);
ViewGroup parent = (ViewGroup) view.getParent();
parent.getLocationInWindow(mTempLoc);
@@ -79,11 +85,9 @@
Rect bounds = new Rect(left, top, right, bottom);
values.put(PROPNAME_BOUNDS, bounds);
- ImageView imageView = (ImageView) view;
Matrix matrix = getMatrix(imageView);
values.put(PROPNAME_MATRIX, matrix);
values.put(PROPNAME_CLIP, findClip(imageView));
- values.put(PROPNAME_DRAWABLE, imageView.getDrawable());
}
@Override
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 49a0138..9a70099 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -89,7 +89,8 @@
* out-in behavior. Finally, note the use of the <code>targets</code> sub-tag, which
* takes a set of {@link android.R.styleable#TransitionTarget target} tags, each
* of which lists a specific <code>targetId</code>, <code>targetClass</code>,
- * <code>excludeId</code>, or <code>excludeClass</code>, which this transition acts upon.
+ * <code>targetViewName</code>, <code>excludeId</code>, <code>excludeClass</code>, or
+ * <code>excludeViewName</code>, which this transition acts upon.
* Use of targets is optional, but can be used to either limit the time spent checking
* attributes on unchanging views, or limiting the types of animations run on specific views.
* In this case, we know that only the <code>grayscaleContainer</code> will be
@@ -106,6 +107,40 @@
private static final String LOG_TAG = "Transition";
static final boolean DBG = false;
+ /**
+ * With {@link #setMatchOrder(int...)}, chooses to match by View instance.
+ */
+ public static final int MATCH_INSTANCE = 0x1;
+ private static final int MATCH_FIRST = MATCH_INSTANCE;
+
+ /**
+ * With {@link #setMatchOrder(int...)}, chooses to match by
+ * {@link android.view.View#getViewName()}. Null names will not be matched.
+ */
+ public static final int MATCH_VIEW_NAME = 0x2;
+
+ /**
+ * With {@link #setMatchOrder(int...)}, chooses to match by
+ * {@link android.view.View#getId()}. Negative IDs will not be matched.
+ */
+ public static final int MATCH_ID = 0x3;
+
+ /**
+ * With {@link #setMatchOrder(int...)}, chooses to match by the {@link android.widget.Adapter}
+ * item id. When {@link android.widget.Adapter#hasStableIds()} returns false, no match
+ * will be made for items.
+ */
+ public static final int MATCH_ITEM_ID = 0x4;
+
+ private static final int MATCH_LAST = MATCH_ITEM_ID;
+
+ private static final int[] DEFAULT_MATCH_ORDER = {
+ MATCH_VIEW_NAME,
+ MATCH_INSTANCE,
+ MATCH_ID,
+ MATCH_ITEM_ID,
+ };
+
private String mName = getClass().getName();
long mStartDelay = -1;
@@ -113,16 +148,19 @@
TimeInterpolator mInterpolator = null;
ArrayList<Integer> mTargetIds = new ArrayList<Integer>();
ArrayList<View> mTargets = new ArrayList<View>();
+ ArrayList<String> mTargetNames = null;
+ ArrayList<Class> mTargetTypes = null;
ArrayList<Integer> mTargetIdExcludes = null;
ArrayList<View> mTargetExcludes = null;
ArrayList<Class> mTargetTypeExcludes = null;
- ArrayList<Class> mTargetTypes = null;
+ ArrayList<String> mTargetNameExcludes = null;
ArrayList<Integer> mTargetIdChildExcludes = null;
ArrayList<View> mTargetChildExcludes = null;
ArrayList<Class> mTargetTypeChildExcludes = null;
private TransitionValuesMaps mStartValues = new TransitionValuesMaps();
private TransitionValuesMaps mEndValues = new TransitionValuesMaps();
TransitionSet mParent = null;
+ private int[] mMatchOrder = DEFAULT_MATCH_ORDER;
// Per-animator information used for later canceling when future transitions overlap
private static ThreadLocal<ArrayMap<Animator, AnimationInfo>> sRunningAnimators =
@@ -334,6 +372,211 @@
}
/**
+ * Sets the order in which Transition matches View start and end values.
+ * <p>
+ * The default behavior is to match first by {@link android.view.View#getViewName()},
+ * then by View instance, then by {@link android.view.View#getId()} and finally
+ * by its item ID if it is in a direct child of ListView. The caller can
+ * choose to have only some or all of the values of {@link #MATCH_INSTANCE},
+ * {@link #MATCH_VIEW_NAME}, {@link #MATCH_ITEM_ID}, and {@link #MATCH_ID}. Only
+ * the match algorithms supplied will be used to determine whether Views are the
+ * the same in both the start and end Scene. Views that do not match will be considered
+ * as entering or leaving the Scene.
+ * </p>
+ * @param matches A list of zero or more of {@link #MATCH_INSTANCE},
+ * {@link #MATCH_VIEW_NAME}, {@link #MATCH_ITEM_ID}, and {@link #MATCH_ID}.
+ * If none are provided, then the default match order will be set.
+ */
+ public void setMatchOrder(int... matches) {
+ if (matches == null || matches.length == 0) {
+ mMatchOrder = DEFAULT_MATCH_ORDER;
+ } else {
+ for (int i = 0; i < matches.length; i++) {
+ int match = matches[i];
+ if (!isValidMatch(match)) {
+ throw new IllegalArgumentException("matches contains invalid value");
+ }
+ if (alreadyContains(matches, i)) {
+ throw new IllegalArgumentException("matches contains a duplicate value");
+ }
+ }
+ mMatchOrder = matches.clone();
+ }
+ }
+
+ private static boolean isValidMatch(int match) {
+ return (match >= MATCH_FIRST && match <= MATCH_LAST);
+ }
+
+ private static boolean alreadyContains(int[] array, int searchIndex) {
+ int value = array[searchIndex];
+ for (int i = 0; i < searchIndex; i++) {
+ if (array[i] == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Match start/end values by View instance. Adds matched values to startValuesList
+ * and endValuesList and removes them from unmatchedStart and unmatchedEnd.
+ */
+ private void matchInstances(ArrayList<TransitionValues> startValuesList,
+ ArrayList<TransitionValues> endValuesList,
+ ArrayMap<View, TransitionValues> unmatchedStart,
+ ArrayMap<View, TransitionValues> unmatchedEnd) {
+ for (int i = unmatchedStart.size() - 1; i >= 0; i--) {
+ View view = unmatchedStart.keyAt(i);
+ TransitionValues end = unmatchedEnd.remove(view);
+ if (end != null) {
+ TransitionValues start = unmatchedStart.removeAt(i);
+ startValuesList.add(start);
+ endValuesList.add(end);
+ }
+ }
+ }
+
+ /**
+ * Match start/end values by Adapter item ID. Adds matched values to startValuesList
+ * and endValuesList and removes them from unmatchedStart and unmatchedEnd, using
+ * startItemIds and endItemIds as a guide for which Views have unique item IDs.
+ */
+ private void matchItemIds(ArrayList<TransitionValues> startValuesList,
+ ArrayList<TransitionValues> endValuesList,
+ ArrayMap<View, TransitionValues> unmatchedStart,
+ ArrayMap<View, TransitionValues> unmatchedEnd,
+ LongSparseArray<View> startItemIds, LongSparseArray<View> endItemIds) {
+ int numStartIds = startItemIds.size();
+ for (int i = 0; i < numStartIds; i++) {
+ View startView = startItemIds.valueAt(i);
+ if (startView != null) {
+ View endView = endItemIds.get(startItemIds.keyAt(i));
+ if (endView != null) {
+ TransitionValues startValues = unmatchedStart.get(startView);
+ TransitionValues endValues = unmatchedEnd.get(endView);
+ if (startValues != null && endValues != null) {
+ startValuesList.add(startValues);
+ endValuesList.add(endValues);
+ unmatchedStart.remove(startView);
+ unmatchedEnd.remove(endView);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Match start/end values by Adapter view ID. Adds matched values to startValuesList
+ * and endValuesList and removes them from unmatchedStart and unmatchedEnd, using
+ * startIds and endIds as a guide for which Views have unique IDs.
+ */
+ private void matchIds(ArrayList<TransitionValues> startValuesList,
+ ArrayList<TransitionValues> endValuesList,
+ ArrayMap<View, TransitionValues> unmatchedStart,
+ ArrayMap<View, TransitionValues> unmatchedEnd,
+ SparseArray<View> startIds, SparseArray<View> endIds) {
+ int numStartIds = startIds.size();
+ for (int i = 0; i < numStartIds; i++) {
+ View startView = startIds.valueAt(i);
+ if (startView != null && isValidTarget(startView)) {
+ View endView = endIds.get(startIds.keyAt(i));
+ if (endView != null && isValidTarget(endView)) {
+ TransitionValues startValues = unmatchedStart.get(startView);
+ TransitionValues endValues = unmatchedEnd.get(endView);
+ if (startValues != null && endValues != null) {
+ startValuesList.add(startValues);
+ endValuesList.add(endValues);
+ unmatchedStart.remove(startView);
+ unmatchedEnd.remove(endView);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Match start/end values by Adapter viewName. Adds matched values to startValuesList
+ * and endValuesList and removes them from unmatchedStart and unmatchedEnd, using
+ * startNames and endNames as a guide for which Views have unique viewNames.
+ */
+ private void matchNames(ArrayList<TransitionValues> startValuesList,
+ ArrayList<TransitionValues> endValuesList,
+ ArrayMap<View, TransitionValues> unmatchedStart,
+ ArrayMap<View, TransitionValues> unmatchedEnd,
+ ArrayMap<String, View> startNames, ArrayMap<String, View> endNames) {
+ int numStartNames = startNames.size();
+ for (int i = 0; i < numStartNames; i++) {
+ View startView = startNames.valueAt(i);
+ if (startView != null && isValidTarget(startView)) {
+ View endView = endNames.get(startNames.keyAt(i));
+ if (endView != null && isValidTarget(endView)) {
+ TransitionValues startValues = unmatchedStart.get(startView);
+ TransitionValues endValues = unmatchedEnd.get(endView);
+ if (startValues != null && endValues != null) {
+ startValuesList.add(startValues);
+ endValuesList.add(endValues);
+ unmatchedStart.remove(startView);
+ unmatchedEnd.remove(endView);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds all values from unmatchedStart and unmatchedEnd to startValuesList and endValuesList,
+ * assuming that there is no match between values in the list.
+ */
+ private void addUnmatched(ArrayList<TransitionValues> startValuesList,
+ ArrayList<TransitionValues> endValuesList,
+ ArrayMap<View, TransitionValues> unmatchedStart,
+ ArrayMap<View, TransitionValues> unmatchedEnd) {
+ // Views that only exist in the start Scene
+ for (int i = 0; i < unmatchedStart.size(); i++) {
+ startValuesList.add(unmatchedStart.valueAt(i));
+ endValuesList.add(null);
+ }
+
+ // Views that only exist in the end Scene
+ for (int i = 0; i < unmatchedEnd.size(); i++) {
+ endValuesList.add(unmatchedEnd.valueAt(i));
+ startValuesList.add(null);
+ }
+ }
+
+ private void matchStartAndEnd(TransitionValuesMaps startValues,
+ TransitionValuesMaps endValues,
+ ArrayList<TransitionValues> startValuesList,
+ ArrayList<TransitionValues> endValuesList) {
+ ArrayMap<View, TransitionValues> unmatchedStart =
+ new ArrayMap<View, TransitionValues>(startValues.viewValues);
+ ArrayMap<View, TransitionValues> unmatchedEnd =
+ new ArrayMap<View, TransitionValues>(endValues.viewValues);
+
+ for (int i = 0; i < mMatchOrder.length; i++) {
+ switch (mMatchOrder[i]) {
+ case MATCH_INSTANCE:
+ matchInstances(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
+ break;
+ case MATCH_VIEW_NAME:
+ matchNames(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
+ startValues.nameValues, endValues.nameValues);
+ break;
+ case MATCH_ID:
+ matchIds(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
+ startValues.idValues, endValues.idValues);
+ break;
+ case MATCH_ITEM_ID:
+ matchItemIds(startValuesList, endValuesList, unmatchedStart, unmatchedEnd,
+ startValues.itemIdValues, endValues.itemIdValues);
+ break;
+ }
+ }
+ addUnmatched(startValuesList, endValuesList, unmatchedStart, unmatchedEnd);
+ }
+
+ /**
* This method, essentially a wrapper around all calls to createAnimator for all
* possible target views, is called with the entire set of start/end
* values. The implementation in Transition iterates through these lists
@@ -349,76 +592,10 @@
if (DBG) {
Log.d(LOG_TAG, "createAnimators() for " + this);
}
- ArrayMap<View, TransitionValues> endCopy =
- new ArrayMap<View, TransitionValues>(endValues.viewValues);
- SparseArray<TransitionValues> endIdCopy = endValues.idValues.clone();
- LongSparseArray<TransitionValues> endItemIdCopy = endValues.itemIdValues.clone();
- // Walk through the start values, playing everything we find
- // Remove from the end set as we go
ArrayList<TransitionValues> startValuesList = new ArrayList<TransitionValues>();
ArrayList<TransitionValues> endValuesList = new ArrayList<TransitionValues>();
- for (View view : startValues.viewValues.keySet()) {
- TransitionValues start = null;
- TransitionValues end = null;
- boolean isInListView = false;
- if (view.getParent() instanceof ListView) {
- isInListView = true;
- }
- if (!isInListView) {
- int id = view.getId();
- start = startValues.viewValues.get(view);
- end = endValues.viewValues.get(view);
- if (end != null) {
- endCopy.remove(view);
- } else if (id != View.NO_ID) {
- end = endIdCopy.get(id);
- if (end == null || startValues.viewValues.containsKey(end.view)) {
- end = null;
- id = View.NO_ID;
- } else {
- endCopy.remove(end.view);
- }
- }
- endIdCopy.remove(id);
- if (isValidTarget(view, id)) {
- startValuesList.add(start);
- endValuesList.add(end);
- }
- } else {
- ListView parent = (ListView) view.getParent();
- if (parent.getAdapter().hasStableIds()) {
- int position = parent.getPositionForView(view);
- long itemId = parent.getItemIdAtPosition(position);
- start = startValues.itemIdValues.get(itemId);
- endItemIdCopy.remove(itemId);
- // TODO: deal with targetIDs for itemIDs for ListView items
- startValuesList.add(start);
- endValuesList.add(end);
- }
- }
- }
- int startItemIdCopySize = startValues.itemIdValues.size();
- for (int i = 0; i < startItemIdCopySize; ++i) {
- long id = startValues.itemIdValues.keyAt(i);
- if (isValidTarget(null, id)) {
- TransitionValues start = startValues.itemIdValues.get(id);
- TransitionValues end = endValues.itemIdValues.get(id);
- endItemIdCopy.remove(id);
- startValuesList.add(start);
- endValuesList.add(end);
- }
- }
- // Now walk through the remains of the end set
- // We've already matched everything from start to end, everything else doesn't match.
- for (View view : endCopy.keySet()) {
- int id = view.getId();
- if (isValidTarget(view, id)) {
- TransitionValues start = null;
- TransitionValues end = endCopy.get(view);
- startValuesList.add(start);
- endValuesList.add(end);
- }
- }
+ matchStartAndEnd(startValues, endValues, startValuesList, endValuesList);
+
ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
long minStartDelay = Long.MAX_VALUE;
int minAnimator = mAnimators.size();
@@ -520,7 +697,8 @@
* is not checked (this is in the case of ListView items, where the
* views are ignored and only the ids are used).
*/
- boolean isValidTarget(View target, long targetId) {
+ boolean isValidTarget(View target) {
+ int targetId = target.getId();
if (mTargetIdExcludes != null && mTargetIdExcludes.contains(targetId)) {
return false;
}
@@ -536,10 +714,20 @@
}
}
}
- if (mTargetIds.size() == 0 && mTargets.size() == 0 && mTargetTypes == null) {
+ if (mTargetNameExcludes != null && target != null && target.getViewName() != null) {
+ if (mTargetNameExcludes.contains(target.getViewName())) {
+ return false;
+ }
+ }
+ if (mTargetIds.size() == 0 && mTargets.size() == 0 &&
+ (mTargetTypes == null || mTargetTypes.isEmpty() &&
+ (mTargetNames == null || mTargetNames.isEmpty()))) {
return true;
}
- if (mTargetIds.contains((int) targetId) || mTargets.contains(target)) {
+ if (mTargetIds.contains(targetId) || mTargets.contains(target)) {
+ return true;
+ }
+ if (mTargetNames != null && mTargetNames.contains(target.getViewName())) {
return true;
}
if (mTargetTypes != null) {
@@ -690,6 +878,33 @@
}
/**
+ * Adds the viewName of a target view that this Transition is interested in
+ * animating. By default, there are no targetNames, and a Transition will
+ * listen for changes on every view in the hierarchy below the sceneRoot
+ * of the Scene being transitioned into. Setting targetNames constrains
+ * the Transition to only listen for, and act on, views with these viewNames.
+ * Views with different viewNames, or no viewName whatsoever, will be ignored.
+ *
+ * <p>Note that viewNames should be unique within the view hierarchy.</p>
+ *
+ * @see android.view.View#getViewName()
+ * @param targetName The viewName of a target view, must be non-null.
+ * @return The Transition to which the target viewName is added.
+ * Returning the same object makes it easier to chain calls during
+ * construction, such as
+ * <code>transitionSet.addTransitions(new Fade()).addTarget(someName);</code>
+ */
+ public Transition addTarget(String targetName) {
+ if (targetName != null) {
+ if (mTargetNames != null) {
+ mTargetNames = new ArrayList<String>();
+ }
+ mTargetNames.add(targetName);
+ }
+ return this;
+ }
+
+ /**
* Adds the Class of a target view that this Transition is interested in
* animating. By default, there are no targetTypes, and a Transition will
* listen for changes on every view in the hierarchy below the sceneRoot
@@ -712,10 +927,12 @@
* <code>transitionSet.addTransitions(new Fade()).addTarget(ImageView.class);</code>
*/
public Transition addTarget(Class targetType) {
- if (mTargetTypes == null) {
- mTargetTypes = new ArrayList<Class>();
+ if (targetType != null) {
+ if (mTargetTypes == null) {
+ mTargetTypes = new ArrayList<Class>();
+ }
+ mTargetTypes.add(targetType);
}
- mTargetTypes.add(targetType);
return this;
}
@@ -737,6 +954,23 @@
}
/**
+ * Removes the given targetName from the list of viewNames that this Transition
+ * is interested in animating.
+ *
+ * @param targetName The viewName of a target view, must not be null.
+ * @return The Transition from which the targetName is removed.
+ * Returning the same object makes it easier to chain calls during
+ * construction, such as
+ * <code>transitionSet.addTransitions(new Fade()).removeTargetName(someName);</code>
+ */
+ public Transition removeTarget(String targetName) {
+ if (targetName != null && mTargetNames != null) {
+ mTargetNames.remove(targetName);
+ }
+ return this;
+ }
+
+ /**
* Whether to add the given id to the list of target ids to exclude from this
* transition. The <code>exclude</code> parameter specifies whether the target
* should be added to or removed from the excluded list.
@@ -758,7 +992,35 @@
* @return This transition object.
*/
public Transition excludeTarget(int targetId, boolean exclude) {
- mTargetIdExcludes = excludeId(mTargetIdExcludes, targetId, exclude);
+ if (targetId >= 0) {
+ mTargetIdExcludes = excludeObject(mTargetIdExcludes, targetId, exclude);
+ }
+ return this;
+ }
+
+ /**
+ * Whether to add the given viewName to the list of target viewNames to exclude from this
+ * transition. The <code>exclude</code> parameter specifies whether the target
+ * should be added to or removed from the excluded list.
+ *
+ * <p>Excluding targets is a general mechanism for allowing transitions to run on
+ * a view hierarchy while skipping target views that should not be part of
+ * the transition. For example, you may want to avoid animating children
+ * of a specific ListView or Spinner. Views can be excluded by their
+ * id, their instance reference, their viewName, or by the Class of that view
+ * (eg, {@link Spinner}).</p>
+ *
+ * @see #excludeTarget(View, boolean)
+ * @see #excludeTarget(int, boolean)
+ * @see #excludeTarget(Class, boolean)
+ *
+ * @param targetViewName The name of a target to ignore when running this transition.
+ * @param exclude Whether to add the target to or remove the target from the
+ * current list of excluded targets.
+ * @return This transition object.
+ */
+ public Transition excludeTarget(String targetViewName, boolean exclude) {
+ mTargetNameExcludes = excludeObject(mTargetNameExcludes, targetViewName, exclude);
return this;
}
@@ -788,23 +1050,10 @@
* @return This transition object.
*/
public Transition excludeChildren(int targetId, boolean exclude) {
- mTargetIdChildExcludes = excludeId(mTargetIdChildExcludes, targetId, exclude);
- return this;
- }
-
- /**
- * Utility method to manage the boilerplate code that is the same whether we
- * are excluding targets or their children.
- */
- private ArrayList<Integer> excludeId(ArrayList<Integer> list, int targetId, boolean exclude) {
- if (targetId > 0) {
- if (exclude) {
- list = ArrayListManager.add(list, targetId);
- } else {
- list = ArrayListManager.remove(list, targetId);
- }
+ if (targetId >= 0) {
+ mTargetIdChildExcludes = excludeObject(mTargetIdChildExcludes, targetId, exclude);
}
- return list;
+ return this;
}
/**
@@ -829,7 +1078,7 @@
* @return This transition object.
*/
public Transition excludeTarget(View target, boolean exclude) {
- mTargetExcludes = excludeView(mTargetExcludes, target, exclude);
+ mTargetExcludes = excludeObject(mTargetExcludes, target, exclude);
return this;
}
@@ -855,7 +1104,7 @@
* @return This transition object.
*/
public Transition excludeChildren(View target, boolean exclude) {
- mTargetChildExcludes = excludeView(mTargetChildExcludes, target, exclude);
+ mTargetChildExcludes = excludeObject(mTargetChildExcludes, target, exclude);
return this;
}
@@ -863,7 +1112,7 @@
* Utility method to manage the boilerplate code that is the same whether we
* are excluding targets or their children.
*/
- private ArrayList<View> excludeView(ArrayList<View> list, View target, boolean exclude) {
+ private static <T> ArrayList<T> excludeObject(ArrayList<T> list, T target, boolean exclude) {
if (target != null) {
if (exclude) {
list = ArrayListManager.add(list, target);
@@ -896,7 +1145,7 @@
* @return This transition object.
*/
public Transition excludeTarget(Class type, boolean exclude) {
- mTargetTypeExcludes = excludeType(mTargetTypeExcludes, type, exclude);
+ mTargetTypeExcludes = excludeObject(mTargetTypeExcludes, type, exclude);
return this;
}
@@ -923,26 +1172,11 @@
* @return This transition object.
*/
public Transition excludeChildren(Class type, boolean exclude) {
- mTargetTypeChildExcludes = excludeType(mTargetTypeChildExcludes, type, exclude);
+ mTargetTypeChildExcludes = excludeObject(mTargetTypeChildExcludes, type, exclude);
return this;
}
/**
- * Utility method to manage the boilerplate code that is the same whether we
- * are excluding targets or their children.
- */
- private ArrayList<Class> excludeType(ArrayList<Class> list, Class type, boolean exclude) {
- if (type != null) {
- if (exclude) {
- list = ArrayListManager.add(list, type);
- } else {
- list = ArrayListManager.remove(list, type);
- }
- }
- return list;
- }
-
- /**
* Sets the target view instances that this Transition is interested in
* animating. By default, there are no targets, and a Transition will
* listen for changes on every view in the hierarchy below the sceneRoot
@@ -991,9 +1225,27 @@
}
/**
- * Returns the array of target IDs that this transition limits itself to
- * tracking and animating. If the array is null for both this method and
- * {@link #getTargets()}, then this transition is
+ * Removes the given target from the list of targets that this Transition
+ * is interested in animating.
+ *
+ * @param target The type of the target view, must be non-null.
+ * @return Transition The Transition from which the target is removed.
+ * Returning the same object makes it easier to chain calls during
+ * construction, such as
+ * <code>transitionSet.addTransitions(new Fade()).removeTarget(someType);</code>
+ */
+ public Transition removeTarget(Class target) {
+ if (target != null) {
+ mTargetTypes.remove(target);
+ }
+ return this;
+ }
+
+ /**
+ * Returns the list of target IDs that this transition limits itself to
+ * tracking and animating. If the list is null or empty for
+ * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetViewNames()}, and
+ * {@link #getTargetTypes()} then this transition is
* not limited to specific views, and will handle changes to any views
* in the hierarchy of a scene change.
*
@@ -1004,9 +1256,10 @@
}
/**
- * Returns the array of target views that this transition limits itself to
- * tracking and animating. If the array is null for both this method and
- * {@link #getTargetIds()}, then this transition is
+ * Returns the list of target views that this transition limits itself to
+ * tracking and animating. If the list is null or empty for
+ * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetViewNames()}, and
+ * {@link #getTargetTypes()} then this transition is
* not limited to specific views, and will handle changes to any views
* in the hierarchy of a scene change.
*
@@ -1017,6 +1270,34 @@
}
/**
+ * Returns the list of target viewNames that this transition limits itself to
+ * tracking and animating. If the list is null or empty for
+ * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetViewNames()}, and
+ * {@link #getTargetTypes()} then this transition is
+ * not limited to specific views, and will handle changes to any views
+ * in the hierarchy of a scene change.
+ *
+ * @return the list of target viewNames
+ */
+ public List<String> getTargetViewNames() {
+ return mTargetNames;
+ }
+
+ /**
+ * Returns the list of target viewNames that this transition limits itself to
+ * tracking and animating. If the list is null or empty for
+ * {@link #getTargetIds()}, {@link #getTargets()}, {@link #getTargetViewNames()}, and
+ * {@link #getTargetTypes()} then this transition is
+ * not limited to specific views, and will handle changes to any views
+ * in the hierarchy of a scene change.
+ *
+ * @return the list of target Types
+ */
+ public List<Class> getTargetTypes() {
+ return mTargetTypes;
+ }
+
+ /**
* Recursive method that captures values for the given view and the
* hierarchy underneath it.
* @param sceneRoot The root of the view hierarchy being captured
@@ -1025,52 +1306,42 @@
*/
void captureValues(ViewGroup sceneRoot, boolean start) {
clearValues(start);
- if (mTargetIds.size() > 0 || mTargets.size() > 0) {
- if (mTargetIds.size() > 0) {
- for (int i = 0; i < mTargetIds.size(); ++i) {
- int id = mTargetIds.get(i);
- View view = sceneRoot.findViewById(id);
- if (view != null) {
- TransitionValues values = new TransitionValues();
- values.view = view;
- if (start) {
- captureStartValues(values);
- } else {
- captureEndValues(values);
- }
- capturePropagationValues(values);
- if (start) {
- mStartValues.viewValues.put(view, values);
- if (id >= 0) {
- mStartValues.idValues.put(id, values);
- }
- } else {
- mEndValues.viewValues.put(view, values);
- if (id >= 0) {
- mEndValues.idValues.put(id, values);
- }
- }
+ if ((mTargetIds.size() > 0 || mTargets.size() > 0)
+ && (mTargetNames == null || mTargetNames.isEmpty())
+ && (mTargetTypes == null || mTargetTypes.isEmpty())) {
+ for (int i = 0; i < mTargetIds.size(); ++i) {
+ int id = mTargetIds.get(i);
+ View view = sceneRoot.findViewById(id);
+ if (view != null) {
+ TransitionValues values = new TransitionValues();
+ values.view = view;
+ if (start) {
+ captureStartValues(values);
+ } else {
+ captureEndValues(values);
+ }
+ capturePropagationValues(values);
+ if (start) {
+ addViewValues(mStartValues, view, values);
+ } else {
+ addViewValues(mEndValues, view, values);
}
}
}
- if (mTargets.size() > 0) {
- for (int i = 0; i < mTargets.size(); ++i) {
- View view = mTargets.get(i);
- if (view != null) {
- TransitionValues values = new TransitionValues();
- values.view = view;
- if (start) {
- captureStartValues(values);
- } else {
- captureEndValues(values);
- }
- capturePropagationValues(values);
- if (start) {
- mStartValues.viewValues.put(view, values);
- } else {
- mEndValues.viewValues.put(view, values);
- }
- }
+ for (int i = 0; i < mTargets.size(); ++i) {
+ View view = mTargets.get(i);
+ TransitionValues values = new TransitionValues();
+ values.view = view;
+ if (start) {
+ captureStartValues(values);
+ } else {
+ captureEndValues(values);
+ }
+ capturePropagationValues(values);
+ if (start) {
+ mStartValues.viewValues.put(view, values);
+ } else {
+ mEndValues.viewValues.put(view, values);
}
}
} else {
@@ -1078,6 +1349,47 @@
}
}
+ static void addViewValues(TransitionValuesMaps transitionValuesMaps,
+ View view, TransitionValues transitionValues) {
+ transitionValuesMaps.viewValues.put(view, transitionValues);
+ int id = view.getId();
+ if (id >= 0) {
+ if (transitionValuesMaps.idValues.indexOfKey(id) >= 0) {
+ // Duplicate IDs cannot match by ID.
+ transitionValuesMaps.idValues.put(id, null);
+ } else {
+ transitionValuesMaps.idValues.put(id, view);
+ }
+ }
+ String name = view.getViewName();
+ if (name != null) {
+ if (transitionValuesMaps.nameValues.containsKey(name)) {
+ // Duplicate viewNames: cannot match by viewName.
+ transitionValuesMaps.nameValues.put(name, null);
+ } else {
+ transitionValuesMaps.nameValues.put(name, view);
+ }
+ }
+ if (view.getParent() instanceof ListView) {
+ ListView listview = (ListView) view.getParent();
+ if (listview.getAdapter().hasStableIds()) {
+ int position = listview.getPositionForView(view);
+ long itemId = listview.getItemIdAtPosition(position);
+ if (transitionValuesMaps.itemIdValues.indexOfKey(itemId) >= 0) {
+ // Duplicate item IDs: cannot match by item ID.
+ View alreadyMatched = transitionValuesMaps.itemIdValues.get(itemId);
+ if (alreadyMatched != null) {
+ alreadyMatched.setHasTransientState(false);
+ transitionValuesMaps.itemIdValues.put(itemId, null);
+ }
+ } else {
+ view.setHasTransientState(true);
+ transitionValuesMaps.itemIdValues.put(itemId, view);
+ }
+ }
+ }
+ }
+
/**
* Clear valuesMaps for specified start/end state
*
@@ -1109,24 +1421,7 @@
if (view == null) {
return;
}
- boolean isListViewItem = false;
- if (view.getParent() instanceof ListView) {
- isListViewItem = true;
- }
- if (isListViewItem && !((ListView) view.getParent()).getAdapter().hasStableIds()) {
- // ignore listview children unless we can track them with stable IDs
- return;
- }
- int id = View.NO_ID;
- long itemId = View.NO_ID;
- if (!isListViewItem) {
- id = view.getId();
- } else {
- ListView listview = (ListView) view.getParent();
- int position = listview.getPositionForView(view);
- itemId = listview.getItemIdAtPosition(position);
- view.setHasTransientState(true);
- }
+ int id = view.getId();
if (mTargetIdExcludes != null && mTargetIdExcludes.contains(id)) {
return;
}
@@ -1151,23 +1446,9 @@
}
capturePropagationValues(values);
if (start) {
- if (!isListViewItem) {
- mStartValues.viewValues.put(view, values);
- if (id >= 0) {
- mStartValues.idValues.put((int) id, values);
- }
- } else {
- mStartValues.itemIdValues.put(itemId, values);
- }
+ addViewValues(mStartValues, view, values);
} else {
- if (!isListViewItem) {
- mEndValues.viewValues.put(view, values);
- if (id >= 0) {
- mEndValues.idValues.put((int) id, values);
- }
- } else {
- mEndValues.itemIdValues.put(itemId, values);
- }
+ addViewValues(mEndValues, view, values);
}
}
if (view instanceof ViewGroup) {
@@ -1178,7 +1459,7 @@
if (mTargetChildExcludes != null && mTargetChildExcludes.contains(view)) {
return;
}
- if (mTargetTypeChildExcludes != null && view != null) {
+ if (mTargetTypeChildExcludes != null) {
int numTypes = mTargetTypeChildExcludes.size();
for (int i = 0; i < numTypes; ++i) {
if (mTargetTypeChildExcludes.get(i).isInstance(view)) {
@@ -1204,22 +1485,7 @@
return mParent.getTransitionValues(view, start);
}
TransitionValuesMaps valuesMaps = start ? mStartValues : mEndValues;
- TransitionValues values = valuesMaps.viewValues.get(view);
- if (values == null) {
- int id = view.getId();
- if (id >= 0) {
- values = valuesMaps.idValues.get(id);
- }
- if (values == null && view.getParent() instanceof ListView) {
- ListView listview = (ListView) view.getParent();
- int position = listview.getPositionForView(view);
- long itemId = listview.getItemIdAtPosition(position);
- values = valuesMaps.itemIdValues.get(itemId);
- }
- // TODO: Doesn't handle the case where a view was parented to a
- // ListView (with an itemId), but no longer is
- }
- return values;
+ return valuesMaps.viewValues.get(view);
}
/**
@@ -1303,11 +1569,7 @@
boolean cancel = false;
TransitionValues oldValues = oldInfo.values;
View oldView = oldInfo.view;
- TransitionValues newValues = mEndValues.viewValues != null ?
- mEndValues.viewValues.get(oldView) : null;
- if (newValues == null) {
- newValues = mEndValues.idValues.get(oldView.getId());
- }
+ TransitionValues newValues = mEndValues.viewValues.get(oldView);
if (oldValues != null) {
// if oldValues null, then transition didn't care to stash values,
// and won't get canceled
@@ -1429,17 +1691,15 @@
}
}
for (int i = 0; i < mStartValues.itemIdValues.size(); ++i) {
- TransitionValues tv = mStartValues.itemIdValues.valueAt(i);
- View v = tv.view;
- if (v.hasTransientState()) {
- v.setHasTransientState(false);
+ View view = mStartValues.itemIdValues.valueAt(i);
+ if (view != null) {
+ view.setHasTransientState(false);
}
}
for (int i = 0; i < mEndValues.itemIdValues.size(); ++i) {
- TransitionValues tv = mEndValues.itemIdValues.valueAt(i);
- View v = tv.view;
- if (v.hasTransientState()) {
- v.setHasTransientState(false);
+ View view = mEndValues.itemIdValues.valueAt(i);
+ if (view != null) {
+ view.setHasTransientState(false);
}
}
mEnded = true;
diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
index a5e960a..f4b562f 100644
--- a/core/java/android/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -30,6 +30,7 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.StringTokenizer;
/**
* This class inflates scenes and transitions from resource files.
@@ -40,6 +41,10 @@
* and {@link android.R.styleable#TransitionManager}.
*/
public class TransitionInflater {
+ private static final String MATCH_INSTANCE = "instance";
+ private static final String MATCH_VIEW_NAME = "viewName";
+ private static final String MATCH_ID = "id";
+ private static final String MATCH_ITEM_ID = "itemId";
private Context mContext;
@@ -229,11 +234,20 @@
com.android.internal.R.styleable.TransitionTarget);
int id = a.getResourceId(
com.android.internal.R.styleable.TransitionTarget_targetId, -1);
+ String viewName;
if (id >= 0) {
transition.addTarget(id);
} else if ((id = a.getResourceId(
com.android.internal.R.styleable.TransitionTarget_excludeId, -1)) >= 0) {
transition.excludeTarget(id, true);
+ } else if ((viewName = a.getString(
+ com.android.internal.R.styleable.TransitionTarget_targetViewName))
+ != null) {
+ transition.addTarget(viewName);
+ } else if ((viewName = a.getString(
+ com.android.internal.R.styleable.TransitionTarget_excludeViewName))
+ != null) {
+ transition.excludeTarget(viewName, true);
} else {
String className = a.getString(
com.android.internal.R.styleable.TransitionTarget_excludeClass);
@@ -257,6 +271,33 @@
}
}
+ private int[] parseMatchOrder(String matchOrderString) {
+ StringTokenizer st = new StringTokenizer(matchOrderString, ",");
+ int matches[] = new int[st.countTokens()];
+ int index = 0;
+ while (st.hasMoreTokens()) {
+ String token = st.nextToken().trim();
+ if (MATCH_ID.equalsIgnoreCase(token)) {
+ matches[index] = Transition.MATCH_ID;
+ } else if (MATCH_INSTANCE.equalsIgnoreCase(token)) {
+ matches[index] = Transition.MATCH_INSTANCE;
+ } else if (MATCH_VIEW_NAME.equalsIgnoreCase(token)) {
+ matches[index] = Transition.MATCH_VIEW_NAME;
+ } else if (MATCH_ITEM_ID.equalsIgnoreCase(token)) {
+ matches[index] = Transition.MATCH_ITEM_ID;
+ } else if (token.isEmpty()) {
+ int[] smallerMatches = new int[matches.length - 1];
+ System.arraycopy(matches, 0, smallerMatches, 0, index);
+ matches = smallerMatches;
+ index--;
+ } else {
+ throw new RuntimeException("Unknown match type in matchOrder: '" + token + "'");
+ }
+ index++;
+ }
+ return matches;
+ }
+
private Transition loadTransition(Transition transition, AttributeSet attrs)
throws Resources.NotFoundException {
@@ -275,6 +316,11 @@
if (resID > 0) {
transition.setInterpolator(AnimationUtils.loadInterpolator(mContext, resID));
}
+ String matchOrder =
+ a.getString(com.android.internal.R.styleable.Transition_matchOrder);
+ if (matchOrder != null) {
+ transition.setMatchOrder(parseMatchOrder(matchOrder));
+ }
a.recycle();
return transition;
}
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index 9081234..698b563 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -272,24 +272,8 @@
int numValues = values.viewValues.size();
for (int i = 0; i < numValues; i++) {
View view = values.viewValues.keyAt(i);
- if (isValidTarget(view, view.getId())) {
- included.viewValues.put(view, values.viewValues.valueAt(i));
- }
- }
- numValues = values.idValues.size();
- for (int i = 0; i < numValues; i++) {
- int id = values.idValues.keyAt(i);
- TransitionValues transitionValues = values.idValues.valueAt(i);
- if (isValidTarget(transitionValues.view, id)) {
- included.idValues.put(id, transitionValues);
- }
- }
- numValues = values.itemIdValues.size();
- for (int i = 0; i < numValues; i++) {
- long id = values.itemIdValues.keyAt(i);
- TransitionValues transitionValues = values.itemIdValues.valueAt(i);
- if (isValidTarget(transitionValues.view, id)) {
- included.itemIdValues.put(id, transitionValues);
+ if (isValidTarget(view)) {
+ addViewValues(included, view, values.viewValues.valueAt(i));
}
}
return included;
@@ -328,10 +312,9 @@
@Override
public void captureStartValues(TransitionValues transitionValues) {
- int targetId = transitionValues.view.getId();
- if (isValidTarget(transitionValues.view, targetId)) {
+ if (isValidTarget(transitionValues.view)) {
for (Transition childTransition : mTransitions) {
- if (childTransition.isValidTarget(transitionValues.view, targetId)) {
+ if (childTransition.isValidTarget(transitionValues.view)) {
childTransition.captureStartValues(transitionValues);
}
}
@@ -340,10 +323,9 @@
@Override
public void captureEndValues(TransitionValues transitionValues) {
- int targetId = transitionValues.view.getId();
- if (isValidTarget(transitionValues.view, targetId)) {
+ if (isValidTarget(transitionValues.view)) {
for (Transition childTransition : mTransitions) {
- if (childTransition.isValidTarget(transitionValues.view, targetId)) {
+ if (childTransition.isValidTarget(transitionValues.view)) {
childTransition.captureEndValues(transitionValues);
}
}
diff --git a/core/java/android/transition/TransitionValuesMaps.java b/core/java/android/transition/TransitionValuesMaps.java
index 131596b..6d5700a 100644
--- a/core/java/android/transition/TransitionValuesMaps.java
+++ b/core/java/android/transition/TransitionValuesMaps.java
@@ -24,7 +24,7 @@
class TransitionValuesMaps {
ArrayMap<View, TransitionValues> viewValues =
new ArrayMap<View, TransitionValues>();
- SparseArray<TransitionValues> idValues = new SparseArray<TransitionValues>();
- LongSparseArray<TransitionValues> itemIdValues =
- new LongSparseArray<TransitionValues>();
+ SparseArray<View> idValues = new SparseArray<View>();
+ LongSparseArray<View> itemIdValues = new LongSparseArray<View>();
+ ArrayMap<String, View> nameValues = new ArrayMap<String, View>();
}
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 6e6496c..0f7638b 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -162,26 +162,15 @@
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
VisibilityInfo visInfo = getVisibilityChangeInfo(startValues, endValues);
- if (visInfo.visibilityChange) {
- // Only transition views that are either targets of this transition
- // or whose parent hierarchies remain stable between scenes
- boolean isTarget = false;
- if (mTargets.size() > 0 || mTargetIds.size() > 0) {
- View startView = startValues != null ? startValues.view : null;
- View endView = endValues != null ? endValues.view : null;
- int startId = startView != null ? startView.getId() : -1;
- int endId = endView != null ? endView.getId() : -1;
- isTarget = isValidTarget(startView, startId) || isValidTarget(endView, endId);
- }
- if (isTarget || ((visInfo.startParent != null || visInfo.endParent != null))) {
- if (visInfo.fadeIn) {
- return onAppear(sceneRoot, startValues, visInfo.startVisibility,
- endValues, visInfo.endVisibility);
- } else {
- return onDisappear(sceneRoot, startValues, visInfo.startVisibility,
- endValues, visInfo.endVisibility
- );
- }
+ if (visInfo.visibilityChange
+ && (visInfo.startParent != null || visInfo.endParent != null)) {
+ if (visInfo.fadeIn) {
+ return onAppear(sceneRoot, startValues, visInfo.startVisibility,
+ endValues, visInfo.endVisibility);
+ } else {
+ return onDisappear(sceneRoot, startValues, visInfo.startVisibility,
+ endValues, visInfo.endVisibility
+ );
}
}
return null;
diff --git a/core/java/android/tv/ITvInputClient.aidl b/core/java/android/tv/ITvInputClient.aidl
index 538f8a1..ac83356 100644
--- a/core/java/android/tv/ITvInputClient.aidl
+++ b/core/java/android/tv/ITvInputClient.aidl
@@ -26,6 +26,7 @@
* @hide
*/
oneway interface ITvInputClient {
- void onSessionCreated(in ComponentName name, IBinder token, in InputChannel channel, int seq);
- void onAvailabilityChanged(in ComponentName name, boolean isAvailable);
+ void onSessionCreated(in String inputId, IBinder token, in InputChannel channel, int seq);
+ void onAvailabilityChanged(in String inputId, boolean isAvailable);
+ void onSessionReleased(int seq);
}
diff --git a/core/java/android/tv/ITvInputManager.aidl b/core/java/android/tv/ITvInputManager.aidl
index a4c99e4..b756aba 100644
--- a/core/java/android/tv/ITvInputManager.aidl
+++ b/core/java/android/tv/ITvInputManager.aidl
@@ -30,12 +30,12 @@
interface ITvInputManager {
List<TvInputInfo> getTvInputList(int userId);
- boolean getAvailability(in ITvInputClient client, in ComponentName name, int userId);
+ boolean getAvailability(in ITvInputClient client, in String inputId, int userId);
- void registerCallback(in ITvInputClient client, in ComponentName name, int userId);
- void unregisterCallback(in ITvInputClient client, in ComponentName name, int userId);
+ void registerCallback(in ITvInputClient client, in String inputId, int userId);
+ void unregisterCallback(in ITvInputClient client, in String inputId, int userId);
- void createSession(in ITvInputClient client, in ComponentName name, int seq, int userId);
+ void createSession(in ITvInputClient client, in String inputId, int seq, int userId);
void releaseSession(in IBinder sessionToken, int userId);
void setSurface(in IBinder sessionToken, in Surface surface, int userId);
diff --git a/core/java/android/tv/ITvInputServiceCallback.aidl b/core/java/android/tv/ITvInputServiceCallback.aidl
index e535c81..71fc780 100644
--- a/core/java/android/tv/ITvInputServiceCallback.aidl
+++ b/core/java/android/tv/ITvInputServiceCallback.aidl
@@ -24,5 +24,5 @@
* @hide
*/
oneway interface ITvInputServiceCallback {
- void onAvailabilityChanged(in ComponentName name, boolean isAvailable);
+ void onAvailabilityChanged(in String inputId, boolean isAvailable);
}
diff --git a/core/java/android/tv/TvInputInfo.java b/core/java/android/tv/TvInputInfo.java
index 90e4177..50462cc 100644
--- a/core/java/android/tv/TvInputInfo.java
+++ b/core/java/android/tv/TvInputInfo.java
@@ -39,7 +39,7 @@
public TvInputInfo(ResolveInfo service) {
mService = service;
ServiceInfo si = service.serviceInfo;
- mId = new ComponentName(si.packageName, si.name).flattenToShortString();
+ mId = generateInputIdForComponenetName(new ComponentName(si.packageName, si.name));
}
/**
@@ -75,7 +75,7 @@
* Loads the user-displayed label for this TV input service.
*
* @param pm Supplies a PackageManager used to load the TV input's resources.
- * @return Returns a CharSequence containing the TV input's label. If the TV input does not have
+ * @return a CharSequence containing the TV input's label. If the TV input does not have
* a label, its name is returned.
*/
public CharSequence loadLabel(PackageManager pm) {
@@ -128,6 +128,17 @@
}
/**
+ * Used to generate an input id from a ComponentName.
+ *
+ * @param name the component name for generating an input id.
+ * @return the generated input id for the given {@code name}.
+ * @hide
+ */
+ public static final String generateInputIdForComponenetName(ComponentName name) {
+ return name.flattenToShortString();
+ }
+
+ /**
* Used to make this class parcelable.
*
* @hide
diff --git a/core/java/android/tv/TvInputManager.java b/core/java/android/tv/TvInputManager.java
index 7b9b1fb..c5f179a 100644
--- a/core/java/android/tv/TvInputManager.java
+++ b/core/java/android/tv/TvInputManager.java
@@ -16,7 +16,6 @@
package android.tv;
-import android.content.ComponentName;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Handler;
@@ -50,15 +49,15 @@
private final ITvInputManager mService;
// A mapping from an input to the list of its TvInputListenerRecords.
- private final Map<ComponentName, List<TvInputListenerRecord>> mTvInputListenerRecordsMap =
- new HashMap<ComponentName, List<TvInputListenerRecord>>();
+ private final Map<String, List<TvInputListenerRecord>> mTvInputListenerRecordsMap =
+ new HashMap<String, List<TvInputListenerRecord>>();
- // A mapping from the sequence number of a session to its SessionCreateCallbackRecord.
- private final SparseArray<SessionCreateCallbackRecord> mSessionCreateCallbackRecordMap =
- new SparseArray<SessionCreateCallbackRecord>();
+ // A mapping from the sequence number of a session to its SessionCallbackRecord.
+ private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap =
+ new SparseArray<SessionCallbackRecord>();
// A sequence number for the next session to be created. Should be protected by a lock
- // {@code mSessionCreateCallbackRecordMap}.
+ // {@code mSessionCallbackRecordMap}.
private int mNextSeq;
private final ITvInputClient mClient;
@@ -68,31 +67,52 @@
/**
* Interface used to receive the created session.
*/
- public interface SessionCreateCallback {
+ public abstract static class SessionCallback {
/**
* This is called after {@link TvInputManager#createSession} has been processed.
*
* @param session A {@link TvInputManager.Session} instance created. This can be
* {@code null} if the creation request failed.
*/
- void onSessionCreated(Session session);
+ public void onSessionCreated(Session session) {
+ }
+
+ /**
+ * This is called when {@link TvInputManager.Session} is released.
+ * This typically happens when the process hosting the session has crashed or been killed.
+ *
+ * @param session A {@link TvInputManager.Session} instance released.
+ */
+ public void onSessionReleased(Session session) {
+ }
}
- private static final class SessionCreateCallbackRecord {
- private final SessionCreateCallback mSessionCreateCallback;
+ private static final class SessionCallbackRecord {
+ private final SessionCallback mSessionCallback;
private final Handler mHandler;
+ private Session mSession;
- public SessionCreateCallbackRecord(SessionCreateCallback sessionCreateCallback,
+ public SessionCallbackRecord(SessionCallback sessionCallback,
Handler handler) {
- mSessionCreateCallback = sessionCreateCallback;
+ mSessionCallback = sessionCallback;
mHandler = handler;
}
public void postSessionCreated(final Session session) {
+ mSession = session;
mHandler.post(new Runnable() {
@Override
public void run() {
- mSessionCreateCallback.onSessionCreated(session);
+ mSessionCallback.onSessionCreated(session);
+ }
+ });
+ }
+
+ public void postSessionReleased() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mSessionCallback.onSessionReleased(mSession);
}
});
}
@@ -105,12 +125,11 @@
/**
* This is called when the availability status of a given TV input is changed.
*
- * @param name {@link ComponentName} of {@link android.app.Service} that implements the
- * given TV input.
+ * @param inputId the id of the TV input.
* @param isAvailable {@code true} if the given TV input is available to show TV programs.
* {@code false} otherwise.
*/
- public void onAvailabilityChanged(ComponentName name, boolean isAvailable) {
+ public void onAvailabilityChanged(String inputId, boolean isAvailable) {
}
}
@@ -127,11 +146,11 @@
return mListener;
}
- public void postAvailabilityChanged(final ComponentName name, final boolean isAvailable) {
+ public void postAvailabilityChanged(final String inputId, final boolean isAvailable) {
mHandler.post(new Runnable() {
@Override
public void run() {
- mListener.onAvailabilityChanged(name, isAvailable);
+ mListener.onAvailabilityChanged(inputId, isAvailable);
}
});
}
@@ -145,34 +164,48 @@
mUserId = userId;
mClient = new ITvInputClient.Stub() {
@Override
- public void onSessionCreated(ComponentName name, IBinder token, InputChannel channel,
+ public void onSessionCreated(String inputId, IBinder token, InputChannel channel,
int seq) {
- synchronized (mSessionCreateCallbackRecordMap) {
- SessionCreateCallbackRecord record = mSessionCreateCallbackRecordMap.get(seq);
- mSessionCreateCallbackRecordMap.delete(seq);
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
Log.e(TAG, "Callback not found for " + token);
return;
}
Session session = null;
if (token != null) {
- session = new Session(token, channel, mService, mUserId);
+ session = new Session(token, channel, mService, mUserId, seq,
+ mSessionCallbackRecordMap);
}
record.postSessionCreated(session);
}
}
@Override
- public void onAvailabilityChanged(ComponentName name, boolean isAvailable) {
+ public void onSessionReleased(int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ mSessionCallbackRecordMap.delete(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq:" + seq);
+ return;
+ }
+ record.mSession.releaseInternal();
+ record.postSessionReleased();
+ }
+ }
+
+ @Override
+ public void onAvailabilityChanged(String inputId, boolean isAvailable) {
synchronized (mTvInputListenerRecordsMap) {
- List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(name);
+ List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId);
if (records == null) {
// Silently ignore - no listener is registered yet.
return;
}
int recordsCount = records.size();
for (int i = 0; i < recordsCount; i++) {
- records.get(i).postAvailabilityChanged(name, isAvailable);
+ records.get(i).postAvailabilityChanged(inputId, isAvailable);
}
}
}
@@ -195,24 +228,23 @@
/**
* Returns the availability of a given TV input.
*
- * @param name {@link ComponentName} of {@link android.app.Service} that implements the given TV
- * input.
+ * @param inputId the id of the TV input.
* @throws IllegalArgumentException if the argument is {@code null}.
* @throws IllegalStateException If there is no {@link TvInputListener} registered on the given
* TV input.
*/
- public boolean getAvailability(ComponentName name) {
- if (name == null) {
- throw new IllegalArgumentException("name cannot be null");
+ public boolean getAvailability(String inputId) {
+ if (inputId == null) {
+ throw new IllegalArgumentException("id cannot be null");
}
synchronized (mTvInputListenerRecordsMap) {
- List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(name);
+ List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId);
if (records == null || records.size() == 0) {
throw new IllegalStateException("At least one listener should be registered.");
}
}
try {
- return mService.getAvailability(mClient, name, mUserId);
+ return mService.getAvailability(mClient, inputId, mUserId);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -221,15 +253,14 @@
/**
* Registers a {@link TvInputListener} for a given TV input.
*
- * @param name {@link ComponentName} of {@link android.app.Service} that implements the given TV
- * input.
+ * @param inputId the id of the TV input.
* @param listener a listener used to monitor status of the given TV input.
* @param handler a {@link Handler} that the status change will be delivered to.
* @throws IllegalArgumentException if any of the arguments is {@code null}.
*/
- public void registerListener(ComponentName name, TvInputListener listener, Handler handler) {
- if (name == null) {
- throw new IllegalArgumentException("name cannot be null");
+ public void registerListener(String inputId, TvInputListener listener, Handler handler) {
+ if (inputId == null) {
+ throw new IllegalArgumentException("id cannot be null");
}
if (listener == null) {
throw new IllegalArgumentException("listener cannot be null");
@@ -238,12 +269,12 @@
throw new IllegalArgumentException("handler cannot be null");
}
synchronized (mTvInputListenerRecordsMap) {
- List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(name);
+ List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId);
if (records == null) {
records = new ArrayList<TvInputListenerRecord>();
- mTvInputListenerRecordsMap.put(name, records);
+ mTvInputListenerRecordsMap.put(inputId, records);
try {
- mService.registerCallback(mClient, name, mUserId);
+ mService.registerCallback(mClient, inputId, mUserId);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -255,22 +286,21 @@
/**
* Unregisters the existing {@link TvInputListener} for a given TV input.
*
- * @param name {@link ComponentName} of {@link android.app.Service} that implements the given TV
- * input.
+ * @param inputId the id of the TV input.
* @param listener the existing listener to remove for the given TV input.
* @throws IllegalArgumentException if any of the arguments is {@code null}.
*/
- public void unregisterListener(ComponentName name, final TvInputListener listener) {
- if (name == null) {
- throw new IllegalArgumentException("name cannot be null");
+ public void unregisterListener(String inputId, final TvInputListener listener) {
+ if (inputId == null) {
+ throw new IllegalArgumentException("id cannot be null");
}
if (listener == null) {
throw new IllegalArgumentException("listener cannot be null");
}
synchronized (mTvInputListenerRecordsMap) {
- List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(name);
+ List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId);
if (records == null) {
- Log.e(TAG, "No listener found for " + name.getClassName());
+ Log.e(TAG, "No listener found for " + inputId);
return;
}
for (Iterator<TvInputListenerRecord> it = records.iterator(); it.hasNext();) {
@@ -281,11 +311,11 @@
}
if (records.isEmpty()) {
try {
- mService.unregisterCallback(mClient, name, mUserId);
+ mService.unregisterCallback(mClient, inputId, mUserId);
} catch (RemoteException e) {
throw new RuntimeException(e);
} finally {
- mTvInputListenerRecordsMap.remove(name);
+ mTvInputListenerRecordsMap.remove(inputId);
}
}
}
@@ -298,16 +328,15 @@
* the given TV input.
* </p>
*
- * @param name {@link ComponentName} of {@link android.app.Service} that implements the given TV
- * input.
+ * @param inputId the id of the TV input.
* @param callback a callback used to receive the created session.
* @param handler a {@link Handler} that the session creation will be delivered to.
* @throws IllegalArgumentException if any of the arguments is {@code null}.
*/
- public void createSession(ComponentName name, final SessionCreateCallback callback,
+ public void createSession(String inputId, final SessionCallback callback,
Handler handler) {
- if (name == null) {
- throw new IllegalArgumentException("name cannot be null");
+ if (inputId == null) {
+ throw new IllegalArgumentException("id cannot be null");
}
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
@@ -315,12 +344,12 @@
if (handler == null) {
throw new IllegalArgumentException("handler cannot be null");
}
- SessionCreateCallbackRecord record = new SessionCreateCallbackRecord(callback, handler);
- synchronized (mSessionCreateCallbackRecordMap) {
+ SessionCallbackRecord record = new SessionCallbackRecord(callback, handler);
+ synchronized (mSessionCallbackRecordMap) {
int seq = mNextSeq++;
- mSessionCreateCallbackRecordMap.put(seq, record);
+ mSessionCallbackRecordMap.put(seq, record);
try {
- mService.createSession(mClient, name, seq, mUserId);
+ mService.createSession(mClient, inputId, seq, mUserId);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -337,6 +366,7 @@
private final ITvInputManager mService;
private final int mUserId;
+ private final int mSeq;
// For scheduling input event handling on the main thread. This also serves as a lock to
// protect pending input events and the input channel.
@@ -344,17 +374,21 @@
private final Pool<PendingEvent> mPendingEventPool = new SimplePool<PendingEvent>(20);
private final SparseArray<PendingEvent> mPendingEvents = new SparseArray<PendingEvent>(20);
+ private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap;
private IBinder mToken;
private TvInputEventSender mSender;
private InputChannel mChannel;
/** @hide */
- private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId) {
+ private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId,
+ int seq, SparseArray<SessionCallbackRecord> sessionCallbackRecordMap) {
mToken = token;
mChannel = channel;
mService = service;
mUserId = userId;
+ mSeq = seq;
+ mSessionCallbackRecordMap = sessionCallbackRecordMap;
}
/**
@@ -368,22 +402,11 @@
}
try {
mService.releaseSession(mToken, mUserId);
- mToken = null;
} catch (RemoteException e) {
throw new RuntimeException(e);
}
- synchronized (mHandler) {
- if (mChannel != null) {
- if (mSender != null) {
- flushPendingEventsLocked();
- mSender.dispose();
- mSender = null;
- }
- mChannel.dispose();
- mChannel = null;
- }
- }
+ releaseInternal();
}
/**
@@ -675,6 +698,24 @@
mPendingEventPool.release(p);
}
+ private void releaseInternal() {
+ mToken = null;
+ synchronized (mHandler) {
+ if (mChannel != null) {
+ if (mSender != null) {
+ flushPendingEventsLocked();
+ mSender.dispose();
+ mSender = null;
+ }
+ mChannel.dispose();
+ mChannel = null;
+ }
+ }
+ synchronized (mSessionCallbackRecordMap) {
+ mSessionCallbackRecordMap.remove(mSeq);
+ }
+ }
+
private final class InputEventHandler extends Handler {
public static final int MSG_SEND_INPUT_EVENT = 1;
public static final int MSG_TIMEOUT_INPUT_EVENT = 2;
diff --git a/core/java/android/tv/TvInputService.java b/core/java/android/tv/TvInputService.java
index 70e7f95..eeb738d 100644
--- a/core/java/android/tv/TvInputService.java
+++ b/core/java/android/tv/TvInputService.java
@@ -60,7 +60,7 @@
*/
public static final String SERVICE_INTERFACE = "android.tv.TvInputService";
- private ComponentName mComponentName;
+ private String mId;
private final Handler mHandler = new ServiceHandler();
private final RemoteCallbackList<ITvInputServiceCallback> mCallbacks =
new RemoteCallbackList<ITvInputServiceCallback>();
@@ -69,7 +69,8 @@
@Override
public void onCreate() {
super.onCreate();
- mComponentName = new ComponentName(getPackageName(), getClass().getName());
+ mId = TvInputInfo.generateInputIdForComponenetName(
+ new ComponentName(getPackageName(), getClass().getName()));
}
@Override
@@ -82,7 +83,7 @@
// The first time a callback is registered, the service needs to report its
// availability status so that the system can know its initial value.
try {
- cb.onAvailabilityChanged(mComponentName, mAvailable);
+ cb.onAvailabilityChanged(mId, mAvailable);
} catch (RemoteException e) {
Log.e(TAG, "error in onAvailabilityChanged", e);
}
@@ -488,7 +489,7 @@
}
}
}
- if (mOverlayView == null) {
+ if (mOverlayView == null || !mOverlayView.isAttachedToWindow()) {
return Session.DISPATCH_NOT_HANDLED;
}
if (!mOverlayView.hasWindowFocus()) {
@@ -531,8 +532,7 @@
int n = mCallbacks.beginBroadcast();
try {
for (int i = 0; i < n; i++) {
- mCallbacks.getBroadcastItem(i).onAvailabilityChanged(mComponentName,
- isAvailable);
+ mCallbacks.getBroadcastItem(i).onAvailabilityChanged(mId, isAvailable);
}
} catch (RemoteException e) {
Log.e(TAG, "Unexpected exception", e);
diff --git a/core/java/android/tv/TvView.java b/core/java/android/tv/TvView.java
index 289823b..7721575 100644
--- a/core/java/android/tv/TvView.java
+++ b/core/java/android/tv/TvView.java
@@ -16,13 +16,13 @@
package android.tv;
-import android.content.ComponentName;
import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
+import android.text.TextUtils;
import android.tv.TvInputManager.Session;
import android.tv.TvInputManager.Session.FinishedInputEventCallback;
-import android.tv.TvInputManager.SessionCreateCallback;
+import android.tv.TvInputManager.SessionCallback;
import android.util.AttributeSet;
import android.util.Log;
import android.view.InputEvent;
@@ -31,6 +31,7 @@
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
+import android.view.ViewRootImpl;
/**
* View playing TV
@@ -46,7 +47,7 @@
private boolean mOverlayViewCreated;
private Rect mOverlayViewFrame;
private final TvInputManager mTvInputManager;
- private SessionCreateCallback mSessionCreateCallback;
+ private SessionCallback mSessionCallback;
private OnUnhandledInputEventListener mOnUnhandledInputEventListener;
private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
@@ -89,7 +90,10 @@
if (dispatchUnhandledInputEvent(event)) {
return;
}
- getViewRootImpl().dispatchUnhandledInputEvent(event);
+ ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl != null) {
+ viewRootImpl.dispatchUnhandledInputEvent(event);
+ }
}
};
@@ -108,19 +112,19 @@
}
/**
- * Binds a TV input to this view. {@link SessionCreateCallback#onSessionCreated} will be
+ * Binds a TV input to this view. {@link SessionCallback#onSessionCreated} will be
* called to send the result of this binding with {@link TvInputManager.Session}.
* If a TV input is already bound, the input will be unbound from this view and its session
* will be released.
*
- * @param name TV input name will be bound to this view.
+ * @param inputId the id of TV input which will be bound to this view.
* @param callback called when TV input is bound. The callback sends
* {@link TvInputManager.Session}
* @throws IllegalArgumentException if any of the arguments is {@code null}.
*/
- public void bindTvInput(ComponentName name, SessionCreateCallback callback) {
- if (name == null) {
- throw new IllegalArgumentException("name cannot be null");
+ public void bindTvInput(String inputId, SessionCallback callback) {
+ if (TextUtils.isEmpty(inputId)) {
+ throw new IllegalArgumentException("inputId cannot be null or an empty string");
}
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
@@ -130,11 +134,11 @@
}
// When bindTvInput is called multiple times before the callback is called,
// only the callback of the last bindTvInput call will be actually called back.
- // The previous callbacks will be ignored. For the logic, mSessionCreateCallback
+ // The previous callbacks will be ignored. For the logic, mSessionCallback
// is newly assigned for every bindTvInput call and compared with
// MySessionCreateCallback.this.
- mSessionCreateCallback = new MySessionCreateCallback(callback);
- mTvInputManager.createSession(name, mSessionCreateCallback, mHandler);
+ mSessionCallback = new MySessionCallback(callback);
+ mTvInputManager.createSession(inputId, mSessionCallback, mHandler);
}
/**
@@ -196,7 +200,9 @@
if (mSession == null) {
return false;
}
- int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler);
+ InputEvent copiedEvent = event.copy();
+ int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,
+ mHandler);
return ret != Session.DISPATCH_NOT_HANDLED;
}
@@ -209,7 +215,9 @@
if (mSession == null) {
return false;
}
- int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler);
+ InputEvent copiedEvent = event.copy();
+ int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,
+ mHandler);
return ret != Session.DISPATCH_NOT_HANDLED;
}
@@ -222,7 +230,9 @@
if (mSession == null) {
return false;
}
- int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler);
+ InputEvent copiedEvent = event.copy();
+ int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,
+ mHandler);
return ret != Session.DISPATCH_NOT_HANDLED;
}
@@ -235,7 +245,9 @@
if (mSession == null) {
return false;
}
- int ret = mSession.dispatchInputEvent(event, event, mFinishedInputEventCallback, mHandler);
+ InputEvent copiedEvent = event.copy();
+ int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,
+ mHandler);
return ret != Session.DISPATCH_NOT_HANDLED;
}
@@ -328,18 +340,20 @@
boolean onUnhandledInputEvent(InputEvent event);
}
- private class MySessionCreateCallback implements SessionCreateCallback {
- final SessionCreateCallback mExternalCallback;
+ private class MySessionCallback extends SessionCallback {
+ final SessionCallback mExternalCallback;
- MySessionCreateCallback(SessionCreateCallback externalCallback) {
+ MySessionCallback(SessionCallback externalCallback) {
mExternalCallback = externalCallback;
}
@Override
public void onSessionCreated(Session session) {
- if (this != mSessionCreateCallback) {
+ if (this != mSessionCallback) {
// This callback is obsolete.
- session.release();
+ if (session != null) {
+ session.release();
+ }
return;
}
mSession = session;
@@ -356,5 +370,13 @@
mExternalCallback.onSessionCreated(session);
}
}
+
+ @Override
+ public void onSessionReleased(Session session) {
+ mSession = null;
+ if (mExternalCallback != null) {
+ mExternalCallback.onSessionReleased(session);
+ }
+ }
}
}
diff --git a/core/java/android/util/Range.java b/core/java/android/util/Range.java
index 9a4bd4b..d7e8cf0 100644
--- a/core/java/android/util/Range.java
+++ b/core/java/android/util/Range.java
@@ -18,7 +18,7 @@
import static com.android.internal.util.Preconditions.*;
-import android.hardware.camera2.impl.HashCodeHelpers;
+import android.hardware.camera2.utils.HashCodeHelpers;
/**
* Immutable class for describing the range of two numeric values.
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 33964a0..8f4b710 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -245,6 +245,9 @@
private static final int SECONDS_PER_HOUR = 60 * 60;
private static final int SECONDS_PER_DAY = 24 * 60 * 60;
+ /** @hide */
+ public static final long NANOS_PER_MS = 1000000;
+
private static final Object sFormatSync = new Object();
private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+5];
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 0a76075..1066430 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -112,8 +112,6 @@
private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt(
"debug.choreographer.skipwarning", 30);
- private static final long NANOS_PER_MS = 1000000;
-
private static final int MSG_DO_FRAME = 0;
private static final int MSG_DO_SCHEDULE_VSYNC = 1;
private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
@@ -263,7 +261,7 @@
* @return The refresh rate as the nanoseconds between frames
* @hide
*/
- long getFrameIntervalNanos() {
+ public long getFrameIntervalNanos() {
return mFrameIntervalNanos;
}
@@ -456,7 +454,7 @@
* @hide
*/
public long getFrameTime() {
- return getFrameTimeNanos() / NANOS_PER_MS;
+ return getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
}
/**
@@ -497,7 +495,7 @@
}
} else {
final long nextFrameTime = Math.max(
- mLastFrameTimeNanos / NANOS_PER_MS + sFrameDelay, now);
+ mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
if (DEBUG) {
Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
}
@@ -746,7 +744,7 @@
mFrame = frame;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
- mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS);
+ mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 6c451eb..a272296 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -1127,14 +1127,15 @@
int modifiers = setupModifiers(paint);
try {
- nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
+ nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint,
+ paint.mNativeTypeface);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
}
private static native void nDrawText(long renderer, char[] text, int index, int count,
- float x, float y, int bidiFlags, long paint);
+ float x, float y, int bidiFlags, long paint, long typeface);
@Override
public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
@@ -1143,7 +1144,7 @@
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
- paint.mNativePaint);
+ paint.mNativePaint, paint.mNativeTypeface);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawText(this, start, end, x, y,
paint);
@@ -1151,7 +1152,7 @@
char[] buf = TemporaryBuffer.obtain(end - start);
TextUtils.getChars(text, start, end, buf, 0);
nDrawText(mRenderer, buf, 0, end - start, x, y,
- paint.mBidiFlags, paint.mNativePaint);
+ paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
TemporaryBuffer.recycle(buf);
}
} finally {
@@ -1167,21 +1168,22 @@
int modifiers = setupModifiers(paint);
try {
- nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
+ nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint,
+ paint.mNativeTypeface);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
}
private static native void nDrawText(long renderer, String text, int start, int end,
- float x, float y, int bidiFlags, long paint);
+ float x, float y, int bidiFlags, long paint, long typeface);
@Override
public void drawText(String text, float x, float y, Paint paint) {
int modifiers = setupModifiers(paint);
try {
nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
- paint.mNativePaint);
+ paint.mNativePaint, paint.mNativeTypeface);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
@@ -1235,14 +1237,14 @@
int modifiers = setupModifiers(paint);
try {
nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
- paint.mNativePaint);
+ paint.mNativePaint, paint.mNativeTypeface);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
}
private static native void nDrawTextRun(long renderer, char[] text, int index, int count,
- int contextIndex, int contextCount, float x, float y, int dir, long nativePaint);
+ int contextIndex, int contextCount, float x, float y, int dir, long nativePaint, long nativeTypeface);
@Override
public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
@@ -1257,7 +1259,7 @@
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
- contextEnd, x, y, flags, paint.mNativePaint);
+ contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawTextRun(this, start, end,
contextStart, contextEnd, x, y, flags, paint);
@@ -1267,7 +1269,7 @@
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
- x, y, flags, paint.mNativePaint);
+ x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
TemporaryBuffer.recycle(buf);
}
} finally {
@@ -1276,7 +1278,7 @@
}
private static native void nDrawTextRun(long renderer, String text, int start, int end,
- int contextStart, int contextEnd, float x, float y, int flags, long nativePaint);
+ int contextStart, int contextEnd, float x, float y, int flags, long nativePaint, long nativeTypeface);
@Override
public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
diff --git a/core/java/android/view/InputEventConsistencyVerifier.java b/core/java/android/view/InputEventConsistencyVerifier.java
index 5dda934..c5e4c21 100644
--- a/core/java/android/view/InputEventConsistencyVerifier.java
+++ b/core/java/android/view/InputEventConsistencyVerifier.java
@@ -113,7 +113,7 @@
* @param flags Flags to the verifier, or 0 if none.
*/
public InputEventConsistencyVerifier(Object caller, int flags) {
- this(caller, flags, InputEventConsistencyVerifier.class.getSimpleName());
+ this(caller, flags, null);
}
/**
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 2d1016a..852fce5 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -2698,10 +2698,10 @@
public static int keyCodeFromString(String symbolicName) {
if (symbolicName.startsWith(LABEL_PREFIX)) {
symbolicName = symbolicName.substring(LABEL_PREFIX.length());
- }
- int keyCode = nativeKeyCodeFromString(symbolicName);
- if (keyCode > 0) {
- return keyCode;
+ int keyCode = nativeKeyCodeFromString(symbolicName);
+ if (keyCode > 0) {
+ return keyCode;
+ }
}
try {
return Integer.parseInt(symbolicName, 10);
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 0626ab96..7f2defda 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -3070,10 +3070,10 @@
public static int axisFromString(String symbolicName) {
if (symbolicName.startsWith(LABEL_PREFIX)) {
symbolicName = symbolicName.substring(LABEL_PREFIX.length());
- }
- int axis = nativeAxisFromString(symbolicName);
- if (axis >= 0) {
- return axis;
+ int axis = nativeAxisFromString(symbolicName);
+ if (axis >= 0) {
+ return axis;
+ }
}
try {
return Integer.parseInt(symbolicName, 10);
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index a675821..f14e73f 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -16,11 +16,17 @@
package android.view;
+import android.animation.TimeInterpolator;
import android.graphics.Canvas;
import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.util.SparseIntArray;
+import com.android.internal.util.VirtualRefBasePtr;
+import com.android.internal.view.animation.FallbackLUTInterpolator;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+
import java.lang.ref.WeakReference;
/**
@@ -65,38 +71,68 @@
put(ViewPropertyAnimator.ALPHA, ALPHA);
}};
- // Keep in sync DeltaValueType in Animator.h
- public static final int DELTA_TYPE_ABSOLUTE = 0;
- public static final int DELTA_TYPE_DELTA = 1;
+ private VirtualRefBasePtr mNativePtr;
private RenderNode mTarget;
- private long mNativePtr;
+ private TimeInterpolator mInterpolator;
+ private boolean mStarted = false;
public int mapViewPropertyToRenderProperty(int viewProperty) {
return sViewPropertyAnimatorMap.get(viewProperty);
}
- public RenderNodeAnimator(int property, int deltaType, float deltaValue) {
- mNativePtr = nCreateAnimator(new WeakReference<RenderNodeAnimator>(this),
- property, deltaType, deltaValue);
+ public RenderNodeAnimator(int property, float finalValue) {
+ init(nCreateAnimator(new WeakReference<RenderNodeAnimator>(this),
+ property, finalValue));
}
- public RenderNodeAnimator(CanvasProperty<Float> property, int deltaType, float deltaValue) {
- mNativePtr = nCreateCanvasPropertyFloatAnimator(
+ public RenderNodeAnimator(CanvasProperty<Float> property, float finalValue) {
+ init(nCreateCanvasPropertyFloatAnimator(
new WeakReference<RenderNodeAnimator>(this),
- property.getNativeContainer(), deltaType, deltaValue);
+ property.getNativeContainer(), finalValue));
}
- public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField,
- int deltaType, float deltaValue) {
- mNativePtr = nCreateCanvasPropertyPaintAnimator(
+ public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, float finalValue) {
+ init(nCreateCanvasPropertyPaintAnimator(
new WeakReference<RenderNodeAnimator>(this),
- property.getNativeContainer(), paintField, deltaType, deltaValue);
+ property.getNativeContainer(), paintField, finalValue));
+ }
+
+ private void init(long ptr) {
+ mNativePtr = new VirtualRefBasePtr(ptr);
+ }
+
+ private void checkMutable() {
+ if (mStarted) {
+ throw new IllegalStateException("Animator has already started, cannot change it now!");
+ }
+ }
+
+ private void applyInterpolator() {
+ if (mInterpolator == null) return;
+
+ long ni;
+ if (mInterpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class)) {
+ ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator();
+ } else {
+ int duration = nGetDuration(mNativePtr.get());
+ ni = FallbackLUTInterpolator.createNativeInterpolator(mInterpolator, duration);
+ }
+ nSetInterpolator(mNativePtr.get(), ni);
+ }
+
+ private void start(RenderNode node) {
+ if (mStarted) {
+ throw new IllegalStateException("Already started!");
+ }
+ mStarted = true;
+ applyInterpolator();
+ mTarget = node;
+ mTarget.addAnimator(this);
}
public void start(View target) {
- mTarget = target.mRenderNode;
- mTarget.addAnimator(this);
+ start(target.mRenderNode);
// Kick off a frame to start the process
target.invalidateViewProperty(true, false);
}
@@ -106,8 +142,7 @@
throw new IllegalArgumentException("Not a GLES20RecordingCanvas");
}
GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas;
- mTarget = recordingCanvas.mNode;
- mTarget.addAnimator(this);
+ start(recordingCanvas.mNode);
}
public void cancel() {
@@ -115,11 +150,17 @@
}
public void setDuration(int duration) {
- nSetDuration(mNativePtr, duration);
+ checkMutable();
+ nSetDuration(mNativePtr.get(), duration);
+ }
+
+ public void setInterpolator(TimeInterpolator interpolator) {
+ checkMutable();
+ mInterpolator = interpolator;
}
long getNativeAnimator() {
- return mNativePtr;
+ return mNativePtr.get();
}
private void onFinished() {
@@ -134,22 +175,13 @@
}
}
- @Override
- protected void finalize() throws Throwable {
- try {
- nUnref(mNativePtr);
- mNativePtr = 0;
- } finally {
- super.finalize();
- }
- }
-
private static native long nCreateAnimator(WeakReference<RenderNodeAnimator> weakThis,
- int property, int deltaValueType, float deltaValue);
+ int property, float deltaValue);
private static native long nCreateCanvasPropertyFloatAnimator(WeakReference<RenderNodeAnimator> weakThis,
- long canvasProperty, int deltaValueType, float deltaValue);
+ long canvasProperty, float deltaValue);
private static native long nCreateCanvasPropertyPaintAnimator(WeakReference<RenderNodeAnimator> weakThis,
- long canvasProperty, int paintField, int deltaValueType, float deltaValue);
+ long canvasProperty, int paintField, float deltaValue);
private static native void nSetDuration(long nativePtr, int duration);
- private static native void nUnref(long nativePtr);
+ private static native int nGetDuration(long nativePtr);
+ private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 2587ba1..17035b1 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -19,7 +19,12 @@
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.Trace;
+import android.util.Log;
+import android.util.TimeUtils;
import android.view.Surface.OutOfResourcesException;
import android.view.View.AttachInfo;
@@ -51,8 +56,6 @@
private static final Rect NULL_RECT = new Rect();
- private static final long NANOS_PER_MS = 1000000;
-
// Keep in sync with DrawFrameTask.h SYNC_* flags
// Nothing interesting to report
private static final int SYNC_OK = 0x0;
@@ -66,6 +69,8 @@
private Choreographer mChoreographer;
ThreadedRenderer(boolean translucent) {
+ AtlasInitializer.sInstance.init();
+
long rootNodePtr = nCreateRootRenderNode();
mRootNode = RenderNode.adopt(rootNodePtr);
mRootNode.setClipToBounds(false);
@@ -203,7 +208,7 @@
void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
attachInfo.mIgnoreDirtyState = true;
long frameTimeNanos = mChoreographer.getFrameTimeNanos();
- attachInfo.mDrawingTime = frameTimeNanos / NANOS_PER_MS;
+ attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;
updateRootDisplayList(view, callbacks);
@@ -293,8 +298,43 @@
}
}
- /** @hide */
- public static native void postToRenderThread(Runnable runnable);
+ private static class AtlasInitializer {
+ static AtlasInitializer sInstance = new AtlasInitializer();
+
+ private boolean mInitialized = false;
+
+ private AtlasInitializer() {}
+
+ synchronized void init() {
+ if (mInitialized) return;
+ IBinder binder = ServiceManager.getService("assetatlas");
+ if (binder == null) return;
+
+ IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
+ try {
+ if (atlas.isCompatible(android.os.Process.myPpid())) {
+ GraphicBuffer buffer = atlas.getBuffer();
+ if (buffer != null) {
+ long[] map = atlas.getMap();
+ if (map != null) {
+ nSetAtlas(buffer, map);
+ mInitialized = true;
+ }
+ // If IAssetAtlas is not the same class as the IBinder
+ // we are using a remote service and we can safely
+ // destroy the graphic buffer
+ if (atlas.getClass() != binder.getClass()) {
+ buffer.destroy();
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Could not acquire atlas", e);
+ }
+ }
+ }
+
+ private static native void nSetAtlas(GraphicBuffer buffer, long[] map);
private static native long nCreateRootRenderNode();
private static native long nCreateProxy(boolean translucent, long rootRenderNode);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index bef96b1..ab518d9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -670,7 +670,7 @@
* @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack
* @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack
* @attr ref android.R.styleable#View_stateListAnimator
- * @attr ref android.R.styleable#View_sharedElementName
+ * @attr ref android.R.styleable#View_viewName
* @attr ref android.R.styleable#View_soundEffectsEnabled
* @attr ref android.R.styleable#View_tag
* @attr ref android.R.styleable#View_textAlignment
@@ -3185,6 +3185,8 @@
private int mBackgroundResource;
private boolean mBackgroundSizeChanged;
+ private String mViewName;
+
static class ListenerInfo {
/**
* Listener used to dispatch focus change events.
@@ -3997,8 +3999,8 @@
case R.styleable.View_accessibilityLiveRegion:
setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT));
break;
- case R.styleable.View_sharedElementName:
- setSharedElementName(a.getString(attr));
+ case R.styleable.View_viewName:
+ setViewName(a.getString(attr));
break;
case R.styleable.View_nestedScrollingEnabled:
setNestedScrollingEnabled(a.getBoolean(attr, false));
@@ -7145,6 +7147,9 @@
if (viewRootImpl != null) {
viewRootImpl.setAccessibilityFocus(this, null);
}
+ Rect rect = (mAttachInfo != null) ? mAttachInfo.mTmpInvalRect : new Rect();
+ getDrawingRect(rect);
+ requestRectangleOnScreen(rect, false);
invalidate();
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
return true;
@@ -18839,15 +18844,15 @@
}
/**
- * Adds all Views that have {@link #getSharedElementName()} non-null to sharedElements.
- * @param sharedElements Will contain all Views in the hierarchy having a shared element name.
+ * Adds all Views that have {@link #getViewName()} non-null to namedElements.
+ * @param namedElements Will contain all Views in the hierarchy having a view name.
* @hide
*/
- public void findSharedElements(Map<String, View> sharedElements) {
+ public void findNamedViews(Map<String, View> namedElements) {
if (getVisibility() == VISIBLE) {
- String sharedElementName = getSharedElementName();
- if (sharedElementName != null) {
- sharedElements.put(sharedElementName, this);
+ String viewName = getViewName();
+ if (viewName != null) {
+ namedElements.put(viewName, this);
}
}
}
@@ -19247,32 +19252,26 @@
}
/**
- * Specifies that the shared name of the View to be shared with another Activity.
- * When transitioning between Activities, the name links a UI element in the starting
- * Activity to UI element in the called Activity. Names should be unique in the
- * View hierarchy.
+ * Sets the name of the View to be used to identify Views in Transitions.
+ * Names should be unique in the View hierarchy.
*
- * @param sharedElementName The cross-Activity View identifier. The called Activity will use
- * the name to match the location with a View in its layout.
- * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.os.Bundle)
+ * @param viewName The name of the View to uniquely identify it for Transitions.
*/
- public void setSharedElementName(String sharedElementName) {
- setTagInternal(com.android.internal.R.id.shared_element_name, sharedElementName);
+ public final void setViewName(String viewName) {
+ mViewName = viewName;
}
/**
- * Returns the shared name of the View to be shared with another Activity.
- * When transitioning between Activities, the name links a UI element in the starting
- * Activity to UI element in the called Activity. Names should be unique in the
- * View hierarchy.
+ * Returns the name of the View to be used to identify Views in Transitions.
+ * Names should be unique in the View hierarchy.
*
- * <p>This returns null if the View is not a shared element or the name if it is.</p>
+ * <p>This returns null if the View has not been given a name.</p>
*
- * @return The name used for this View for cross-Activity transitions or null if
- * this View has not been identified as shared.
+ * @return The name used of the View to be used to identify Views in Transitions or null
+ * if no name has been given.
*/
- public String getSharedElementName() {
- return (String) getTag(com.android.internal.R.id.shared_element_name);
+ public String getViewName() {
+ return mViewName;
}
/**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4309366..b821a3e 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2301,13 +2301,13 @@
* individually during the transition.
* @return True if the ViewGroup should be acted on together during an Activity transition.
* The default value is false when the background is null and true when the background
- * is not null or if {@link #getSharedElementName()} is not null.
+ * is not null or if {@link #getViewName()} is not null.
*/
public boolean isTransitionGroup() {
if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
} else {
- return getBackground() != null || getSharedElementName() != null;
+ return getBackground() != null || getViewName() != null;
}
}
@@ -2318,8 +2318,8 @@
* in Activity transitions. If false, the ViewGroup won't transition,
* only its children. If true, the entire ViewGroup will transition
* together.
- * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
- * android.app.ActivityOptions.ActivityTransitionListener)
+ * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.app.Activity,
+ * android.util.Pair[])
*/
public void setTransitionGroup(boolean isTransitionGroup) {
mGroupFlags |= FLAG_IS_TRANSITION_GROUP_SET;
@@ -5956,15 +5956,15 @@
/** @hide */
@Override
- public void findSharedElements(Map<String, View> sharedElements) {
+ public void findNamedViews(Map<String, View> namedElements) {
if (getVisibility() != VISIBLE) {
return;
}
- super.findSharedElements(sharedElements);
+ super.findNamedViews(namedElements);
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
- child.findSharedElements(sharedElements);
+ child.findNamedViews(namedElements);
}
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 375f5e3..4acc608 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1527,4 +1527,44 @@
* until the called Activity's exiting transition completes.
*/
public boolean getAllowExitTransitionOverlap() { return true; }
+
+ /**
+ * @return the color of the status bar.
+ */
+ public abstract int getStatusBarColor();
+
+ /**
+ * Sets the color of the status bar to {@param color}.
+ *
+ * For this to take effect,
+ * the window must be drawing the system bar backgrounds with
+ * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} and
+ * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS} must not be set.
+ *
+ * If {@param color} is not opaque, consider setting
+ * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
+ * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
+ */
+ public abstract void setStatusBarColor(int color);
+
+ /**
+ * @return the color of the navigation bar.
+ */
+ public abstract int getNavigationBarColor();
+
+ /**
+ * Sets the color of the navigation bar to {@param color}.
+ *
+ * For this to take effect,
+ * the window must be drawing the system bar backgrounds with
+ * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} and
+ * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION} must not be set.
+ *
+ * If {@param color} is not opaque, consider setting
+ * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
+ * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
+ */
+ public abstract void setNavigationBarColor(int color);
+
+
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 032a82f..031ad80 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -915,6 +915,14 @@
public static final int FLAG_NEEDS_MENU_KEY = 0x40000000;
/**
+ * Flag indicating that this Window is responsible for drawing the background for the
+ * system bars. If set, the system bars are drawn with a transparent background and the
+ * corresponding areas in this window are filled with the colors specified in
+ * {@link Window#getStatusBarColor()} and {@link Window#getNavigationBarColor()}.
+ */
+ public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000;
+
+ /**
* Various behavioral options/flags. Default is none.
*
* @see #FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
@@ -941,6 +949,7 @@
* @see #FLAG_SPLIT_TOUCH
* @see #FLAG_HARDWARE_ACCELERATED
* @see #FLAG_LOCAL_FOCUS_MODE
+ * @see #FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
*/
@ViewDebug.ExportedProperty(flagMapping = {
@ViewDebug.FlagToString(mask = FLAG_ALLOW_LOCK_WHILE_SCREEN_ON, equals = FLAG_ALLOW_LOCK_WHILE_SCREEN_ON,
@@ -998,7 +1007,9 @@
@ViewDebug.FlagToString(mask = FLAG_TRANSLUCENT_STATUS, equals = FLAG_TRANSLUCENT_STATUS,
name = "FLAG_TRANSLUCENT_STATUS"),
@ViewDebug.FlagToString(mask = FLAG_TRANSLUCENT_NAVIGATION, equals = FLAG_TRANSLUCENT_NAVIGATION,
- name = "FLAG_TRANSLUCENT_NAVIGATION")
+ name = "FLAG_TRANSLUCENT_NAVIGATION"),
+ @ViewDebug.FlagToString(mask = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, equals = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ name = "FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS")
})
public int flags;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 9d10930..34967df 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -17,15 +17,19 @@
package android.view.accessibility;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.Nullable;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.InputType;
+import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.LongArray;
import android.util.Pools.SynchronizedPool;
import android.view.View;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -112,7 +116,7 @@
public static final int ACTION_SELECT = 0x00000004;
/**
- * Action that unselects the node.
+ * Action that deselects the node.
*/
public static final int ACTION_CLEAR_SELECTION = 0x00000008;
@@ -307,6 +311,18 @@
*/
public static final int ACTION_SET_TEXT = 0x00200000;
+ private static final int LAST_LEGACY_STANDARD_ACTION = ACTION_SET_TEXT;
+
+ /**
+ * Mask to see if the value is larger than the largest ACTION_ constant
+ */
+ private static final int ACTION_TYPE_MASK = 0xFF000000;
+
+ /**
+ * Mask to define standard not legacy actions.
+ */
+ private static final int STANDARD_NON_LEGACY_ACTION_MASK = 0x01000000;
+
// Action arguments
/**
@@ -548,7 +564,7 @@
private String mViewIdResourceName;
private LongArray mChildNodeIds;
- private int mActions;
+ private ArrayList<AccessibilityAction> mActions;
private int mMovementGranularities;
@@ -875,6 +891,17 @@
/**
* Gets the actions that can be performed on the node.
+ */
+ public List<AccessibilityAction> getActionList() {
+ if (mActions == null) {
+ return Collections.emptyList();
+ }
+
+ return mActions;
+ }
+
+ /**
+ * Gets the actions that can be performed on the node.
*
* @return The bit mask of with actions.
*
@@ -892,9 +919,61 @@
* @see AccessibilityNodeInfo#ACTION_PREVIOUS_HTML_ELEMENT
* @see AccessibilityNodeInfo#ACTION_SCROLL_FORWARD
* @see AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD
+ *
+ * @deprecated Use {@link #getActionList()}.
*/
+ @Deprecated
public int getActions() {
- return mActions;
+ int returnValue = 0;
+
+ if (mActions == null) {
+ return returnValue;
+ }
+
+ final int actionSize = mActions.size();
+ for (int i = 0; i < actionSize; i++) {
+ int actionId = mActions.get(i).getId();
+ if (actionId <= LAST_LEGACY_STANDARD_ACTION) {
+ returnValue |= actionId;
+ }
+ }
+
+ return returnValue;
+ }
+
+ /**
+ * Adds an action that can be performed on the node.
+ * <p>
+ * To add a standard action use the static constants on {@link AccessibilityAction}.
+ * To add a custom action create a new {@link AccessibilityAction} by passing in a
+ * resource id from your application as the action id and an optional label that
+ * describes the action. To override one of the standard actions use as the action
+ * id of a standard action id such as {@link #ACTION_CLICK} and an optional label that
+ * describes the action.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param action The action.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void addAction(AccessibilityAction action) {
+ enforceNotSealed();
+
+ if (action == null) {
+ return;
+ }
+
+ if (mActions == null) {
+ mActions = new ArrayList<AccessibilityAction>();
+ }
+
+ mActions.remove(action);
+ mActions.add(action);
}
/**
@@ -908,10 +987,21 @@
* @param action The action.
*
* @throws IllegalStateException If called from an AccessibilityService.
+ * @throws IllegalArgumentException If the argument is not one of the standard actions.
+ *
+ * @deprecated This has been deprecated for {@link #addAction(AccessibilityAction)}
*/
+ @Deprecated
public void addAction(int action) {
enforceNotSealed();
- mActions |= action;
+
+ AccessibilityAction newAction = getActionSingleton(action);
+ if (newAction == null) {
+ // This means it is not one of the standard actions
+ throw new IllegalArgumentException("Argument is not one of the standard actions");
+ }
+
+ addAction(newAction);
}
/**
@@ -923,13 +1013,40 @@
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
*
- * @param action The action.
+ * @param action The action to be removed.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ * @deprecated Use {@link #removeAction(AccessibilityAction)}
+ */
+ @Deprecated
+ public void removeAction(int action) {
+ enforceNotSealed();
+
+ removeAction(getActionSingleton(action));
+ }
+
+ /**
+ * Removes an action that can be performed on the node. If the action was
+ * not already added to the node, calling this method has no effect.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param action The action to be removed.
+ * @return The action removed from the list of actions.
*
* @throws IllegalStateException If called from an AccessibilityService.
*/
- public void removeAction(int action) {
+ public boolean removeAction(AccessibilityAction action) {
enforceNotSealed();
- mActions &= ~action;
+
+ if (mActions == null || action == null) {
+ return false;
+ }
+
+ return mActions.remove(action);
}
/**
@@ -2307,7 +2424,29 @@
parcel.writeInt(mBoundsInScreen.left);
parcel.writeInt(mBoundsInScreen.right);
- parcel.writeInt(mActions);
+ if (mActions != null && !mActions.isEmpty()) {
+ final int actionCount = mActions.size();
+ parcel.writeInt(actionCount);
+
+ int defaultLegacyStandardActions = 0;
+ for (int i = 0; i < actionCount; i++) {
+ AccessibilityAction action = mActions.get(i);
+ if (isDefaultLegacyStandardAction(action)) {
+ defaultLegacyStandardActions |= action.getId();
+ }
+ }
+ parcel.writeInt(defaultLegacyStandardActions);
+
+ for (int i = 0; i < actionCount; i++) {
+ AccessibilityAction action = mActions.get(i);
+ if (!isDefaultLegacyStandardAction(action)) {
+ parcel.writeInt(action.getId());
+ parcel.writeCharSequence(action.getLabel());
+ }
+ }
+ } else {
+ parcel.writeInt(0);
+ }
parcel.writeInt(mMovementGranularities);
@@ -2388,7 +2527,17 @@
mText = other.mText;
mContentDescription = other.mContentDescription;
mViewIdResourceName = other.mViewIdResourceName;
- mActions= other.mActions;
+
+ final ArrayList<AccessibilityAction> otherActions = other.mActions;
+ if (otherActions != null && otherActions.size() > 0) {
+ if (mActions == null) {
+ mActions = new ArrayList(otherActions);
+ } else {
+ mActions.clear();
+ mActions.addAll(other.mActions);
+ }
+ }
+
mBooleanProperties = other.mBooleanProperties;
mMovementGranularities = other.mMovementGranularities;
@@ -2452,7 +2601,17 @@
mBoundsInScreen.left = parcel.readInt();
mBoundsInScreen.right = parcel.readInt();
- mActions = parcel.readInt();
+ final int actionCount = parcel.readInt();
+ if (actionCount > 0) {
+ final int legacyStandardActions = parcel.readInt();
+ addLegacyStandardActions(legacyStandardActions);
+ final int nonLegacyActionCount = actionCount - Integer.bitCount(legacyStandardActions);
+ for (int i = 0; i < nonLegacyActionCount; i++) {
+ AccessibilityAction action = new AccessibilityAction(
+ parcel.readInt(), parcel.readCharSequence());
+ addAction(action);
+ }
+ }
mMovementGranularities = parcel.readInt();
@@ -2524,7 +2683,9 @@
mText = null;
mContentDescription = null;
mViewIdResourceName = null;
- mActions = 0;
+ if (mActions != null) {
+ mActions.clear();
+ }
mTextSelectionStart = UNDEFINED_SELECTION_INDEX;
mTextSelectionEnd = UNDEFINED_SELECTION_INDEX;
mInputType = InputType.TYPE_NULL;
@@ -2546,6 +2707,33 @@
}
}
+ private static boolean isDefaultLegacyStandardAction(AccessibilityAction action) {
+ return (action.getId() <= LAST_LEGACY_STANDARD_ACTION
+ && TextUtils.isEmpty(action.getLabel()));
+ }
+
+ private static AccessibilityAction getActionSingleton(int actionId) {
+ final int actions = AccessibilityAction.sStandardActions.size();
+ for (int i = 0; i < actions; i++) {
+ AccessibilityAction currentAction = AccessibilityAction.sStandardActions.valueAt(i);
+ if (actionId == currentAction.getId()) {
+ return currentAction;
+ }
+ }
+
+ return null;
+ }
+
+ private void addLegacyStandardActions(int actionMask) {
+ int remainingIds = actionMask;
+ while (remainingIds > 0) {
+ final int id = 1 << Integer.numberOfTrailingZeros(remainingIds);
+ remainingIds &= ~id;
+ AccessibilityAction action = getActionSingleton(id);
+ addAction(action);
+ }
+ }
+
/**
* Gets the human readable action symbolic name.
*
@@ -2709,23 +2897,432 @@
builder.append("; longClickable: ").append(isLongClickable());
builder.append("; enabled: ").append(isEnabled());
builder.append("; password: ").append(isPassword());
- builder.append("; scrollable: " + isScrollable());
-
- builder.append("; [");
- for (int actionBits = mActions; actionBits != 0;) {
- final int action = 1 << Integer.numberOfTrailingZeros(actionBits);
- actionBits &= ~action;
- builder.append(getActionSymbolicName(action));
- if (actionBits != 0) {
- builder.append(", ");
- }
- }
- builder.append("]");
+ builder.append("; scrollable: ").append(isScrollable());
+ builder.append("; actions: ").append(mActions);
return builder.toString();
}
/**
+ * A class defining an action that can be performed on an {@link AccessibilityNodeInfo}.
+ * Each action has a unique id that is mandatory and optional data.
+ * <p>
+ * There are three categories of actions:
+ * <ul>
+ * <li><strong>Standard actions</strong> - These are actions that are reported and
+ * handled by the standard UI widgets in the platform. For each standard action
+ * there is a static constant defined in this class, e.g. {@link #ACTION_FOCUS}.
+ * </li>
+ * <li><strong>Custom actions action</strong> - These are actions that are reported
+ * and handled by custom widgets. i.e. ones that are not part of the UI toolkit. For
+ * example, an application may define a custom action for clearing the user history.
+ * </li>
+ * <li><strong>Overriden standard actions</strong> - These are actions that override
+ * standard actions to customize them. For example, an app may add a label to the
+ * standard click action to announce that this action clears browsing history.
+ * </ul>
+ * </p>
+ */
+ public static final class AccessibilityAction {
+
+ /**
+ * Action that gives input focus to the node.
+ */
+ public static final AccessibilityAction ACTION_FOCUS =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_FOCUS, null);
+
+ /**
+ * Action that clears input focus of the node.
+ */
+ public static final AccessibilityAction ACTION_CLEAR_FOCUS =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLEAR_FOCUS, null);
+
+ /**
+ * Action that selects the node.
+ */
+ public static final AccessibilityAction ACTION_SELECT =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_SELECT, null);
+
+ /**
+ * Action that deselects the node.
+ */
+ public static final AccessibilityAction ACTION_CLEAR_SELECTION =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLEAR_SELECTION, null);
+
+ /**
+ * Action that clicks on the node info.
+ */
+ public static final AccessibilityAction ACTION_CLICK =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLICK, null);
+
+ /**
+ * Action that long clicks on the node.
+ */
+ public static final AccessibilityAction ACTION_LONG_CLICK =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_LONG_CLICK, null);
+
+ /**
+ * Action that gives accessibility focus to the node.
+ */
+ public static final AccessibilityAction ACTION_ACCESSIBILITY_FOCUS =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
+
+ /**
+ * Action that clears accessibility focus of the node.
+ */
+ public static final AccessibilityAction ACTION_CLEAR_ACCESSIBILITY_FOCUS =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
+
+ /**
+ * Action that requests to go to the next entity in this node's text
+ * at a given movement granularity. For example, move to the next character,
+ * word, etc.
+ * <p>
+ * <strong>Arguments:</strong>
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT},
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
+ * <strong>Example:</strong> Move to the previous character and do not extend selection.
+ * <code><pre><p>
+ * Bundle arguments = new Bundle();
+ * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+ * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
+ * false);
+ * info.performAction(AccessibilityAction.ACTION_NEXT_AT_MOVEMENT_GRANULARITY.getId(),
+ * arguments);
+ * </code></pre></p>
+ * </p>
+ *
+ * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
+ * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
+ *
+ * @see AccessibilityNodeInfo#setMovementGranularities(int)
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
+ * @see AccessibilityNodeInfo#getMovementGranularities()
+ * AccessibilityNodeInfo.getMovementGranularities()
+ *
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE
+ */
+ public static final AccessibilityAction ACTION_NEXT_AT_MOVEMENT_GRANULARITY =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, null);
+
+ /**
+ * Action that requests to go to the previous entity in this node's text
+ * at a given movement granularity. For example, move to the next character,
+ * word, etc.
+ * <p>
+ * <strong>Arguments:</strong>
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT},
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
+ * <strong>Example:</strong> Move to the next character and do not extend selection.
+ * <code><pre><p>
+ * Bundle arguments = new Bundle();
+ * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+ * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
+ * false);
+ * info.performAction(AccessibilityAction.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY.getId(),
+ * arguments);
+ * </code></pre></p>
+ * </p>
+ *
+ * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
+ * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
+ *
+ * @see AccessibilityNodeInfo#setMovementGranularities(int)
+ * AccessibilityNodeInfo.setMovementGranularities(int)
+ * @see AccessibilityNodeInfo#getMovementGranularities()
+ * AccessibilityNodeInfo.getMovementGranularities()
+ *
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
+ * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE
+ * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE
+ */
+ public static final AccessibilityAction ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, null);
+
+ /**
+ * Action to move to the next HTML element of a given type. For example, move
+ * to the BUTTON, INPUT, TABLE, etc.
+ * <p>
+ * <strong>Arguments:</strong>
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
+ * <strong>Example:</strong>
+ * <code><pre><p>
+ * Bundle arguments = new Bundle();
+ * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
+ * info.performAction(AccessibilityAction.ACTION_NEXT_HTML_ELEMENT.getId(), arguments);
+ * </code></pre></p>
+ * </p>
+ */
+ public static final AccessibilityAction ACTION_NEXT_HTML_ELEMENT =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, null);
+
+ /**
+ * Action to move to the previous HTML element of a given type. For example, move
+ * to the BUTTON, INPUT, TABLE, etc.
+ * <p>
+ * <strong>Arguments:</strong>
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
+ * <strong>Example:</strong>
+ * <code><pre><p>
+ * Bundle arguments = new Bundle();
+ * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
+ * info.performAction(AccessibilityAction.ACTION_PREVIOUS_HTML_ELEMENT.getId(), arguments);
+ * </code></pre></p>
+ * </p>
+ */
+ public static final AccessibilityAction ACTION_PREVIOUS_HTML_ELEMENT =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, null);
+
+ /**
+ * Action to scroll the node content forward.
+ */
+ public static final AccessibilityAction ACTION_SCROLL_FORWARD =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, null);
+
+ /**
+ * Action to scroll the node content backward.
+ */
+ public static final AccessibilityAction ACTION_SCROLL_BACKWARD =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, null);
+
+ /**
+ * Action to copy the current selection to the clipboard.
+ */
+ public static final AccessibilityAction ACTION_COPY =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_COPY, null);
+
+ /**
+ * Action to paste the current clipboard content.
+ */
+ public static final AccessibilityAction ACTION_PASTE =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_PASTE, null);
+
+ /**
+ * Action to cut the current selection and place it to the clipboard.
+ */
+ public static final AccessibilityAction ACTION_CUT =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CUT, null);
+
+ /**
+ * Action to set the selection. Performing this action with no arguments
+ * clears the selection.
+ * <p>
+ * <strong>Arguments:</strong>
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT},
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT}<br>
+ * <strong>Example:</strong>
+ * <code><pre><p>
+ * Bundle arguments = new Bundle();
+ * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
+ * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
+ * info.performAction(AccessibilityAction.ACTION_SET_SELECTION.getId(), arguments);
+ * </code></pre></p>
+ * </p>
+ *
+ * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT
+ * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT
+ */
+ public static final AccessibilityAction ACTION_SET_SELECTION =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_SET_SELECTION, null);
+
+ /**
+ * Action to expand an expandable node.
+ */
+ public static final AccessibilityAction ACTION_EXPAND =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_EXPAND, null);
+
+ /**
+ * Action to collapse an expandable node.
+ */
+ public static final AccessibilityAction ACTION_COLLAPSE =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_COLLAPSE, null);
+
+ /**
+ * Action to dismiss a dismissable node.
+ */
+ public static final AccessibilityAction ACTION_DISMISS =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_DISMISS, null);
+
+ /**
+ * Action that sets the text of the node. Performing the action without argument,
+ * using <code> null</code> or empty {@link CharSequence} will clear the text. This
+ * action will also put the cursor at the end of text.
+ * <p>
+ * <strong>Arguments:</strong>
+ * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE
+ * AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
+ * <strong>Example:</strong>
+ * <code><pre><p>
+ * Bundle arguments = new Bundle();
+ * arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
+ * "android");
+ * info.performAction(AccessibilityAction.ACTION_SET_TEXT.getId(), arguments);
+ * </code></pre></p>
+ */
+ public static final AccessibilityAction ACTION_SET_TEXT =
+ new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_SET_TEXT, null);
+
+ private static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<AccessibilityAction>();
+ static {
+ sStandardActions.add(ACTION_FOCUS);
+ sStandardActions.add(ACTION_CLEAR_FOCUS);
+ sStandardActions.add(ACTION_SELECT);
+ sStandardActions.add(ACTION_CLEAR_SELECTION);
+ sStandardActions.add(ACTION_CLICK);
+ sStandardActions.add(ACTION_LONG_CLICK);
+ sStandardActions.add(ACTION_ACCESSIBILITY_FOCUS);
+ sStandardActions.add(ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+ sStandardActions.add(ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
+ sStandardActions.add(ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
+ sStandardActions.add(ACTION_NEXT_HTML_ELEMENT);
+ sStandardActions.add(ACTION_PREVIOUS_HTML_ELEMENT);
+ sStandardActions.add(ACTION_SCROLL_FORWARD);
+ sStandardActions.add(ACTION_SCROLL_BACKWARD);
+ sStandardActions.add(ACTION_COPY);
+ sStandardActions.add(ACTION_PASTE);
+ sStandardActions.add(ACTION_CUT);
+ sStandardActions.add(ACTION_SET_SELECTION);
+ sStandardActions.add(ACTION_EXPAND);
+ sStandardActions.add(ACTION_COLLAPSE);
+ sStandardActions.add(ACTION_DISMISS);
+ sStandardActions.add(ACTION_SET_TEXT);
+ }
+
+ private final int mActionId;
+ private final CharSequence mLabel;
+
+ /**
+ * Creates a new AccessibilityAction. For adding a standard action without a specific label,
+ * use the static constants.
+ *
+ * You can also override the description for one the standard actions. Below is an example
+ * how to override the standard click action by adding a custom label:
+ * <pre>
+ * AccessibilityAction action = new AccessibilityAction(
+ * AccessibilityAction.ACTION_ACTION_CLICK, getLocalizedLabel());
+ * node.addAction(action);
+ * </pre>
+ *
+ * @param actionId The id for this action. This should either be one of the
+ * standard actions or a specific action for your app. In that case it is
+ * required to use a resource identifier.
+ * @param label The label for the new AccessibilityAction.
+ */
+ public AccessibilityAction(int actionId, @Nullable CharSequence label) {
+ if ((actionId & ACTION_TYPE_MASK) == 0 && Integer.bitCount(actionId) > 1) {
+ throw new IllegalArgumentException("Invalid standard action id");
+ }
+
+ if ((actionId & STANDARD_NON_LEGACY_ACTION_MASK) != 0) {
+ throw new IllegalArgumentException("action id not a resource id");
+ }
+
+ mActionId = actionId;
+ mLabel = label;
+ }
+
+ /**
+ * Gets the id for this action.
+ *
+ * @return The action id.
+ */
+ public int getId() {
+ return mActionId;
+ }
+
+ /**
+ * Gets the label for this action. Its purpose is to describe the
+ * action to user.
+ *
+ * @return The label.
+ */
+ public CharSequence getLabel() {
+ return mLabel;
+ }
+
+ @Override
+ public int hashCode() {
+ return mActionId;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null) {
+ return false;
+ }
+
+ if (other == this) {
+ return true;
+ }
+
+ if (getClass() != other.getClass()) {
+ return false;
+ }
+
+ return mActionId == ((AccessibilityAction)other).mActionId;
+ }
+
+ @Override
+ public String toString() {
+ return "AccessibilityAction: " + getActionSymbolicName(mActionId) + " - " + mLabel;
+ }
+ }
+
+ /**
* Class with information if a node is a range. Use
* {@link RangeInfo#obtain(int, float, float, float)} to get an instance.
*/
diff --git a/core/java/android/view/animation/AccelerateDecelerateInterpolator.java b/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
index 158c56e..ed6949a 100644
--- a/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
+++ b/core/java/android/view/animation/AccelerateDecelerateInterpolator.java
@@ -19,12 +19,17 @@
import android.content.Context;
import android.util.AttributeSet;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
/**
* An interpolator where the rate of change starts and ends slowly but
* accelerates through the middle.
*
*/
-public class AccelerateDecelerateInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class AccelerateDecelerateInterpolator implements Interpolator, NativeInterpolatorFactory {
public AccelerateDecelerateInterpolator() {
}
@@ -35,4 +40,10 @@
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
+
+ /** @hide */
+ @Override
+ public long createNativeInterpolator() {
+ return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();
+ }
}
diff --git a/core/java/android/view/animation/AccelerateInterpolator.java b/core/java/android/view/animation/AccelerateInterpolator.java
index dcab743..c08f348 100644
--- a/core/java/android/view/animation/AccelerateInterpolator.java
+++ b/core/java/android/view/animation/AccelerateInterpolator.java
@@ -20,12 +20,17 @@
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
/**
* An interpolator where the rate of change starts out slowly and
* and then accelerates.
*
*/
-public class AccelerateInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class AccelerateInterpolator implements Interpolator, NativeInterpolatorFactory {
private final float mFactor;
private final double mDoubleFactor;
@@ -64,4 +69,10 @@
return (float)Math.pow(input, mDoubleFactor);
}
}
+
+ /** @hide */
+ @Override
+ public long createNativeInterpolator() {
+ return NativeInterpolatorFactoryHelper.createAccelerateInterpolator(mFactor);
+ }
}
diff --git a/core/java/android/view/animation/AnticipateInterpolator.java b/core/java/android/view/animation/AnticipateInterpolator.java
index a6f110e..83a8007 100644
--- a/core/java/android/view/animation/AnticipateInterpolator.java
+++ b/core/java/android/view/animation/AnticipateInterpolator.java
@@ -20,10 +20,15 @@
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
/**
* An interpolator where the change starts backward then flings forward.
*/
-public class AnticipateInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class AnticipateInterpolator implements Interpolator, NativeInterpolatorFactory {
private final float mTension;
public AnticipateInterpolator() {
@@ -53,4 +58,10 @@
// a(t) = t * t * ((tension + 1) * t - tension)
return t * t * ((mTension + 1) * t - mTension);
}
+
+ /** @hide */
+ @Override
+ public long createNativeInterpolator() {
+ return NativeInterpolatorFactoryHelper.createAnticipateInterpolator(mTension);
+ }
}
diff --git a/core/java/android/view/animation/AnticipateOvershootInterpolator.java b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
index 3dc9722..1a8adfd 100644
--- a/core/java/android/view/animation/AnticipateOvershootInterpolator.java
+++ b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
@@ -19,6 +19,11 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
import static com.android.internal.R.styleable.AnticipateOvershootInterpolator_extraTension;
import static com.android.internal.R.styleable.AnticipateOvershootInterpolator_tension;
import static com.android.internal.R.styleable.AnticipateOvershootInterpolator;
@@ -27,7 +32,8 @@
* An interpolator where the change starts backward then flings forward and overshoots
* the target value and finally goes back to the final value.
*/
-public class AnticipateOvershootInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class AnticipateOvershootInterpolator implements Interpolator, NativeInterpolatorFactory {
private final float mTension;
public AnticipateOvershootInterpolator() {
@@ -80,4 +86,10 @@
if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension);
else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);
}
+
+ /** @hide */
+ @Override
+ public long createNativeInterpolator() {
+ return NativeInterpolatorFactoryHelper.createAnticipateOvershootInterpolator(mTension);
+ }
}
diff --git a/core/java/android/view/animation/BounceInterpolator.java b/core/java/android/view/animation/BounceInterpolator.java
index ecf99a7..9d8ca90 100644
--- a/core/java/android/view/animation/BounceInterpolator.java
+++ b/core/java/android/view/animation/BounceInterpolator.java
@@ -19,10 +19,15 @@
import android.content.Context;
import android.util.AttributeSet;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
/**
* An interpolator where the change bounces at the end.
*/
-public class BounceInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class BounceInterpolator implements Interpolator, NativeInterpolatorFactory {
public BounceInterpolator() {
}
@@ -47,4 +52,10 @@
else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f;
else return bounce(t - 1.0435f) + 0.95f;
}
+
+ /** @hide */
+ @Override
+ public long createNativeInterpolator() {
+ return NativeInterpolatorFactoryHelper.createBounceInterpolator();
+ }
}
\ No newline at end of file
diff --git a/core/java/android/view/animation/CycleInterpolator.java b/core/java/android/view/animation/CycleInterpolator.java
index d355c23..d1ebf05 100644
--- a/core/java/android/view/animation/CycleInterpolator.java
+++ b/core/java/android/view/animation/CycleInterpolator.java
@@ -20,12 +20,17 @@
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
/**
* Repeats the animation for a specified number of cycles. The
* rate of change follows a sinusoidal pattern.
*
*/
-public class CycleInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class CycleInterpolator implements Interpolator, NativeInterpolatorFactory {
public CycleInterpolator(float cycles) {
mCycles = cycles;
}
@@ -44,4 +49,10 @@
}
private float mCycles;
+
+ /** @hide */
+ @Override
+ public long createNativeInterpolator() {
+ return NativeInterpolatorFactoryHelper.createCycleInterpolator(mCycles);
+ }
}
diff --git a/core/java/android/view/animation/DecelerateInterpolator.java b/core/java/android/view/animation/DecelerateInterpolator.java
index 20e079b..0789a0e 100644
--- a/core/java/android/view/animation/DecelerateInterpolator.java
+++ b/core/java/android/view/animation/DecelerateInterpolator.java
@@ -20,12 +20,17 @@
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
/**
* An interpolator where the rate of change starts out quickly and
* and then decelerates.
*
*/
-public class DecelerateInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class DecelerateInterpolator implements Interpolator, NativeInterpolatorFactory {
public DecelerateInterpolator() {
}
@@ -60,4 +65,10 @@
}
private float mFactor = 1.0f;
+
+ /** @hide */
+ @Override
+ public long createNativeInterpolator() {
+ return NativeInterpolatorFactoryHelper.createDecelerateInterpolator(mFactor);
+ }
}
diff --git a/core/java/android/view/animation/LinearInterpolator.java b/core/java/android/view/animation/LinearInterpolator.java
index 96a039f..552c611 100644
--- a/core/java/android/view/animation/LinearInterpolator.java
+++ b/core/java/android/view/animation/LinearInterpolator.java
@@ -19,11 +19,16 @@
import android.content.Context;
import android.util.AttributeSet;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
/**
* An interpolator where the rate of change is constant
*
*/
-public class LinearInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class LinearInterpolator implements Interpolator, NativeInterpolatorFactory {
public LinearInterpolator() {
}
@@ -34,4 +39,10 @@
public float getInterpolation(float input) {
return input;
}
+
+ /** @hide */
+ @Override
+ public long createNativeInterpolator() {
+ return NativeInterpolatorFactoryHelper.createLinearInterpolator();
+ }
}
diff --git a/core/java/android/view/animation/OvershootInterpolator.java b/core/java/android/view/animation/OvershootInterpolator.java
index 494f8ab..a2466f1 100644
--- a/core/java/android/view/animation/OvershootInterpolator.java
+++ b/core/java/android/view/animation/OvershootInterpolator.java
@@ -20,11 +20,16 @@
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
/**
* An interpolator where the change flings forward and overshoots the last value
* then comes back.
*/
-public class OvershootInterpolator implements Interpolator {
+@HasNativeInterpolator
+public class OvershootInterpolator implements Interpolator, NativeInterpolatorFactory {
private final float mTension;
public OvershootInterpolator() {
@@ -56,4 +61,10 @@
t -= 1.0f;
return t * t * ((mTension + 1) * t + mTension) + 1.0f;
}
+
+ /** @hide */
+ @Override
+ public long createNativeInterpolator() {
+ return NativeInterpolatorFactoryHelper.createOvershootInterpolator(mTension);
+ }
}
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
index 92455df..fad6747 100644
--- a/core/java/android/view/inputmethod/CursorAnchorInfo.java
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -35,8 +35,12 @@
public final class CursorAnchorInfo implements Parcelable {
private final int mSelectionStart;
private final int mSelectionEnd;
- private final int mCandidatesStart;
- private final int mCandidatesEnd;
+
+ private final int mComposingTextStart;
+ /**
+ * The text, tracked as a composing region.
+ */
+ private final String mComposingText;
/**
* Horizontal position of the insertion marker, in the local coordinates that will be
@@ -83,8 +87,8 @@
public CursorAnchorInfo(final Parcel source) {
mSelectionStart = source.readInt();
mSelectionEnd = source.readInt();
- mCandidatesStart = source.readInt();
- mCandidatesEnd = source.readInt();
+ mComposingTextStart = source.readInt();
+ mComposingText = source.readString();
mInsertionMarkerHorizontal = source.readFloat();
mInsertionMarkerTop = source.readFloat();
mInsertionMarkerBaseline = source.readFloat();
@@ -104,8 +108,8 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mSelectionStart);
dest.writeInt(mSelectionEnd);
- dest.writeInt(mCandidatesStart);
- dest.writeInt(mCandidatesEnd);
+ dest.writeInt(mComposingTextStart);
+ dest.writeString(mComposingText);
dest.writeFloat(mInsertionMarkerHorizontal);
dest.writeFloat(mInsertionMarkerTop);
dest.writeFloat(mInsertionMarkerBaseline);
@@ -119,14 +123,17 @@
@Override
public int hashCode(){
// TODO: Improve the hash function.
- final float floatHash = mSelectionStart + mSelectionEnd + mCandidatesStart + mCandidatesEnd
- + mInsertionMarkerHorizontal + mInsertionMarkerTop + mInsertionMarkerBaseline
- + mInsertionMarkerBottom;
+ final float floatHash = mInsertionMarkerHorizontal + mInsertionMarkerTop
+ + mInsertionMarkerBaseline + mInsertionMarkerBottom;
int hash = floatHash > 0 ? (int) floatHash : (int)(-floatHash);
- if (mCharacterRects != null) {
- hash += mCharacterRects.hashCode();
- }
- hash += mMatrix.hashCode();
+ hash *= 31;
+ hash += mSelectionStart + mSelectionEnd + mComposingTextStart;
+ hash *= 31;
+ hash += Objects.hashCode(mComposingText);
+ hash *= 31;
+ hash += Objects.hashCode(mCharacterRects);
+ hash *= 31;
+ hash += Objects.hashCode(mMatrix);
return hash;
}
@@ -147,8 +154,10 @@
}
if (mSelectionStart != that.mSelectionStart
|| mSelectionEnd != that.mSelectionEnd
- || mCandidatesStart != that.mCandidatesStart
- || mCandidatesEnd != that.mCandidatesEnd) {
+ || mComposingTextStart != that.mComposingTextStart) {
+ return false;
+ }
+ if (!Objects.equals(mComposingTextStart, that.mComposingTextStart)) {
return false;
}
if (!Objects.equals(mCharacterRects, that.mCharacterRects)) {
@@ -163,13 +172,14 @@
@Override
public String toString() {
return "SelectionInfo{mSelection=" + mSelectionStart + "," + mSelectionEnd
- + " mCandiadtes=" + mCandidatesStart + "," + mCandidatesEnd
+ + " mComposingTextStart=" + mComposingTextStart
+ + " mComposingText=" + Objects.toString(mComposingText)
+ " mInsertionMarkerHorizontal=" + mInsertionMarkerHorizontal
+ " mInsertionMarkerTop=" + mInsertionMarkerTop
+ " mInsertionMarkerBaseline=" + mInsertionMarkerBaseline
+ " mInsertionMarkerBottom=" + mInsertionMarkerBottom
- + " mCharacterRects=" + (mCharacterRects != null ? mCharacterRects : "null")
- + " mMatrix=" + mMatrix
+ + " mCharacterRects=" + Objects.toString(mCharacterRects)
+ + " mMatrix=" + Objects.toString(mMatrix)
+ "}";
}
@@ -190,16 +200,23 @@
private int mSelectionEnd = -1;
/**
- * Sets the text range of the composition string. Calling this can be skipped if there is
- * no composition.
+ * Sets the text range of the composing text. Calling this can be skipped if there is
+ * no composing text.
+ * @param index index where the composing text starts.
+ * @param composingText the entire composing text.
*/
- public CursorAnchorInfoBuilder setCandidateRange(final int start, final int end) {
- mCandidateStart = start;
- mCandidateEnd = end;
+ public CursorAnchorInfoBuilder setComposingText(final int index,
+ final CharSequence composingText) {
+ mComposingTextStart = index;
+ if (composingText == null) {
+ mComposingText = null;
+ } else {
+ mComposingText = composingText.toString();
+ }
return this;
}
- private int mCandidateStart = -1;
- private int mCandidateEnd = -1;
+ private int mComposingTextStart = -1;
+ private String mComposingText = null;
/**
* Sets the location of the text insertion point (zero width cursor) as a rectangle in
@@ -273,14 +290,10 @@
* is interpreted as an identity matrix.
*/
public CursorAnchorInfoBuilder setMatrix(final Matrix matrix) {
- if (matrix != null) {
- mMatrix = matrix;
- } else {
- mMatrix = Matrix.IDENTITY_MATRIX;
- }
+ mMatrix.set(matrix != null ? matrix : Matrix.IDENTITY_MATRIX);
return this;
}
- private Matrix mMatrix = Matrix.IDENTITY_MATRIX;
+ private final Matrix mMatrix = new Matrix(Matrix.IDENTITY_MATRIX);
/**
* @return {@link CursorAnchorInfo} using parameters in this
@@ -297,13 +310,13 @@
public void reset() {
mSelectionStart = -1;
mSelectionEnd = -1;
- mCandidateStart = -1;
- mCandidateEnd = -1;
+ mComposingTextStart = -1;
+ mComposingText = null;
mInsertionMarkerHorizontal = Float.NaN;
mInsertionMarkerTop = Float.NaN;
mInsertionMarkerBaseline = Float.NaN;
mInsertionMarkerBottom = Float.NaN;
- mMatrix = Matrix.IDENTITY_MATRIX;
+ mMatrix.set(Matrix.IDENTITY_MATRIX);
if (mCharacterRectBuilder != null) {
mCharacterRectBuilder.reset();
}
@@ -313,15 +326,15 @@
private CursorAnchorInfo(final CursorAnchorInfoBuilder builder) {
mSelectionStart = builder.mSelectionStart;
mSelectionEnd = builder.mSelectionEnd;
- mCandidatesStart = builder.mCandidateStart;
- mCandidatesEnd = builder.mCandidateEnd;
+ mComposingTextStart = builder.mComposingTextStart;
+ mComposingText = builder.mComposingText;
mInsertionMarkerHorizontal = builder.mInsertionMarkerHorizontal;
mInsertionMarkerTop = builder.mInsertionMarkerTop;
mInsertionMarkerBaseline = builder.mInsertionMarkerBaseline;
mInsertionMarkerBottom = builder.mInsertionMarkerBottom;
mCharacterRects = builder.mCharacterRectBuilder != null ?
builder.mCharacterRectBuilder.build() : null;
- mMatrix = builder.mMatrix;
+ mMatrix = new Matrix(builder.mMatrix);
}
/**
@@ -341,19 +354,19 @@
}
/**
- * Returns the index where the composition starts.
- * @return -1 if there is no composition.
+ * Returns the index where the composing text starts.
+ * @return -1 if there is no composing text.
*/
- public int getCandidatesStart() {
- return mCandidatesStart;
+ public int getComposingTextStart() {
+ return mComposingTextStart;
}
/**
- * Returns the index where the composition ends.
- * @return -1 if there is no composition.
+ * Returns the entire composing text.
+ * @return null if there is no composition.
*/
- public int getCandidatesEnd() {
- return mCandidatesEnd;
+ public String getComposingText() {
+ return mComposingText;
}
/**
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index e1c6f52..f874eb7 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -49,7 +49,6 @@
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewRootImpl;
-import android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -57,6 +56,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -318,11 +318,16 @@
int mCursorSelEnd;
int mCursorCandStart;
int mCursorCandEnd;
+
+ /**
+ * The instance that has previously been sent to the input method.
+ */
+ private CursorAnchorInfo mCursorAnchorInfo = null;
+
/**
* The buffer to retrieve the view location in screen coordinates in {@link #updateCursor}.
*/
private final int[] mViewTopLeft = new int[2];
- private final CursorAnchorInfoBuilder mCursorAnchorInfoBuilder = new CursorAnchorInfoBuilder();
// -----------------------------------------------------------
@@ -492,6 +497,9 @@
case SET_CURSOR_ANCHOR_MONITOR_MODE: {
synchronized (mH) {
mCursorAnchorMonitorMode = msg.arg1;
+ // Clear the cache.
+ mCursorRect.setEmpty();
+ mCursorAnchorInfo = null;
}
return;
}
@@ -1176,6 +1184,7 @@
mCursorCandStart = -1;
mCursorCandEnd = -1;
mCursorRect.setEmpty();
+ mCursorAnchorInfo = null;
servedContext = new ControlledInputConnectionWrapper(vh.getLooper(), ic, this);
} else {
servedContext = null;
@@ -1538,10 +1547,9 @@
|| mCurrentTextBoxAttribute == null || mCurMethod == null) {
return;
}
+ if (DEBUG) Log.d(TAG, "updateCursor");
mTmpCursorRect.set(left, top, right, bottom);
- if (!mCursorRect.equals(mTmpCursorRect)) {
- if (DEBUG) Log.d(TAG, "updateCursor");
-
+ if (!Objects.equals(mCursorRect, mTmpCursorRect)) {
try {
if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod);
mCursorRect.set(mTmpCursorRect);
@@ -1572,10 +1580,14 @@
|| mCurrentTextBoxAttribute == null || mCurMethod == null) {
return;
}
- if (DEBUG) Log.d(TAG, "updateCursorAnchorInfo");
-
+ if (Objects.equals(mCursorAnchorInfo, cursorAnchorInfo)) {
+ Log.w(TAG, "Ignoring redundant updateCursorAnchorInfo: info=" + cursorAnchorInfo);
+ return;
+ }
+ if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo);
try {
mCurMethod.updateCursorAnchorInfo(cursorAnchorInfo);
+ mCursorAnchorInfo = cursorAnchorInfo;
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId, e);
}
diff --git a/core/java/android/webkit/EventLogTags.logtags b/core/java/android/webkit/EventLogTags.logtags
index b0b5493..a90aebd 100644
--- a/core/java/android/webkit/EventLogTags.logtags
+++ b/core/java/android/webkit/EventLogTags.logtags
@@ -8,3 +8,4 @@
# 70103- used by the browser app itself
70150 browser_snap_center
+70151 exp_det_attempt_to_call_object_getclass (app_signature|3)
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 25bcd44..ac12357 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -50,28 +50,6 @@
private static WebViewFactoryProvider sProviderInstance;
private static final Object sProviderLock = new Object();
- public static boolean isExperimentalWebViewAvailable() {
- // TODO: Remove callers of this method then remove it.
- return false; // Hide the toggle in Developer Settings.
- }
-
- /** @hide */
- public static void setUseExperimentalWebView(boolean enable) {
- // TODO: Remove callers of this method then remove it.
- }
-
- /** @hide */
- public static boolean useExperimentalWebView() {
- // TODO: Remove callers of this method then remove it.
- return true;
- }
-
- /** @hide */
- public static boolean isUseExperimentalWebViewSet() {
- // TODO: Remove callers of this method then remove it.
- return false; // User has not modifed Developer Settings
- }
-
static WebViewFactoryProvider getProvider() {
synchronized (sProviderLock) {
// For now the main purpose of this function (and the factory abstraction) is to keep
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index f4cd5fc..f91ef1a 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -743,7 +743,7 @@
*
* @param view The view whose scroll state is being reported
*
- * @param scrollState The current scroll state. One of
+ * @param scrollState The current scroll state. One of
* {@link #SCROLL_STATE_TOUCH_SCROLL} or {@link #SCROLL_STATE_IDLE}.
*/
public void onScrollStateChanged(AbsListView view, int scrollState);
@@ -3267,7 +3267,7 @@
}
}
- private boolean startScrollIfNeeded(int y, MotionEvent vtev) {
+ private boolean startScrollIfNeeded(int x, int y, MotionEvent vtev) {
// Check if we have moved far enough that it looks more like a
// scroll than a tap
final int deltaY = y - mMotionY;
@@ -3296,27 +3296,31 @@
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
- scrollIfNeeded(y, vtev);
+ scrollIfNeeded(x, y, vtev);
return true;
}
return false;
}
- private void scrollIfNeeded(int y, MotionEvent vtev) {
+ private void scrollIfNeeded(int x, int y, MotionEvent vtev) {
int rawDeltaY = y - mMotionY;
+ int scrollOffsetCorrection = 0;
+ int scrollConsumedCorrection = 0;
+ if (mLastY == Integer.MIN_VALUE) {
+ rawDeltaY -= mMotionCorrection;
+ }
if (dispatchNestedPreScroll(0, rawDeltaY, mScrollConsumed, mScrollOffset)) {
rawDeltaY -= mScrollConsumed[1];
- mMotionCorrection -= mScrollOffset[1];
- if (mLastY != Integer.MIN_VALUE) {
- mLastY -= mScrollOffset[1] + mScrollConsumed[1];
- }
+ scrollOffsetCorrection -= mScrollOffset[1];
+ scrollConsumedCorrection -= mScrollConsumed[1];
if (vtev != null) {
vtev.offsetLocation(0, mScrollOffset[1]);
}
}
- final int deltaY = rawDeltaY - mMotionCorrection;
- int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
+ final int deltaY = rawDeltaY;
+ int incrementalDeltaY =
+ mLastY != Integer.MIN_VALUE ? y - mLastY + scrollConsumedCorrection : deltaY;
int lastYCorrection = 0;
if (mTouchMode == TOUCH_MODE_SCROLL) {
@@ -3378,46 +3382,51 @@
(motionViewRealTop - motionViewPrevTop);
if (dispatchNestedScroll(0, overscroll - incrementalDeltaY, 0, overscroll,
mScrollOffset)) {
- mMotionCorrection -= mScrollOffset[1];
lastYCorrection -= mScrollOffset[1];
if (vtev != null) {
vtev.offsetLocation(0, mScrollOffset[1]);
}
} else {
- overScrollBy(0, overscroll, 0, mScrollY, 0, 0,
- 0, mOverscrollDistance, true);
- if (Math.abs(mOverscrollDistance) == Math.abs(mScrollY)) {
- // Don't allow overfling if we're at the edge.
- if (mVelocityTracker != null) {
- mVelocityTracker.clear();
- }
+ final boolean atOverscrollEdge = overScrollBy(0, overscroll,
+ 0, mScrollY, 0, 0, 0, mOverscrollDistance, true);
+
+ if (atOverscrollEdge && mVelocityTracker != null) {
+ // Don't allow overfling if we're at the edge
+ mVelocityTracker.clear();
}
final int overscrollMode = getOverScrollMode();
if (overscrollMode == OVER_SCROLL_ALWAYS ||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
!contentFits())) {
- mDirection = 0; // Reset when entering overscroll.
- mTouchMode = TOUCH_MODE_OVERSCROLL;
- if (deltaY > 0) {
- mEdgeGlowTop.onPull((float) overscroll / getHeight());
+ if (!atOverscrollEdge) {
+ mDirection = 0; // Reset when entering overscroll.
+ mTouchMode = TOUCH_MODE_OVERSCROLL;
+ }
+ if (incrementalDeltaY > 0) {
+ mEdgeGlowTop.onPull((float) -overscroll / getHeight(),
+ (float) x / getWidth());
if (!mEdgeGlowBottom.isFinished()) {
mEdgeGlowBottom.onRelease();
}
- invalidate(mEdgeGlowTop.getBounds(false));
- } else if (deltaY < 0) {
- mEdgeGlowBottom.onPull((float) overscroll / getHeight());
+ invalidate(0, 0, getWidth(),
+ mEdgeGlowTop.getMaxHeight() + getPaddingTop());
+ } else if (incrementalDeltaY < 0) {
+ mEdgeGlowBottom.onPull((float) overscroll / getHeight(),
+ 1.f - (float) x / getWidth());
if (!mEdgeGlowTop.isFinished()) {
mEdgeGlowTop.onRelease();
}
- invalidate(mEdgeGlowBottom.getBounds(true));
+ invalidate(0, getHeight() - getPaddingBottom() -
+ mEdgeGlowBottom.getMaxHeight(), getWidth(),
+ getHeight());
}
}
}
}
- mMotionY = y;
+ mMotionY = y + scrollOffsetCorrection;
}
- mLastY = y + lastYCorrection;
+ mLastY = y + lastYCorrection + scrollOffsetCorrection;
}
} else if (mTouchMode == TOUCH_MODE_OVERSCROLL) {
if (y != mLastY) {
@@ -3445,17 +3454,22 @@
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
!contentFits())) {
if (rawDeltaY > 0) {
- mEdgeGlowTop.onPull((float) overScrollDistance / getHeight());
+ mEdgeGlowTop.onPull((float) overScrollDistance / getHeight(),
+ (float) x / getWidth());
if (!mEdgeGlowBottom.isFinished()) {
mEdgeGlowBottom.onRelease();
}
- invalidate(mEdgeGlowTop.getBounds(false));
+ invalidate(0, 0, getWidth(),
+ mEdgeGlowTop.getMaxHeight() + getPaddingTop());
} else if (rawDeltaY < 0) {
- mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight());
+ mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight(),
+ 1.f - (float) x / getWidth());
if (!mEdgeGlowTop.isFinished()) {
mEdgeGlowTop.onRelease();
}
- invalidate(mEdgeGlowBottom.getBounds(true));
+ invalidate(0, getHeight() - getPaddingBottom() -
+ mEdgeGlowBottom.getMaxHeight(), getWidth(),
+ getHeight());
}
}
}
@@ -3703,7 +3717,7 @@
case TOUCH_MODE_DONE_WAITING:
// Check if we have moved far enough that it looks more like a
// scroll than a tap. If so, we'll enter scrolling mode.
- if (startScrollIfNeeded(y, vtev)) {
+ if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, vtev)) {
break;
}
// Otherwise, check containment within list bounds. If we're
@@ -3723,7 +3737,7 @@
break;
case TOUCH_MODE_SCROLL:
case TOUCH_MODE_OVERSCROLL:
- scrollIfNeeded(y, vtev);
+ scrollIfNeeded((int) ev.getX(pointerIndex), y, vtev);
break;
}
}
@@ -4022,8 +4036,8 @@
canvas.translate(leftPadding, edgeY);
mEdgeGlowTop.setSize(width, getHeight());
if (mEdgeGlowTop.draw(canvas)) {
- mEdgeGlowTop.setPosition(leftPadding, edgeY);
- invalidate(mEdgeGlowTop.getBounds(false));
+ invalidate(0, 0, getWidth(),
+ mEdgeGlowTop.getMaxHeight() + getPaddingTop());
}
canvas.restoreToCount(restoreCount);
}
@@ -4040,9 +4054,9 @@
canvas.rotate(180, width, 0);
mEdgeGlowBottom.setSize(width, height);
if (mEdgeGlowBottom.draw(canvas)) {
- // Account for the rotation
- mEdgeGlowBottom.setPosition(edgeX + width, edgeY);
- invalidate(mEdgeGlowBottom.getBounds(true));
+ invalidate(0, getHeight() - getPaddingBottom() -
+ mEdgeGlowBottom.getMaxHeight(), getWidth(),
+ getHeight());
}
canvas.restoreToCount(restoreCount);
}
@@ -4161,7 +4175,7 @@
final int y = (int) ev.getY(pointerIndex);
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
- if (startScrollIfNeeded(y, null)) {
+ if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, null)) {
return true;
}
break;
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 225cd6d..4f2d9c6 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -19,7 +19,9 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.Insets;
import android.graphics.Rect;
+import android.graphics.Region.Op;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.AttributeSet;
@@ -32,9 +34,12 @@
import com.android.internal.R;
public abstract class AbsSeekBar extends ProgressBar {
+ private final Rect mTempRect = new Rect();
+
private Drawable mThumb;
private int mThumbOffset;
-
+ private boolean mSplitTrack;
+
/**
* On touch, this offset plus the scaled value from the position of the
* touch will form the progress value. Usually 0.
@@ -51,10 +56,10 @@
* progress.
*/
private int mKeyProgressIncrement = 1;
-
+
private static final int NO_ALPHA = 0xFF;
private float mDisabledAlpha;
-
+
private int mScaledTouchSlop;
private float mTouchDownX;
private boolean mIsDragging;
@@ -76,12 +81,16 @@
TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.SeekBar, defStyleAttr, defStyleRes);
- Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb);
- setThumb(thumb); // will guess mThumbOffset if thumb != null...
- // ...but allow layout to override this
- int thumbOffset = a.getDimensionPixelOffset(
+
+ final Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb);
+ setThumb(thumb);
+
+ // Guess thumb offset if thumb != null, but allow layout to override.
+ final int thumbOffset = a.getDimensionPixelOffset(
com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset());
setThumbOffset(thumbOffset);
+
+ mSplitTrack = a.getBoolean(com.android.internal.R.styleable.SeekBar_splitTrack, false);
a.recycle();
a = context.obtainStyledAttributes(attrs,
@@ -97,7 +106,7 @@
* <p>
* If the thumb is a valid drawable (i.e. not null), half its width will be
* used as the new thumb offset (@see #setThumbOffset(int)).
- *
+ *
* @param thumb Drawable representing the thumb
*/
public void setThumb(Drawable thumb) {
@@ -132,7 +141,7 @@
mThumb = thumb;
invalidate();
if (needUpdate) {
- updateThumbPos(getWidth(), getHeight());
+ updateThumbAndTrackPos(getWidth(), getHeight());
if (thumb != null && thumb.isStateful()) {
// Note that if the states are different this won't work.
// For now, let's consider that an app bug.
@@ -162,7 +171,7 @@
/**
* Sets the thumb offset that allows the thumb to extend out of the range of
* the track.
- *
+ *
* @param thumbOffset The offset amount in pixels.
*/
public void setThumbOffset(int thumbOffset) {
@@ -171,8 +180,27 @@
}
/**
+ * Specifies whether the track should be split by the thumb. When true,
+ * the thumb's optical bounds will be clipped out of the track drawable,
+ * then the thumb will be drawn into the resulting gap.
+ *
+ * @param splitTrack Whether the track should be split by the thumb
+ */
+ public void setSplitTrack(boolean splitTrack) {
+ mSplitTrack = splitTrack;
+ invalidate();
+ }
+
+ /**
+ * Returns whether the track should be split by the thumb.
+ */
+ public boolean getSplitTrack() {
+ return mSplitTrack;
+ }
+
+ /**
* Sets the amount of progress changed via the arrow keys.
- *
+ *
* @param increment The amount to increment or decrement when the user
* presses the arrow keys.
*/
@@ -184,14 +212,14 @@
* Returns the amount of progress changed via the arrow keys.
* <p>
* By default, this will be a value that is derived from the max progress.
- *
+ *
* @return The amount to increment or decrement when the user presses the
* arrow keys. This will be positive.
*/
public int getKeyProgressIncrement() {
return mKeyProgressIncrement;
}
-
+
@Override
public synchronized void setMax(int max) {
super.setMax(max);
@@ -217,79 +245,85 @@
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
-
- Drawable progressDrawable = getProgressDrawable();
+
+ final Drawable progressDrawable = getProgressDrawable();
if (progressDrawable != null) {
progressDrawable.setAlpha(isEnabled() ? NO_ALPHA : (int) (NO_ALPHA * mDisabledAlpha));
}
-
- if (mThumb != null && mThumb.isStateful()) {
- int[] state = getDrawableState();
- mThumb.setState(state);
+
+ final Drawable thumb = mThumb;
+ if (thumb != null && thumb.isStateful()) {
+ thumb.setState(getDrawableState());
}
}
-
+
@Override
void onProgressRefresh(float scale, boolean fromUser) {
super.onProgressRefresh(scale, fromUser);
- Drawable thumb = mThumb;
+
+ final Drawable thumb = mThumb;
if (thumb != null) {
setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);
- /*
- * Since we draw translated, the drawable's bounds that it signals
- * for invalidation won't be the actual bounds we want invalidated,
- * so just invalidate this whole view.
- */
+
+ // Since we draw translated, the drawable's bounds that it signals
+ // for invalidation won't be the actual bounds we want invalidated,
+ // so just invalidate this whole view.
invalidate();
}
}
-
-
+
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
- updateThumbPos(w, h);
+
+ updateThumbAndTrackPos(w, h);
}
- private void updateThumbPos(int w, int h) {
- Drawable d = getCurrentDrawable();
- Drawable thumb = mThumb;
- int thumbHeight = thumb == null ? 0 : thumb.getIntrinsicHeight();
+ private void updateThumbAndTrackPos(int w, int h) {
+ final Drawable track = getCurrentDrawable();
+ final Drawable thumb = mThumb;
+
// The max height does not incorporate padding, whereas the height
- // parameter does
- int trackHeight = Math.min(mMaxHeight, h - mPaddingTop - mPaddingBottom);
-
- int max = getMax();
- float scale = max > 0 ? (float) getProgress() / (float) max : 0;
-
+ // parameter does.
+ final int trackHeight = Math.min(mMaxHeight, h - mPaddingTop - mPaddingBottom);
+ final int thumbHeight = thumb == null ? 0 : thumb.getIntrinsicHeight();
+
+ // Apply offset to whichever item is taller.
+ final int trackOffset;
+ final int thumbOffset;
if (thumbHeight > trackHeight) {
- if (thumb != null) {
- setThumbPos(w, thumb, scale, 0);
- }
- int gapForCenteringTrack = (thumbHeight - trackHeight) / 2;
- if (d != null) {
- // Canvas will be translated by the padding, so 0,0 is where we start drawing
- d.setBounds(0, gapForCenteringTrack,
- w - mPaddingRight - mPaddingLeft, h - mPaddingBottom - gapForCenteringTrack
- - mPaddingTop);
- }
+ trackOffset = (thumbHeight - trackHeight) / 2;
+ thumbOffset = 0;
} else {
- if (d != null) {
- // Canvas will be translated by the padding, so 0,0 is where we start drawing
- d.setBounds(0, 0, w - mPaddingRight - mPaddingLeft, h - mPaddingBottom
- - mPaddingTop);
- }
- int gap = (trackHeight - thumbHeight) / 2;
- if (thumb != null) {
- setThumbPos(w, thumb, scale, gap);
- }
+ trackOffset = 0;
+ thumbOffset = (trackHeight - thumbHeight) / 2;
+ }
+
+ if (track != null) {
+ track.setBounds(0, trackOffset, w - mPaddingRight - mPaddingLeft,
+ h - mPaddingBottom - trackOffset - mPaddingTop);
+ }
+
+ if (thumb != null) {
+ setThumbPos(w, thumb, getScale(), thumbOffset);
}
}
+ private float getScale() {
+ final int max = getMax();
+ return max > 0 ? getProgress() / (float) max : 0;
+ }
+
/**
- * @param gap If set to {@link Integer#MIN_VALUE}, this will be ignored and
+ * Updates the thumb drawable bounds.
+ *
+ * @param w Width of the view, including padding
+ * @param thumb Drawable used for the thumb
+ * @param scale Current progress between 0 and 1
+ * @param offset Vertical offset for centering. If set to
+ * {@link Integer#MIN_VALUE}, the current offset will be used.
*/
- private void setThumbPos(int w, Drawable thumb, float scale, int gap) {
+ private void setThumbPos(int w, Drawable thumb, float scale, int offset) {
int available = w - mPaddingLeft - mPaddingRight;
final int thumbWidth = thumb.getIntrinsicWidth();
final int thumbHeight = thumb.getIntrinsicHeight();
@@ -301,13 +335,13 @@
final int thumbPos = (int) (scale * available + 0.5f);
final int top, bottom;
- if (gap == Integer.MIN_VALUE) {
+ if (offset == Integer.MIN_VALUE) {
final Rect oldBounds = thumb.getBounds();
top = oldBounds.top;
bottom = oldBounds.bottom;
} else {
- top = gap;
- bottom = gap + thumbHeight;
+ top = offset;
+ bottom = offset + thumbHeight;
}
final int left = (isLayoutRtl() && mMirrorForRtl) ? available - thumbPos : thumbPos;
@@ -342,6 +376,33 @@
protected synchronized void onDraw(Canvas canvas) {
super.onDraw(canvas);
+ drawThumb(canvas);
+ }
+
+ @Override
+ void drawTrack(Canvas canvas) {
+ final Drawable thumbDrawable = mThumb;
+ if (thumbDrawable != null && mSplitTrack) {
+ final Insets insets = thumbDrawable.getOpticalInsets();
+ final Rect tempRect = mTempRect;
+ thumbDrawable.copyBounds(tempRect);
+ tempRect.offset(mPaddingLeft - mThumbOffset, mPaddingTop);
+ tempRect.left += insets.left;
+ tempRect.right -= insets.right;
+
+ final int saveCount = canvas.save();
+ canvas.clipRect(tempRect, Op.DIFFERENCE);
+ super.drawTrack(canvas);
+ canvas.restoreToCount(saveCount);
+ } else {
+ super.drawTrack(canvas);
+ }
+ }
+
+ /**
+ * Draw the thumb.
+ */
+ void drawThumb(Canvas canvas) {
if (mThumb != null) {
canvas.save();
// Translate the padding. For the x, we need to allow the thumb to
@@ -366,17 +427,17 @@
}
dw += mPaddingLeft + mPaddingRight;
dh += mPaddingTop + mPaddingBottom;
-
+
setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
resolveSizeAndState(dh, heightMeasureSpec, 0));
}
-
+
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!mIsUserSeekable || !isEnabled()) {
return false;
}
-
+
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (isInScrollingContainer()) {
@@ -391,7 +452,7 @@
attemptClaimDrag();
}
break;
-
+
case MotionEvent.ACTION_MOVE:
if (mIsDragging) {
trackTouchEvent(event);
@@ -408,7 +469,7 @@
}
}
break;
-
+
case MotionEvent.ACTION_UP:
if (mIsDragging) {
trackTouchEvent(event);
@@ -426,7 +487,7 @@
// value has not apparently changed)
invalidate();
break;
-
+
case MotionEvent.ACTION_CANCEL:
if (mIsDragging) {
onStopTrackingTouch();
@@ -493,7 +554,7 @@
mParent.requestDisallowInterceptTouchEvent(true);
}
}
-
+
/**
* This is called when the user has started touching this widget.
*/
@@ -526,7 +587,7 @@
setProgress(progress - mKeyProgressIncrement, true);
onKeyChange();
return true;
-
+
case KeyEvent.KEYCODE_DPAD_RIGHT:
if (progress >= getMax()) break;
setProgress(progress + mKeyProgressIncrement, true);
@@ -595,17 +656,13 @@
public void onRtlPropertiesChanged(int layoutDirection) {
super.onRtlPropertiesChanged(layoutDirection);
- int max = getMax();
- float scale = max > 0 ? (float) getProgress() / (float) max : 0;
-
- Drawable thumb = mThumb;
+ final Drawable thumb = mThumb;
if (thumb != null) {
- setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);
- /*
- * Since we draw translated, the drawable's bounds that it signals
- * for invalidation won't be the actual bounds we want invalidated,
- * so just invalidate this whole view.
- */
+ setThumbPos(getWidth(), thumb, getScale(), Integer.MIN_VALUE);
+
+ // Since we draw translated, the drawable's bounds that it signals
+ // for invalidation won't be the actual bounds we want invalidated,
+ // so just invalidate this whole view.
invalidate();
}
}
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index fa37443..c4a40b4 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -16,13 +16,16 @@
package android.widget;
+import android.content.res.TypedArray;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
-import com.android.internal.R;
+import android.graphics.RectF;
import android.content.Context;
-import android.content.res.Resources;
import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
+import android.util.FloatMath;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
@@ -55,16 +58,11 @@
// Time it will take before a pulled glow begins receding in ms
private static final int PULL_TIME = 167;
- // Time it will take in ms for a pulled glow to decay to partial strength before release
- private static final int PULL_DECAY_TIME = 1000;
-
private static final float MAX_ALPHA = 1.f;
- private static final float HELD_EDGE_SCALE_Y = 0.5f;
- private static final float MAX_GLOW_HEIGHT = 4.f;
+ private static final float MAX_GLOW_SCALE = 2.f;
- private static final float PULL_GLOW_BEGIN = 1.f;
- private static final float PULL_EDGE_BEGIN = 0.6f;
+ private static final float PULL_GLOW_BEGIN = 0.f;
// Minimum velocity that will be absorbed
private static final int MIN_VELOCITY = 100;
@@ -73,24 +71,13 @@
private static final float EPSILON = 0.001f;
- private final Drawable mEdge;
- private final Drawable mGlow;
- private int mWidth;
- private int mHeight;
- private int mX;
- private int mY;
- private static final int MIN_WIDTH = 300;
- private final int mMinWidth;
+ private static final double ANGLE = Math.PI / 6;
+ private static final float SIN = (float) Math.sin(ANGLE);
+ private static final float COS = (float) Math.cos(ANGLE);
- private float mEdgeAlpha;
- private float mEdgeScaleY;
private float mGlowAlpha;
private float mGlowScaleY;
- private float mEdgeAlphaStart;
- private float mEdgeAlphaFinish;
- private float mEdgeScaleYStart;
- private float mEdgeScaleYFinish;
private float mGlowAlphaStart;
private float mGlowAlphaFinish;
private float mGlowScaleYStart;
@@ -107,16 +94,11 @@
private static final int STATE_RECEDE = 3;
private static final int STATE_PULL_DECAY = 4;
- // How much dragging should effect the height of the edge image.
- // Number determined by user testing.
- private static final int PULL_DISTANCE_EDGE_FACTOR = 7;
-
// How much dragging should effect the height of the glow image.
// Number determined by user testing.
private static final int PULL_DISTANCE_GLOW_FACTOR = 7;
private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 1.1f;
- private static final int VELOCITY_EDGE_FACTOR = 8;
private static final int VELOCITY_GLOW_FACTOR = 12;
private int mState = STATE_IDLE;
@@ -124,30 +106,27 @@
private float mPullDistance;
private final Rect mBounds = new Rect();
-
- private final int mEdgeHeight;
- private final int mGlowHeight;
- private final int mGlowWidth;
- private final int mMaxEffectHeight;
+ private final RectF mArcRect = new RectF();
+ private final Paint mPaint = new Paint();
+ private float mRadius;
+ private float mBaseGlowHeight;
+ private float mDisplacement = 0.5f;
+ private float mTargetDisplacement = 0.5f;
/**
* Construct a new EdgeEffect with a theme appropriate for the provided context.
* @param context Context used to provide theming and resource information for the EdgeEffect
*/
public EdgeEffect(Context context) {
- final Resources res = context.getResources();
- mEdge = context.getDrawable(R.drawable.overscroll_edge);
- mGlow = context.getDrawable(R.drawable.overscroll_glow);
-
- mEdgeHeight = mEdge.getIntrinsicHeight();
- mGlowHeight = mGlow.getIntrinsicHeight();
- mGlowWidth = mGlow.getIntrinsicWidth();
-
- mMaxEffectHeight = (int) (Math.min(
- mGlowHeight * MAX_GLOW_HEIGHT * mGlowHeight / mGlowWidth * 0.6f,
- mGlowHeight * MAX_GLOW_HEIGHT) + 0.5f);
-
- mMinWidth = (int) (res.getDisplayMetrics().density * MIN_WIDTH + 0.5f);
+ mPaint.setAntiAlias(true);
+ final TypedArray a = context.obtainStyledAttributes(
+ com.android.internal.R.styleable.EdgeEffect);
+ final int themeColor = a.getColor(
+ com.android.internal.R.styleable.EdgeEffect_colorPrimaryLight, 0xff666666);
+ a.recycle();
+ mPaint.setColor((themeColor & 0xffffff) | 0x33000000);
+ mPaint.setStyle(Paint.Style.FILL);
+ mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
mInterpolator = new DecelerateInterpolator();
}
@@ -158,20 +137,13 @@
* @param height Effect height in pixels
*/
public void setSize(int width, int height) {
- mWidth = width;
- mHeight = height;
- }
+ final float r = width * 0.75f / SIN;
+ final float y = COS * r;
+ final float h = r - y;
+ mRadius = r;
+ mBaseGlowHeight = h;
- /**
- * Set the position of this edge effect in pixels. This position is
- * only used by {@link #getBounds(boolean)}.
- *
- * @param x The position of the edge effect on the X axis
- * @param y The position of the edge effect on the Y axis
- */
- void setPosition(int x, int y) {
- mX = x;
- mY = y;
+ mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h));
}
/**
@@ -199,17 +171,38 @@
* The host view should always {@link android.view.View#invalidate()} after this
* and draw the results accordingly.
*
+ * <p>Views using EdgeEffect should favor {@link #onPull(float, float)} when the displacement
+ * of the pull point is known.</p>
+ *
* @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
* 1.f (full length of the view) or negative values to express change
* back toward the edge reached to initiate the effect.
*/
public void onPull(float deltaDistance) {
+ onPull(deltaDistance, 0.5f);
+ }
+
+ /**
+ * A view should call this when content is pulled away from an edge by the user.
+ * This will update the state of the current visual effect and its associated animation.
+ * The host view should always {@link android.view.View#invalidate()} after this
+ * and draw the results accordingly.
+ *
+ * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
+ * 1.f (full length of the view) or negative values to express change
+ * back toward the edge reached to initiate the effect.
+ * @param displacement The displacement from the starting side of the effect of the point
+ * initiating the pull. In the case of touch this is the finger position.
+ * Values may be from 0-1.
+ */
+ public void onPull(float deltaDistance, float displacement) {
final long now = AnimationUtils.currentAnimationTimeMillis();
+ mTargetDisplacement = displacement;
if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration) {
return;
}
if (mState != STATE_PULL) {
- mGlowScaleY = PULL_GLOW_BEGIN;
+ mGlowScaleY = Math.max(PULL_GLOW_BEGIN, mGlowScaleY);
}
mState = STATE_PULL;
@@ -217,30 +210,20 @@
mDuration = PULL_TIME;
mPullDistance += deltaDistance;
- float distance = Math.abs(mPullDistance);
- mEdgeAlpha = mEdgeAlphaStart = Math.max(PULL_EDGE_BEGIN, Math.min(distance, MAX_ALPHA));
- mEdgeScaleY = mEdgeScaleYStart = Math.max(
- HELD_EDGE_SCALE_Y, Math.min(distance * PULL_DISTANCE_EDGE_FACTOR, 1.f));
-
+ final float absdd = Math.abs(deltaDistance);
mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA,
- mGlowAlpha +
- (Math.abs(deltaDistance) * PULL_DISTANCE_ALPHA_GLOW_FACTOR));
+ mGlowAlpha + (absdd * PULL_DISTANCE_ALPHA_GLOW_FACTOR));
- float glowChange = Math.abs(deltaDistance);
- if (deltaDistance > 0 && mPullDistance < 0) {
- glowChange = -glowChange;
- }
if (mPullDistance == 0) {
- mGlowScaleY = 0;
+ mGlowScaleY = mGlowScaleYStart = 0;
+ } else {
+ final float scale = Math.max(0, 1 - 1 /
+ FloatMath.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3f) / 0.7f;
+
+ mGlowScaleY = mGlowScaleYStart = scale;
}
- // Do not allow glow to get larger than MAX_GLOW_HEIGHT.
- mGlowScaleY = mGlowScaleYStart = Math.min(MAX_GLOW_HEIGHT, Math.max(
- 0, mGlowScaleY + glowChange * PULL_DISTANCE_GLOW_FACTOR));
-
- mEdgeAlphaFinish = mEdgeAlpha;
- mEdgeScaleYFinish = mEdgeScaleY;
mGlowAlphaFinish = mGlowAlpha;
mGlowScaleYFinish = mGlowScaleY;
}
@@ -259,13 +242,9 @@
}
mState = STATE_RECEDE;
- mEdgeAlphaStart = mEdgeAlpha;
- mEdgeScaleYStart = mEdgeScaleY;
mGlowAlphaStart = mGlowAlpha;
mGlowScaleYStart = mGlowScaleY;
- mEdgeAlphaFinish = 0.f;
- mEdgeScaleYFinish = 0.f;
mGlowAlphaFinish = 0.f;
mGlowScaleYFinish = 0.f;
@@ -290,30 +269,21 @@
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mDuration = 0.15f + (velocity * 0.02f);
- // The edge should always be at least partially visible, regardless
- // of velocity.
- mEdgeAlphaStart = 0.f;
- mEdgeScaleY = mEdgeScaleYStart = 0.f;
// The glow depends more on the velocity, and therefore starts out
// nearly invisible.
mGlowAlphaStart = 0.3f;
- mGlowScaleYStart = 0.f;
+ mGlowScaleYStart = Math.max(mGlowScaleY, 0.f);
- // Factor the velocity by 8. Testing on device shows this works best to
- // reflect the strength of the user's scrolling.
- mEdgeAlphaFinish = Math.max(0, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1));
- // Edge should never get larger than the size of its asset.
- mEdgeScaleYFinish = Math.max(
- HELD_EDGE_SCALE_Y, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1.f));
// Growth for the size of the glow should be quadratic to properly
// respond
// to a user's scrolling speed. The faster the scrolling speed, the more
// intense the effect should be for both the size and the saturation.
- mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f);
+ mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f) / 2, 1.f);
// Alpha should change for the glow as well as size.
mGlowAlphaFinish = Math.max(
mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA));
+ mTargetDisplacement = 0.5f;
}
@@ -330,52 +300,40 @@
public boolean draw(Canvas canvas) {
update();
- mGlow.setAlpha((int) (Math.max(0, Math.min(mGlowAlpha, 1)) * 255));
+ final int count = canvas.save();
- int glowBottom = (int) Math.min(
- mGlowHeight * mGlowScaleY * mGlowHeight / mGlowWidth * 0.6f,
- mGlowHeight * MAX_GLOW_HEIGHT);
- if (mWidth < mMinWidth) {
- // Center the glow and clip it.
- int glowLeft = (mWidth - mMinWidth)/2;
- mGlow.setBounds(glowLeft, 0, mWidth - glowLeft, glowBottom);
- } else {
- // Stretch the glow to fit.
- mGlow.setBounds(0, 0, mWidth, glowBottom);
- }
+ final float y = mBounds.height();
+ final float centerY = y - mRadius;
+ final float centerX = mBounds.centerX();
- mGlow.draw(canvas);
+ mArcRect.set(centerX - mRadius, centerY - mRadius, centerX + mRadius, centerY + mRadius);
+ canvas.scale(1.f, Math.min(mGlowScaleY, 1.f), centerX, 0);
- mEdge.setAlpha((int) (Math.max(0, Math.min(mEdgeAlpha, 1)) * 255));
+ final float displacement = Math.max(0, Math.min(mDisplacement, 1.f)) - 0.5f;
+ float translateX = mBounds.width() * displacement / 2;
- int edgeBottom = (int) (mEdgeHeight * mEdgeScaleY);
- if (mWidth < mMinWidth) {
- // Center the edge and clip it.
- int edgeLeft = (mWidth - mMinWidth)/2;
- mEdge.setBounds(edgeLeft, 0, mWidth - edgeLeft, edgeBottom);
- } else {
- // Stretch the edge to fit.
- mEdge.setBounds(0, 0, mWidth, edgeBottom);
- }
- mEdge.draw(canvas);
+ canvas.clipRect(Float.MIN_VALUE, mBounds.top,
+ Float.MAX_VALUE, Float.MAX_VALUE);
+ canvas.translate(translateX, 0);
+ canvas.drawArc(mArcRect, 45, 90, true, mPaint);
+ canvas.restoreToCount(count);
- if (mState == STATE_RECEDE && glowBottom == 0 && edgeBottom == 0) {
+ boolean oneLastFrame = false;
+ if (mState == STATE_RECEDE && mGlowScaleY == 0) {
mState = STATE_IDLE;
+ oneLastFrame = true;
}
- return mState != STATE_IDLE;
+ return mState != STATE_IDLE || oneLastFrame;
}
/**
- * Returns the bounds of the edge effect.
- *
- * @hide
+ * Return the maximum height that the edge effect will be drawn at given the original
+ * {@link #setSize(int, int) input size}.
+ * @return The maximum height of the edge effect
*/
- public Rect getBounds(boolean reverse) {
- mBounds.set(0, 0, mWidth, mMaxEffectHeight);
- mBounds.offset(mX, mY - (reverse ? mMaxEffectHeight : 0));
-
- return mBounds;
+ public int getMaxHeight() {
+ return (int) (mBounds.height() * MAX_GLOW_SCALE + 0.5f);
}
private void update() {
@@ -384,10 +342,9 @@
final float interp = mInterpolator.getInterpolation(t);
- mEdgeAlpha = mEdgeAlphaStart + (mEdgeAlphaFinish - mEdgeAlphaStart) * interp;
- mEdgeScaleY = mEdgeScaleYStart + (mEdgeScaleYFinish - mEdgeScaleYStart) * interp;
mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp;
mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp;
+ mDisplacement = (mDisplacement + mTargetDisplacement) / 2;
if (t >= 1.f - EPSILON) {
switch (mState) {
@@ -396,42 +353,17 @@
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mDuration = RECEDE_TIME;
- mEdgeAlphaStart = mEdgeAlpha;
- mEdgeScaleYStart = mEdgeScaleY;
mGlowAlphaStart = mGlowAlpha;
mGlowScaleYStart = mGlowScaleY;
- // After absorb, the glow and edge should fade to nothing.
- mEdgeAlphaFinish = 0.f;
- mEdgeScaleYFinish = 0.f;
+ // After absorb, the glow should fade to nothing.
mGlowAlphaFinish = 0.f;
mGlowScaleYFinish = 0.f;
break;
case STATE_PULL:
- mState = STATE_PULL_DECAY;
- mStartTime = AnimationUtils.currentAnimationTimeMillis();
- mDuration = PULL_DECAY_TIME;
-
- mEdgeAlphaStart = mEdgeAlpha;
- mEdgeScaleYStart = mEdgeScaleY;
- mGlowAlphaStart = mGlowAlpha;
- mGlowScaleYStart = mGlowScaleY;
-
- // After pull, the glow and edge should fade to nothing.
- mEdgeAlphaFinish = 0.f;
- mEdgeScaleYFinish = 0.f;
- mGlowAlphaFinish = 0.f;
- mGlowScaleYFinish = 0.f;
+ // Hold in this state until explicitly released.
break;
case STATE_PULL_DECAY:
- // When receding, we want edge to decrease more slowly
- // than the glow.
- float factor = mGlowScaleYFinish != 0 ? 1
- / (mGlowScaleYFinish * mGlowScaleYFinish)
- : Float.MAX_VALUE;
- mEdgeScaleY = mEdgeScaleYStart +
- (mEdgeScaleYFinish - mEdgeScaleYStart) *
- interp * factor;
mState = STATE_RECEDE;
break;
case STATE_RECEDE:
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index b0a4e24..27d6b82 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -39,6 +39,7 @@
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
@@ -94,6 +95,8 @@
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.CursorAnchorInfo;
+import android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
@@ -215,6 +218,8 @@
private TextView mTextView;
+ final CursorAnchorInfoNotifier mCursorAnchorInfoNotifier = new CursorAnchorInfoNotifier();
+
Editor(TextView textView) {
mTextView = textView;
}
@@ -249,9 +254,13 @@
// We had an active selection from before, start the selection mode.
startSelectionActionMode();
}
+
+ getPositionListener().addSubscriber(mCursorAnchorInfoNotifier, true);
}
void onDetachedFromWindow() {
+ getPositionListener().removeSubscriber(mCursorAnchorInfoNotifier);
+
if (mError != null) {
hideError();
}
@@ -780,7 +789,7 @@
boolean parentPositionChanged, boolean parentScrolled);
}
- private boolean isPositionVisible(int positionX, int positionY) {
+ private boolean isPositionVisible(final float positionX, final float positionY) {
synchronized (TEMP_POSITION) {
final float[] position = TEMP_POSITION;
position[0] = positionX;
@@ -2134,7 +2143,8 @@
private class PositionListener implements ViewTreeObserver.OnPreDrawListener {
// 3 handles
// 3 ActionPopup [replace, suggestion, easyedit] (suggestionsPopup first hides the others)
- private final int MAXIMUM_NUMBER_OF_LISTENERS = 6;
+ // 1 CursorAnchorInfoNotifier
+ private final int MAXIMUM_NUMBER_OF_LISTENERS = 7;
private TextViewPositionListener[] mPositionListeners =
new TextViewPositionListener[MAXIMUM_NUMBER_OF_LISTENERS];
private boolean mCanMove[] = new boolean[MAXIMUM_NUMBER_OF_LISTENERS];
@@ -2997,6 +3007,122 @@
}
}
+ /**
+ * A listener to call {@link InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo)}
+ * while the input method is requesting the cursor/anchor position. Does nothing as long as
+ * {@link InputMethodManager#isWatchingCursor(View)} returns false.
+ */
+ private final class CursorAnchorInfoNotifier implements TextViewPositionListener {
+ final CursorAnchorInfoBuilder mSelectionInfoBuilder = new CursorAnchorInfoBuilder();
+ final int[] mTmpIntOffset = new int[2];
+ final Matrix mViewToScreenMatrix = new Matrix();
+
+ @Override
+ public void updatePosition(int parentPositionX, int parentPositionY,
+ boolean parentPositionChanged, boolean parentScrolled) {
+ final InputMethodState ims = mInputMethodState;
+ if (ims == null || ims.mBatchEditNesting > 0) {
+ return;
+ }
+ final InputMethodManager imm = InputMethodManager.peekInstance();
+ if (null == imm) {
+ return;
+ }
+ // Skip if the IME has not requested the cursor/anchor position.
+ if (!imm.isWatchingCursor(mTextView)) {
+ return;
+ }
+ Layout layout = mTextView.getLayout();
+ if (layout == null) {
+ return;
+ }
+
+ final CursorAnchorInfoBuilder builder = mSelectionInfoBuilder;
+ builder.reset();
+
+ final int selectionStart = mTextView.getSelectionStart();
+ builder.setSelectionRange(selectionStart, mTextView.getSelectionEnd());
+
+ // Construct transformation matrix from view local coordinates to screen coordinates.
+ mViewToScreenMatrix.set(mTextView.getMatrix());
+ mTextView.getLocationOnScreen(mTmpIntOffset);
+ mViewToScreenMatrix.postTranslate(mTmpIntOffset[0], mTmpIntOffset[1]);
+ builder.setMatrix(mViewToScreenMatrix);
+
+ final float viewportToContentHorizontalOffset =
+ mTextView.viewportToContentHorizontalOffset();
+ final float viewportToContentVerticalOffset =
+ mTextView.viewportToContentVerticalOffset();
+
+ final CharSequence text = mTextView.getText();
+ if (text instanceof Spannable) {
+ final Spannable sp = (Spannable) text;
+ int composingTextStart = EditableInputConnection.getComposingSpanStart(sp);
+ int composingTextEnd = EditableInputConnection.getComposingSpanEnd(sp);
+ if (composingTextEnd < composingTextStart) {
+ final int temp = composingTextEnd;
+ composingTextEnd = composingTextStart;
+ composingTextStart = temp;
+ }
+ final boolean hasComposingText =
+ (0 <= composingTextStart) && (composingTextStart < composingTextEnd);
+ if (hasComposingText) {
+ final CharSequence composingText = text.subSequence(composingTextStart,
+ composingTextEnd);
+ builder.setComposingText(composingTextStart, composingText);
+ }
+ for (int offset = composingTextStart; offset < composingTextEnd; offset++) {
+ if (offset < 0) {
+ continue;
+ }
+ final int line = layout.getLineForOffset(offset);
+ final float left = layout.getPrimaryHorizontal(offset)
+ + viewportToContentHorizontalOffset;
+ final float top = layout.getLineTop(line) + viewportToContentVerticalOffset;
+ // Here we are tentatively passing offset + 1 to calculate the other side of
+ // the primary horizontal to preserve as many positions as possible so that
+ // the IME can reconstruct the layout entirely. However, we should revisit this
+ // to have a clear specification about the relationship between the index of
+ // the character and its bounding box. See also the TODO comment below.
+ final float right = layout.getPrimaryHorizontal(offset + 1)
+ + viewportToContentHorizontalOffset;
+ final float bottom = layout.getLineBottom(line)
+ + viewportToContentVerticalOffset;
+ // Take TextView's padding and scroll into account.
+ if (isPositionVisible(left, top) && isPositionVisible(right, bottom)) {
+ // Here offset is the index in Java chars.
+ // TODO: We must have a well-defined specification. For example, how
+ // RTL, surrogate pairs, and composition letters are handled must be
+ // documented.
+ builder.addCharacterRect(offset, left, top, right, bottom);
+ }
+ }
+ }
+
+ // Treat selectionStart as the insertion point.
+ if (0 <= selectionStart) {
+ final int offset = selectionStart;
+ final int line = layout.getLineForOffset(offset);
+ final float insertionMarkerX = layout.getPrimaryHorizontal(offset)
+ + viewportToContentHorizontalOffset;
+ final float insertionMarkerTop = layout.getLineTop(line)
+ + viewportToContentVerticalOffset;
+ final float insertionMarkerBaseline = layout.getLineBaseline(line)
+ + viewportToContentVerticalOffset;
+ final float insertionMarkerBottom = layout.getLineBottom(line)
+ + viewportToContentVerticalOffset;
+ // Take TextView's padding and scroll into account.
+ if (isPositionVisible(insertionMarkerX, insertionMarkerTop) &&
+ isPositionVisible(insertionMarkerX, insertionMarkerBottom)) {
+ builder.setInsertionMarkerLocation(insertionMarkerX, insertionMarkerTop,
+ insertionMarkerBaseline, insertionMarkerBottom);
+ }
+ }
+
+ imm.updateCursorAnchorInfo(mTextView, builder.build());
+ }
+ }
+
private abstract class HandleView extends View implements TextViewPositionListener {
protected Drawable mDrawable;
protected Drawable mDrawableLtr;
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 25d4f42..0c65c50 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -616,12 +616,14 @@
if (canOverscroll) {
final int pulledToX = oldX + deltaX;
if (pulledToX < 0) {
- mEdgeGlowLeft.onPull((float) deltaX / getWidth());
+ mEdgeGlowLeft.onPull((float) deltaX / getWidth(),
+ 1.f - ev.getY(activePointerIndex) / getHeight());
if (!mEdgeGlowRight.isFinished()) {
mEdgeGlowRight.onRelease();
}
} else if (pulledToX > range) {
- mEdgeGlowRight.onPull((float) deltaX / getWidth());
+ mEdgeGlowRight.onPull((float) deltaX / getWidth(),
+ ev.getY(activePointerIndex) / getHeight());
if (!mEdgeGlowLeft.isFinished()) {
mEdgeGlowLeft.onRelease();
}
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index f7e81b8..0c3715d 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -1066,21 +1066,30 @@
protected synchronized void onDraw(Canvas canvas) {
super.onDraw(canvas);
- Drawable d = mCurrentDrawable;
+ drawTrack(canvas);
+ }
+
+ /**
+ * Draws the progress bar track.
+ */
+ void drawTrack(Canvas canvas) {
+ final Drawable d = mCurrentDrawable;
if (d != null) {
// Translate canvas so a indeterminate circular progress bar with padding
// rotates properly in its animation
- canvas.save();
+ final int saveCount = canvas.save();
+
if(isLayoutRtl() && mMirrorForRtl) {
canvas.translate(getWidth() - mPaddingRight, mPaddingTop);
canvas.scale(-1.0f, 1.0f);
} else {
canvas.translate(mPaddingLeft, mPaddingTop);
}
- long time = getDrawingTime();
+
+ final long time = getDrawingTime();
if (mHasAnimation) {
mAnimation.getTransformation(time, mTransformation);
- float scale = mTransformation.getAlpha();
+ final float scale = mTransformation.getAlpha();
try {
mInDrawing = true;
d.setLevel((int) (scale * MAX_LEVEL));
@@ -1089,8 +1098,10 @@
}
postInvalidateOnAnimation();
}
+
d.draw(canvas);
- canvas.restore();
+ canvas.restoreToCount(saveCount);
+
if (mShouldStartAnimationDrawable && d instanceof Animatable) {
((Animatable) d).start();
mShouldStartAnimationDrawable = false;
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 0fa75a6..fd04890 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -669,12 +669,14 @@
} else if (canOverscroll) {
final int pulledToY = oldY + deltaY;
if (pulledToY < 0) {
- mEdgeGlowTop.onPull((float) deltaY / getHeight());
+ mEdgeGlowTop.onPull((float) deltaY / getHeight(),
+ ev.getX(activePointerIndex) / getWidth());
if (!mEdgeGlowBottom.isFinished()) {
mEdgeGlowBottom.onRelease();
}
} else if (pulledToY > range) {
- mEdgeGlowBottom.onPull((float) deltaY / getHeight());
+ mEdgeGlowBottom.onPull((float) deltaY / getHeight(),
+ 1.f - ev.getX(activePointerIndex) / getWidth());
if (!mEdgeGlowTop.isFinished()) {
mEdgeGlowTop.onRelease();
}
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 08af4de..438e164 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -22,9 +22,11 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.Insets;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
+import android.graphics.Region.Op;
import android.graphics.drawable.Drawable;
import android.text.Layout;
import android.text.StaticLayout;
@@ -85,6 +87,7 @@
private int mThumbTextPadding;
private int mSwitchMinWidth;
private int mSwitchPadding;
+ private boolean mSplitTrack;
private CharSequence mTextOn;
private CharSequence mTextOff;
@@ -174,13 +177,13 @@
super(context, attrs, defStyleAttr, defStyleRes);
mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
- Resources res = getResources();
+
+ final Resources res = getResources();
mTextPaint.density = res.getDisplayMetrics().density;
mTextPaint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale);
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.Switch, defStyleAttr, defStyleRes);
-
mThumbDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_thumb);
mTrackDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_track);
mTextOn = a.getText(com.android.internal.R.styleable.Switch_textOn);
@@ -191,15 +194,16 @@
com.android.internal.R.styleable.Switch_switchMinWidth, 0);
mSwitchPadding = a.getDimensionPixelSize(
com.android.internal.R.styleable.Switch_switchPadding, 0);
+ mSplitTrack = a.getBoolean(com.android.internal.R.styleable.Switch_splitTrack, false);
- int appearance = a.getResourceId(
+ final int appearance = a.getResourceId(
com.android.internal.R.styleable.Switch_switchTextAppearance, 0);
if (appearance != 0) {
setSwitchTextAppearance(context, appearance);
}
a.recycle();
- ViewConfiguration config = ViewConfiguration.get(context);
+ final ViewConfiguration config = ViewConfiguration.get(context);
mTouchSlop = config.getScaledTouchSlop();
mMinFlingVelocity = config.getScaledMinimumFlingVelocity();
@@ -469,6 +473,29 @@
}
/**
+ * Specifies whether the track should be split by the thumb. When true,
+ * the thumb's optical bounds will be clipped out of the track drawable,
+ * then the thumb will be drawn into the resulting gap.
+ *
+ * @param splitTrack Whether the track should be split by the thumb
+ *
+ * @attr ref android.R.styleable#Switch_splitTrack
+ */
+ public void setSplitTrack(boolean splitTrack) {
+ mSplitTrack = splitTrack;
+ invalidate();
+ }
+
+ /**
+ * Returns whether the track should be split by the thumb.
+ *
+ * @attr ref android.R.styleable#Switch_splitTrack
+ */
+ public boolean getSplitTrack() {
+ return mSplitTrack;
+ }
+
+ /**
* Returns the text displayed when the button is in the checked state.
*
* @attr ref android.R.styleable#Switch_textOn
@@ -518,13 +545,15 @@
mTrackDrawable.getPadding(mTempRect);
- final int maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth());
+ final int maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth())
+ + mThumbTextPadding * 2;
+ mThumbWidth = Math.max(maxTextWidth, mThumbDrawable.getIntrinsicWidth());
+
final int switchWidth = Math.max(mSwitchMinWidth,
- maxTextWidth * 2 + mThumbTextPadding * 4 + mTempRect.left + mTempRect.right);
+ 2 * mThumbWidth + mTempRect.left + mTempRect.right);
final int switchHeight = Math.max(mTrackDrawable.getIntrinsicHeight(),
mThumbDrawable.getIntrinsicHeight());
- mThumbWidth = maxTextWidth + mThumbTextPadding * 2;
mSwitchWidth = switchWidth;
mSwitchHeight = switchHeight;
@@ -777,7 +806,7 @@
final Drawable trackDrawable = mTrackDrawable;
final Drawable thumbDrawable = mThumbDrawable;
- // Draw the switch
+ // Layout the track.
final int switchLeft = mSwitchLeft;
final int switchTop = mSwitchTop;
final int switchRight = mSwitchRight;
@@ -793,9 +822,10 @@
// Relies on mTempRect, MUST be called first!
final int thumbPos = getThumbOffset();
+ // Layout the thumb.
thumbDrawable.getPadding(tempRect);
- int thumbLeft = switchInnerLeft - tempRect.left + thumbPos;
- int thumbRight = switchInnerLeft + thumbPos + mThumbWidth + tempRect.right;
+ final int thumbLeft = switchInnerLeft - tempRect.left + thumbPos;
+ final int thumbRight = switchInnerLeft + thumbPos + mThumbWidth + tempRect.right;
thumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);
final Drawable background = getBackground();
@@ -805,20 +835,32 @@
super.onDraw(canvas);
- trackDrawable.draw(canvas);
+ if (mSplitTrack) {
+ final Insets insets = thumbDrawable.getOpticalInsets();
+ thumbDrawable.copyBounds(tempRect);
+ tempRect.left += insets.left;
+ tempRect.right -= insets.right;
+
+ final int saveCount = canvas.save();
+ canvas.clipRect(tempRect, Op.DIFFERENCE);
+ trackDrawable.draw(canvas);
+ canvas.restoreToCount(saveCount);
+ } else {
+ trackDrawable.draw(canvas);
+ }
final int saveCount = canvas.save();
canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom);
thumbDrawable.draw(canvas);
- final int drawableState[] = getDrawableState();
- if (mTextColors != null) {
- mTextPaint.setColor(mTextColors.getColorForState(drawableState, 0));
- }
- mTextPaint.drawableState = drawableState;
-
final Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout;
if (switchText != null) {
+ final int drawableState[] = getDrawableState();
+ if (mTextColors != null) {
+ mTextPaint.setColor(mTextColors.getColorForState(drawableState, 0));
+ }
+ mTextPaint.drawableState = drawableState;
+
final int left = (thumbLeft + thumbRight) / 2 - switchText.getWidth() / 2;
final int top = (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2;
canvas.translate(left, top);
@@ -889,12 +931,16 @@
protected void drawableStateChanged() {
super.drawableStateChanged();
- int[] myDrawableState = getDrawableState();
+ final int[] myDrawableState = getDrawableState();
- // Set the state of the Drawable
- // Drawable may be null when checked state is set from XML, from super constructor
- if (mThumbDrawable != null) mThumbDrawable.setState(myDrawableState);
- if (mTrackDrawable != null) mTrackDrawable.setState(myDrawableState);
+ if (mThumbDrawable != null && mThumbDrawable.setState(myDrawableState)) {
+ // Handle changes to thumb width and height.
+ requestLayout();
+ }
+
+ if (mTrackDrawable != null) {
+ mTrackDrawable.setState(myDrawableState);
+ }
invalidate();
}
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 075feba..928e34e 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -734,13 +734,13 @@
addCustomViewsWithGravity(mTempViews, Gravity.LEFT);
final int leftViewsCount = mTempViews.size();
for (int i = 0; i < leftViewsCount; i++) {
- left = layoutChildLeft(getChildAt(i), left);
+ left = layoutChildLeft(mTempViews.get(i), left);
}
addCustomViewsWithGravity(mTempViews, Gravity.RIGHT);
final int rightViewsCount = mTempViews.size();
for (int i = 0; i < rightViewsCount; i++) {
- right = layoutChildRight(getChildAt(i), right);
+ right = layoutChildRight(mTempViews.get(i), right);
}
// Centered views try to center with respect to the whole bar, but views pinned
@@ -759,7 +759,7 @@
final int centerViewsCount = mTempViews.size();
for (int i = 0; i < centerViewsCount; i++) {
- centerLeft = layoutChildLeft(getChildAt(i), centerLeft);
+ centerLeft = layoutChildLeft(mTempViews.get(i), centerLeft);
}
mTempViews.clear();
}
@@ -778,18 +778,20 @@
private int layoutChildLeft(View child, int left) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
left += lp.leftMargin;
- int top = getChildTop(child);
- child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
- left += lp.rightMargin;
+ final int top = getChildTop(child);
+ final int childWidth = child.getMeasuredWidth();
+ child.layout(left, top, left + childWidth, top + child.getMeasuredHeight());
+ left += childWidth + lp.rightMargin;
return left;
}
private int layoutChildRight(View child, int right) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
right -= lp.rightMargin;
- int top = getChildTop(child);
- child.layout(right - child.getMeasuredWidth(), top, right, top + child.getMeasuredHeight());
- right -= lp.leftMargin;
+ final int top = getChildTop(child);
+ final int childWidth = child.getMeasuredWidth();
+ child.layout(right - childWidth, top, right, top + child.getMeasuredHeight());
+ right -= childWidth + lp.leftMargin;
return right;
}
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 4726da7..664f9db 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -26,6 +26,7 @@
import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
@@ -38,6 +39,7 @@
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
@@ -121,11 +123,14 @@
private int mCheckedItem = -1;
private int mAlertDialogLayout;
+ private int mButtonPanelSideLayout;
private int mListLayout;
private int mMultiChoiceItemLayout;
private int mSingleChoiceItemLayout;
private int mListItemLayout;
+ private int mButtonPanelLayoutHint = AlertDialog.LAYOUT_HINT_NONE;
+
private Handler mHandler;
private final View.OnClickListener mButtonHandler = new View.OnClickListener() {
@@ -197,6 +202,9 @@
mAlertDialogLayout = a.getResourceId(com.android.internal.R.styleable.AlertDialog_layout,
com.android.internal.R.layout.alert_dialog);
+ mButtonPanelSideLayout = a.getResourceId(
+ com.android.internal.R.styleable.AlertDialog_buttonPanelSideLayout, 0);
+
mListLayout = a.getResourceId(
com.android.internal.R.styleable.AlertDialog_listLayout,
com.android.internal.R.layout.select_dialog);
@@ -238,8 +246,21 @@
public void installContent() {
/* We use a custom title so never request a window title */
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
- mWindow.setContentView(mAlertDialogLayout);
+ int contentView = selectContentView();
+ mWindow.setContentView(contentView);
setupView();
+ setupDecor();
+ }
+
+ private int selectContentView() {
+ if (mButtonPanelSideLayout == 0) {
+ return mAlertDialogLayout;
+ }
+ if (mButtonPanelLayoutHint == AlertDialog.LAYOUT_HINT_SIDE) {
+ return mButtonPanelSideLayout;
+ }
+ // TODO: use layout hint side for long messages/lists
+ return mAlertDialogLayout;
}
public void setTitle(CharSequence title) {
@@ -296,6 +317,13 @@
}
/**
+ * Sets a hint for the best button panel layout.
+ */
+ public void setButtonPanelLayoutHint(int layoutHint) {
+ mButtonPanelLayoutHint = layoutHint;
+ }
+
+ /**
* Sets a click listener or a message to be sent when the button is clicked.
* You only need to pass one of {@code listener} or {@code msg}.
*
@@ -415,7 +443,28 @@
public boolean onKeyUp(int keyCode, KeyEvent event) {
return mScrollView != null && mScrollView.executeKeyEvent(event);
}
-
+
+ private void setupDecor() {
+ final View decor = mWindow.getDecorView();
+ final View parent = mWindow.findViewById(R.id.parentPanel);
+ if (parent != null && decor != null) {
+ decor.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
+ @Override
+ public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) {
+ if (insets.isRound()) {
+ // TODO: Get the padding as a function of the window size.
+ int roundOffset = mContext.getResources().getDimensionPixelOffset(
+ R.dimen.alert_dialog_round_padding);
+ parent.setPadding(roundOffset, roundOffset, roundOffset, roundOffset);
+ }
+ return insets.consumeSystemWindowInsets();
+ }
+ });
+ decor.setFitsSystemWindows(true);
+ decor.requestApplyInsets();
+ }
+ }
+
private void setupView() {
LinearLayout contentPanel = (LinearLayout) mWindow.findViewById(R.id.contentPanel);
setupContent(contentPanel);
@@ -636,14 +685,31 @@
private void setBackground(TypedArray a, View topPanel, View contentPanel, View customPanel,
View buttonPanel, boolean hasTitle, boolean hasCustomView, boolean hasButtons) {
- final int topBright = a.getResourceId(
- R.styleable.AlertDialog_topBright, R.drawable.popup_top_bright);
- final int topDark = a.getResourceId(
- R.styleable.AlertDialog_topDark, R.drawable.popup_top_dark);
- final int centerBright = a.getResourceId(
- R.styleable.AlertDialog_centerBright, R.drawable.popup_center_bright);
- final int centerDark = a.getResourceId(
- R.styleable.AlertDialog_centerDark, R.drawable.popup_center_dark);
+ int fullDark = 0;
+ int topDark = 0;
+ int centerDark = 0;
+ int bottomDark = 0;
+ int fullBright = 0;
+ int topBright = 0;
+ int centerBright = 0;
+ int bottomBright = 0;
+ int bottomMedium = 0;
+ if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.KITKAT) {
+ fullDark = R.drawable.popup_full_dark;
+ topDark = R.drawable.popup_top_dark;
+ centerDark = R.drawable.popup_center_dark;
+ bottomDark = R.drawable.popup_bottom_dark;
+ fullBright = R.drawable.popup_full_bright;
+ topBright = R.drawable.popup_top_bright;
+ centerBright = R.drawable.popup_center_bright;
+ bottomBright = R.drawable.popup_bottom_bright;
+ bottomMedium = R.drawable.popup_bottom_medium;
+ }
+ topBright = a.getResourceId(R.styleable.AlertDialog_topBright, topBright);
+ topDark = a.getResourceId(R.styleable.AlertDialog_topDark, topDark);
+ centerBright = a.getResourceId(R.styleable.AlertDialog_centerBright, centerBright);
+ centerDark = a.getResourceId(R.styleable.AlertDialog_centerDark, centerDark);
+
/* We now set the background of all of the sections of the alert.
* First collect together each section that is being displayed along
@@ -707,22 +773,17 @@
if (lastView != null) {
if (setView) {
- final int bottomBright = a.getResourceId(
- R.styleable.AlertDialog_bottomBright, R.drawable.popup_bottom_bright);
- final int bottomMedium = a.getResourceId(
- R.styleable.AlertDialog_bottomMedium, R.drawable.popup_bottom_medium);
- final int bottomDark = a.getResourceId(
- R.styleable.AlertDialog_bottomDark, R.drawable.popup_bottom_dark);
+ bottomBright = a.getResourceId(R.styleable.AlertDialog_bottomBright, bottomBright);
+ bottomMedium = a.getResourceId(R.styleable.AlertDialog_bottomMedium, bottomMedium);
+ bottomDark = a.getResourceId(R.styleable.AlertDialog_bottomDark, bottomDark);
// ListViews will use the Bright background, but buttons use the
// Medium background.
lastView.setBackgroundResource(
lastLight ? (hasButtons ? bottomMedium : bottomBright) : bottomDark);
} else {
- final int fullBright = a.getResourceId(
- R.styleable.AlertDialog_fullBright, R.drawable.popup_full_bright);
- final int fullDark = a.getResourceId(
- R.styleable.AlertDialog_fullDark, R.drawable.popup_full_dark);
+ fullBright = a.getResourceId(R.styleable.AlertDialog_fullBright, fullBright);
+ fullDark = a.getResourceId(R.styleable.AlertDialog_fullDark, fullDark);
lastView.setBackgroundResource(lastLight ? fullBright : fullDark);
}
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 2f74372..47ef65a 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -84,6 +84,7 @@
Slog.e(TAG, "PackageManagerService is dead?");
}
if (canForward) {
+ newIntent.prepareToLeaveUser(callingUserId);
startActivityAsUser(newIntent, userDest);
} else {
Slog.wtf(TAG, "the intent: " + newIntent + "cannot be forwarded from user "
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 882bec9..41f3337 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -1108,13 +1108,6 @@
mRuntime = runtime;
}
}
- String webview = WebViewFactory.useExperimentalWebView() ? "chromeview" : "webview";
- if (!Objects.equals(webview, mWebView)) {
- changed = true;
- if (update) {
- mWebView = webview;
- }
- }
return changed;
}
diff --git a/core/java/com/android/internal/notification/DemoContactNotificationScorer.java b/core/java/com/android/internal/notification/DemoContactNotificationScorer.java
deleted file mode 100644
index f484724..0000000
--- a/core/java/com/android/internal/notification/DemoContactNotificationScorer.java
+++ /dev/null
@@ -1,188 +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.notification;
-
-import android.app.Notification;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.ContactsContract;
-import android.provider.Settings;
-import android.text.SpannableString;
-import android.util.Slog;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * This NotificationScorer bumps up the priority of notifications that contain references to the
- * display names of starred contacts. The references it picks up are spannable strings which, in
- * their entirety, match the display name of some starred contact. The magnitude of the bump ranges
- * from 0 to 15 (assuming NOTIFICATION_PRIORITY_MULTIPLIER = 10) depending on the initial score, and
- * the mapping is defined by priorityBumpMap. In a production version of this scorer, a notification
- * extra will be used to specify contact identifiers.
- */
-
-public class DemoContactNotificationScorer implements NotificationScorer {
- private static final String TAG = "DemoContactNotificationScorer";
- private static final boolean DBG = false;
-
- protected static final boolean ENABLE_CONTACT_SCORER = true;
- private static final String SETTING_ENABLE_SCORER = "contact_scorer_enabled";
- protected boolean mEnabled;
-
- // see NotificationManagerService
- private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
-
- private Context mContext;
-
- private static final List<String> RELEVANT_KEYS_LIST = Arrays.asList(
- Notification.EXTRA_INFO_TEXT, Notification.EXTRA_TEXT, Notification.EXTRA_TEXT_LINES,
- Notification.EXTRA_SUB_TEXT, Notification.EXTRA_TITLE
- );
-
- private static final String[] PROJECTION = new String[] {
- ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME
- };
-
- private static final Uri CONTACTS_URI = ContactsContract.Contacts.CONTENT_URI;
-
- private static List<String> extractSpannedStrings(CharSequence charSequence) {
- if (charSequence == null) return Collections.emptyList();
- if (!(charSequence instanceof SpannableString)) {
- return Arrays.asList(charSequence.toString());
- }
- SpannableString spannableString = (SpannableString)charSequence;
- // get all spans
- Object[] ssArr = spannableString.getSpans(0, spannableString.length(), Object.class);
- // spanned string sequences
- ArrayList<String> sss = new ArrayList<String>();
- for (Object spanObj : ssArr) {
- try {
- sss.add(spannableString.subSequence(spannableString.getSpanStart(spanObj),
- spannableString.getSpanEnd(spanObj)).toString());
- } catch(StringIndexOutOfBoundsException e) {
- Slog.e(TAG, "Bad indices when extracting spanned subsequence", e);
- }
- }
- return sss;
- };
-
- private static String getQuestionMarksInParens(int n) {
- StringBuilder sb = new StringBuilder("(");
- for (int i = 0; i < n; i++) {
- if (sb.length() > 1) sb.append(',');
- sb.append('?');
- }
- sb.append(")");
- return sb.toString();
- }
-
- private boolean hasStarredContact(Bundle extras) {
- if (extras == null) return false;
- ArrayList<String> qStrings = new ArrayList<String>();
- // build list to query against the database for display names.
- for (String rk: RELEVANT_KEYS_LIST) {
- if (extras.get(rk) == null) {
- continue;
- } else if (extras.get(rk) instanceof CharSequence) {
- qStrings.addAll(extractSpannedStrings((CharSequence) extras.get(rk)));
- } else if (extras.get(rk) instanceof CharSequence[]) {
- // this is intended for Notification.EXTRA_TEXT_LINES
- for (CharSequence line: (CharSequence[]) extras.get(rk)){
- qStrings.addAll(extractSpannedStrings(line));
- }
- } else {
- Slog.w(TAG, "Strange, the extra " + rk + " is of unexpected type.");
- }
- }
- if (qStrings.isEmpty()) return false;
- String[] qStringsArr = qStrings.toArray(new String[qStrings.size()]);
-
- String selection = ContactsContract.Contacts.DISPLAY_NAME + " IN "
- + getQuestionMarksInParens(qStringsArr.length) + " AND "
- + ContactsContract.Contacts.STARRED+" ='1'";
-
- Cursor c = null;
- try {
- c = mContext.getContentResolver().query(
- CONTACTS_URI, PROJECTION, selection, qStringsArr, null);
- if (c != null) return c.getCount() > 0;
- } catch(Throwable t) {
- Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
- } finally {
- if (c != null) {
- c.close();
- }
- }
- return false;
- }
-
- private final static int clamp(int x, int low, int high) {
- return (x < low) ? low : ((x > high) ? high : x);
- }
-
- private static int priorityBumpMap(int incomingScore) {
- //assumption is that scale runs from [-2*pm, 2*pm]
- int pm = NOTIFICATION_PRIORITY_MULTIPLIER;
- int theScore = incomingScore;
- // enforce input in range
- theScore = clamp(theScore, -2 * pm, 2 * pm);
- if (theScore != incomingScore) return incomingScore;
- // map -20 -> -20 and -10 -> 5 (when pm = 10)
- if (theScore <= -pm) {
- theScore += 1.5 * (theScore + 2 * pm);
- } else {
- // map 0 -> 10, 10 -> 15, 20 -> 20;
- theScore += 0.5 * (2 * pm - theScore);
- }
- if (DBG) Slog.v(TAG, "priorityBumpMap: score before: " + incomingScore
- + ", score after " + theScore + ".");
- return theScore;
- }
-
- @Override
- public void initialize(Context context) {
- if (DBG) Slog.v(TAG, "Initializing " + getClass().getSimpleName() + ".");
- mContext = context;
- mEnabled = ENABLE_CONTACT_SCORER && 1 == Settings.Global.getInt(
- mContext.getContentResolver(), SETTING_ENABLE_SCORER, 0);
- }
-
- @Override
- public int getScore(Notification notification, int score) {
- if (notification == null || !mEnabled) {
- if (DBG) Slog.w(TAG, "empty notification? scorer disabled?");
- return score;
- }
- boolean hasStarredPriority = hasStarredContact(notification.extras);
-
- if (DBG) {
- if (hasStarredPriority) {
- Slog.v(TAG, "Notification references starred contact. Promoted!");
- } else {
- Slog.v(TAG, "Notification lacks any starred contact reference. Not promoted!");
- }
- }
- if (hasStarredPriority) score = priorityBumpMap(score);
- return score;
- }
-}
-
diff --git a/core/java/com/android/internal/notification/NotificationScorer.java b/core/java/com/android/internal/notification/NotificationScorer.java
deleted file mode 100644
index 863c08c..0000000
--- a/core/java/com/android/internal/notification/NotificationScorer.java
+++ /dev/null
@@ -1,27 +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.notification;
-
-import android.app.Notification;
-import android.content.Context;
-
-public interface NotificationScorer {
-
- public void initialize(Context context);
- public int getScore(Notification notification, int score);
-
-}
diff --git a/core/java/com/android/internal/notification/PeopleNotificationScorer.java b/core/java/com/android/internal/notification/PeopleNotificationScorer.java
deleted file mode 100644
index efb5f63..0000000
--- a/core/java/com/android/internal/notification/PeopleNotificationScorer.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
-* Copyright (C) 2014 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-package com.android.internal.notification;
-
-import android.app.Notification;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.Contacts;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.LruCache;
-import android.util.Slog;
-
-/**
- * This {@link NotificationScorer} attempts to validate people references.
- * Also elevates the priority of real people.
- */
-public class PeopleNotificationScorer implements NotificationScorer {
- private static final String TAG = "PeopleNotificationScorer";
- private static final boolean DBG = false;
-
- private static final boolean ENABLE_PEOPLE_SCORER = true;
- private static final String SETTING_ENABLE_PEOPLE_SCORER = "people_scorer_enabled";
- private static final String[] LOOKUP_PROJECTION = { Contacts._ID };
- private static final int MAX_PEOPLE = 10;
- private static final int PEOPLE_CACHE_SIZE = 200;
- // see NotificationManagerService
- private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
-
- protected boolean mEnabled;
- private Context mContext;
-
- // maps raw person handle to resolved person object
- private LruCache<String, LookupResult> mPeopleCache;
-
- private float findMaxContactScore(Bundle extras) {
- if (extras == null) {
- return 0f;
- }
-
- final String[] people = extras.getStringArray(Notification.EXTRA_PEOPLE);
- if (people == null || people.length == 0) {
- return 0f;
- }
-
- float rank = 0f;
- for (int personIdx = 0; personIdx < people.length && personIdx < MAX_PEOPLE; personIdx++) {
- final String handle = people[personIdx];
- if (TextUtils.isEmpty(handle)) continue;
-
- LookupResult lookupResult = mPeopleCache.get(handle);
- if (lookupResult == null || lookupResult.isExpired()) {
- final Uri uri = Uri.parse(handle);
- if ("tel".equals(uri.getScheme())) {
- if (DBG) Slog.w(TAG, "checking telephone URI: " + handle);
- lookupResult = lookupPhoneContact(handle, uri.getSchemeSpecificPart());
- } else if (handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) {
- if (DBG) Slog.w(TAG, "checking lookup URI: " + handle);
- lookupResult = resolveContactsUri(handle, uri);
- } else {
- if (DBG) Slog.w(TAG, "unsupported URI " + handle);
- }
- } else {
- if (DBG) Slog.w(TAG, "using cached lookupResult: " + lookupResult.mId);
- }
- if (lookupResult != null) {
- rank = Math.max(rank, lookupResult.getRank());
- }
- }
- return rank;
- }
-
- private LookupResult lookupPhoneContact(final String handle, final String number) {
- LookupResult lookupResult = null;
- Cursor c = null;
- try {
- Uri numberUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
- Uri.encode(number));
- c = mContext.getContentResolver().query(numberUri, LOOKUP_PROJECTION, null, null, null);
- if (c != null && c.getCount() > 0) {
- c.moveToFirst();
- final int idIdx = c.getColumnIndex(Contacts._ID);
- final int id = c.getInt(idIdx);
- if (DBG) Slog.w(TAG, "is valid: " + id);
- lookupResult = new LookupResult(id);
- }
- } catch(Throwable t) {
- Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
- } finally {
- if (c != null) {
- c.close();
- }
- }
- if (lookupResult == null) {
- lookupResult = new LookupResult(LookupResult.INVALID_ID);
- }
- mPeopleCache.put(handle, lookupResult);
- return lookupResult;
- }
-
- private LookupResult resolveContactsUri(String handle, final Uri personUri) {
- LookupResult lookupResult = null;
- Cursor c = null;
- try {
- c = mContext.getContentResolver().query(personUri, LOOKUP_PROJECTION, null, null, null);
- if (c != null && c.getCount() > 0) {
- c.moveToFirst();
- final int idIdx = c.getColumnIndex(Contacts._ID);
- final int id = c.getInt(idIdx);
- if (DBG) Slog.w(TAG, "is valid: " + id);
- lookupResult = new LookupResult(id);
- }
- } catch(Throwable t) {
- Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
- } finally {
- if (c != null) {
- c.close();
- }
- }
- if (lookupResult == null) {
- lookupResult = new LookupResult(LookupResult.INVALID_ID);
- }
- mPeopleCache.put(handle, lookupResult);
- return lookupResult;
- }
-
- private final static int clamp(int x, int low, int high) {
- return (x < low) ? low : ((x > high) ? high : x);
- }
-
- // TODO: rework this function before shipping
- private static int priorityBumpMap(int incomingScore) {
- //assumption is that scale runs from [-2*pm, 2*pm]
- int pm = NOTIFICATION_PRIORITY_MULTIPLIER;
- int theScore = incomingScore;
- // enforce input in range
- theScore = clamp(theScore, -2 * pm, 2 * pm);
- if (theScore != incomingScore) return incomingScore;
- // map -20 -> -20 and -10 -> 5 (when pm = 10)
- if (theScore <= -pm) {
- theScore += 1.5 * (theScore + 2 * pm);
- } else {
- // map 0 -> 10, 10 -> 15, 20 -> 20;
- theScore += 0.5 * (2 * pm - theScore);
- }
- if (DBG) Slog.v(TAG, "priorityBumpMap: score before: " + incomingScore
- + ", score after " + theScore + ".");
- return theScore;
- }
-
- @Override
- public void initialize(Context context) {
- if (DBG) Slog.v(TAG, "Initializing " + getClass().getSimpleName() + ".");
- mContext = context;
- mPeopleCache = new LruCache<String, LookupResult>(PEOPLE_CACHE_SIZE);
- mEnabled = ENABLE_PEOPLE_SCORER && 1 == Settings.Global.getInt(
- mContext.getContentResolver(), SETTING_ENABLE_PEOPLE_SCORER, 0);
- }
-
- @Override
- public int getScore(Notification notification, int score) {
- if (notification == null || !mEnabled) {
- if (DBG) Slog.w(TAG, "empty notification? scorer disabled?");
- return score;
- }
- float contactScore = findMaxContactScore(notification.extras);
- if (contactScore > 0f) {
- if (DBG) Slog.v(TAG, "Notification references a real contact. Promoted!");
- score = priorityBumpMap(score);
- } else {
- if (DBG) Slog.v(TAG, "Notification lacks any valid contact reference. Not promoted!");
- }
- return score;
- }
-
- private static class LookupResult {
- private static final long CONTACT_REFRESH_MILLIS = 60 * 60 * 1000; // 1hr
- public static final int INVALID_ID = -1;
-
- private final long mExpireMillis;
- private int mId;
-
- public LookupResult(int id) {
- mId = id;
- mExpireMillis = System.currentTimeMillis() + CONTACT_REFRESH_MILLIS;
- }
-
- public boolean isExpired() {
- return mExpireMillis < System.currentTimeMillis();
- }
-
- public boolean isInvalid() {
- return mId == INVALID_ID || isExpired();
- }
-
- public float getRank() {
- if (isInvalid()) {
- return 0f;
- } else {
- return 1f; // TODO: finer grained score
- }
- }
-
- public LookupResult setId(int id) {
- mId = id;
- return this;
- }
- }
-}
-
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 1aff190..7bd5b12 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -188,8 +188,7 @@
boolean mShuttingDown;
- HashMap<String, SparseBooleanArray>[] mActiveEvents
- = (HashMap<String, SparseBooleanArray>[]) new HashMap[HistoryItem.EVENT_COUNT];
+ final HistoryEventTracker mActiveEvents = new HistoryEventTracker();
long mHistoryBaseTime;
boolean mHaveBatteryLevel = false;
@@ -2297,44 +2296,8 @@
public void noteEventLocked(int code, String name, int uid) {
uid = mapUid(uid);
- if ((code&HistoryItem.EVENT_FLAG_START) != 0) {
- int idx = code&~HistoryItem.EVENT_FLAG_START;
- HashMap<String, SparseBooleanArray> active = mActiveEvents[idx];
- if (active == null) {
- active = new HashMap<String, SparseBooleanArray>();
- mActiveEvents[idx] = active;
- }
- SparseBooleanArray uids = active.get(name);
- if (uids == null) {
- uids = new SparseBooleanArray();
- active.put(name, uids);
- }
- if (uids.get(uid)) {
- // Already set, nothing to do!
- return;
- }
- uids.put(uid, true);
- } else if ((code&HistoryItem.EVENT_FLAG_FINISH) != 0) {
- int idx = code&~HistoryItem.EVENT_FLAG_FINISH;
- HashMap<String, SparseBooleanArray> active = mActiveEvents[idx];
- if (active == null) {
- // not currently active, nothing to do.
- return;
- }
- SparseBooleanArray uids = active.get(name);
- if (uids == null) {
- // not currently active, nothing to do.
- return;
- }
- idx = uids.indexOfKey(uid);
- if (idx < 0 || !uids.valueAt(idx)) {
- // not currently active, nothing to do.
- return;
- }
- uids.removeAt(idx);
- if (uids.size() <= 0) {
- active.remove(name);
- }
+ if (!mActiveEvents.updateState(code, name, uid, 0)) {
+ return;
}
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
@@ -2348,6 +2311,9 @@
}
}
+ private String mInitialAcquireWakeName;
+ private int mInitialAcquireWakeUid = -1;
+
public void noteStartWakeLocked(int uid, int pid, String name, String historyName, int type,
boolean unimportantForLogging, long elapsedRealtime, long uptime) {
uid = mapUid(uid);
@@ -2360,8 +2326,9 @@
if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "
+ Integer.toHexString(mHistoryCur.states));
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
- mHistoryCur.wakelockTag.string = historyName != null ? historyName : name;
- mHistoryCur.wakelockTag.uid = uid;
+ mHistoryCur.wakelockTag.string = mInitialAcquireWakeName
+ = historyName != null ? historyName : name;
+ mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
mWakeLockImportant = !unimportantForLogging;
addHistoryRecordLocked(elapsedRealtime, uptime);
} else if (!mWakeLockImportant && !unimportantForLogging) {
@@ -2369,8 +2336,9 @@
// We'll try to update the last tag.
mHistoryLastWritten.wakelockTag = null;
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
- mHistoryCur.wakelockTag.string = historyName != null ? historyName : name;
- mHistoryCur.wakelockTag.uid = uid;
+ mHistoryCur.wakelockTag.string = mInitialAcquireWakeName
+ = historyName != null ? historyName : name;
+ mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
addHistoryRecordLocked(elapsedRealtime, uptime);
}
mWakeLockImportant = true;
@@ -2395,6 +2363,14 @@
mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: "
+ Integer.toHexString(mHistoryCur.states));
+ if ((name != null && !name.equals(mInitialAcquireWakeName))
+ || uid != mInitialAcquireWakeUid) {
+ mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+ mHistoryCur.wakelockTag.string = name;
+ mHistoryCur.wakelockTag.uid = uid;
+ }
+ mInitialAcquireWakeName = null;
+ mInitialAcquireWakeUid = -1;
addHistoryRecordLocked(elapsedRealtime, uptime);
}
}
@@ -5699,7 +5675,8 @@
final long lastRealtime = out.time;
final long lastWalltime = out.currentTime;
readHistoryDelta(mHistoryBuffer, out);
- if (out.cmd != HistoryItem.CMD_CURRENT_TIME && lastWalltime != 0) {
+ if (out.cmd != HistoryItem.CMD_CURRENT_TIME
+ && out.cmd != HistoryItem.CMD_RESET && lastWalltime != 0) {
out.currentTime = lastWalltime + (out.time - lastRealtime);
}
return true;
@@ -5845,17 +5822,15 @@
private void initActiveHistoryEventsLocked(long elapsedRealtimeMs, long uptimeMs) {
for (int i=0; i<HistoryItem.EVENT_COUNT; i++) {
- HashMap<String, SparseBooleanArray> active = mActiveEvents[i];
+ HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(i);
if (active == null) {
continue;
}
- for (HashMap.Entry<String, SparseBooleanArray> ent : active.entrySet()) {
- SparseBooleanArray uids = ent.getValue();
+ for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
+ SparseIntArray uids = ent.getValue();
for (int j=0; j<uids.size(); j++) {
- if (uids.valueAt(j)) {
- addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, i, ent.getKey(),
- uids.keyAt(j));
- }
+ addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, i, ent.getKey(),
+ uids.keyAt(j));
}
}
}
@@ -5971,7 +5946,8 @@
boolean reset) {
mRecordingHistory = true;
mHistoryCur.currentTime = System.currentTimeMillis();
- addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_CURRENT_TIME,
+ addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs,
+ reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME,
mHistoryCur);
mHistoryCur.currentTime = 0;
if (reset) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 3ea749e..5ce658b 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -23,6 +23,7 @@
import android.content.res.TypedArray;
import android.net.LocalServerSocket;
import android.opengl.EGL14;
+import android.os.Build;
import android.os.Debug;
import android.os.Process;
import android.os.SystemClock;
@@ -505,7 +506,7 @@
/**
* Prepare the arguments and fork for the system server process.
*/
- private static boolean startSystemServer()
+ private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException {
long capabilities = posixCapabilitiesAsBits(
OsConstants.CAP_BLOCK_SUSPEND,
@@ -553,6 +554,10 @@
/* For child process */
if (pid == 0) {
+ if (hasSecondZygote(abiList)) {
+ waitForSecondaryZygote(socketName);
+ }
+
handleSystemServerProcess(parsedArgs);
}
@@ -615,7 +620,7 @@
Trace.setTracingEnabled(false);
if (startSystemServer) {
- startSystemServer();
+ startSystemServer(abiList, socketName);
}
Log.i(TAG, "Accepting command socket connections");
@@ -632,6 +637,36 @@
}
/**
+ * Return {@code true} if this device configuration has another zygote.
+ *
+ * We determine this by comparing the device ABI list with this zygotes
+ * list. If this zygote supports all ABIs this device supports, there won't
+ * be another zygote.
+ */
+ private static boolean hasSecondZygote(String abiList) {
+ return !SystemProperties.get("ro.product.cpu.abilist").equals(abiList);
+ }
+
+ private static void waitForSecondaryZygote(String socketName) {
+ String otherZygoteName = Process.ZYGOTE_SOCKET.equals(socketName) ?
+ Process.SECONDARY_ZYGOTE_SOCKET : Process.ZYGOTE_SOCKET;
+ while (true) {
+ try {
+ final Process.ZygoteState zs = Process.ZygoteState.connect(otherZygoteName);
+ zs.close();
+ break;
+ } catch (IOException ioe) {
+ Log.w(TAG, "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
+ }
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+
+ /**
* Runs the zygote process's select loop. Accepts new connections as
* they happen, and reads commands from connections one spawn-request's
* worth at a time.
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index d177410..a56fa36 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -117,6 +117,13 @@
}
/**
+ * Checks if given array is null or has zero elements.
+ */
+ public static <T> boolean isEmpty(T[] array) {
+ return array == null || array.length == 0;
+ }
+
+ /**
* Checks that value is present as at least one of the elements of the array.
* @param array the array to check in
* @param value the value to check for
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index 52281d9..34f62ba 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -450,6 +450,7 @@
public void disconnect() {
if ((mConnection != null) && (mSrcContext != null)) {
mSrcContext.unbindService(mConnection);
+ mConnection = null;
}
try {
// Send the DISCONNECTED, although it may not be received
@@ -463,10 +464,12 @@
// Tell source we're disconnected.
if (mSrcHandler != null) {
replyDisconnected(STATUS_SUCCESSFUL);
+ mSrcHandler = null;
}
// Unlink only when bindService isn't used
if (mConnection == null && mDstMessenger != null && mDeathMonitor!= null) {
mDstMessenger.getBinder().unlinkToDeath(mDeathMonitor, 0);
+ mDeathMonitor = null;
}
}
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index bc92c4a..4b84941 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -55,5 +55,9 @@
public static final int BASE_DNS_PINGER = 0x00050000;
public static final int BASE_NSD_MANAGER = 0x00060000;
public static final int BASE_NETWORK_STATE_TRACKER = 0x00070000;
+ public static final int BASE_CONNECTIVITY_SERVICE = 0x00080000;
+ public static final int BASE_NETWORK_AGENT = 0x00081000;
+ public static final int BASE_NETWORK_MONITOR = 0x00082000;
+ public static final int BASE_CONNECTIVITY_MANAGER = 0x00083000;
//TODO: define all used protocols
}
diff --git a/core/java/com/android/internal/util/VirtualRefBasePtr.java b/core/java/com/android/internal/util/VirtualRefBasePtr.java
new file mode 100644
index 0000000..0bd4d3a
--- /dev/null
+++ b/core/java/com/android/internal/util/VirtualRefBasePtr.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+/**
+ * Helper class that contains a strong reference to a VirtualRefBase native
+ * object. This will incStrong in the ctor, and decStrong in the finalizer
+ */
+public final class VirtualRefBasePtr {
+ private long mNativePtr;
+
+ public VirtualRefBasePtr(long ptr) {
+ mNativePtr = ptr;
+ nIncStrong(mNativePtr);
+ }
+
+ public long get() {
+ return mNativePtr;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ nDecStrong(mNativePtr);
+ mNativePtr = 0;
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private static native void nIncStrong(long ptr);
+ private static native void nDecStrong(long ptr);
+}
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index b35de93..5b59599 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -912,6 +912,15 @@
}
}
+ public static int readIntAttribute(XmlPullParser in, String name, int defaultValue) {
+ final String value = in.getAttributeValue(null, name);
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
public static int readIntAttribute(XmlPullParser in, String name) throws IOException {
final String value = in.getAttributeValue(null, name);
try {
diff --git a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
new file mode 100644
index 0000000..aec2b7e
--- /dev/null
+++ b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view.animation;
+
+import android.animation.TimeInterpolator;
+import android.util.TimeUtils;
+import android.view.Choreographer;
+
+/**
+ * Interpolator that builds a lookup table to use. This is a fallback for
+ * building a native interpolator from a TimeInterpolator that is not marked
+ * with {@link HasNativeInterpolator}
+ */
+@HasNativeInterpolator
+public class FallbackLUTInterpolator implements NativeInterpolatorFactory {
+
+ private final float mLut[];
+
+ /**
+ * Used to cache the float[] LUT for use across multiple native
+ * interpolator creation
+ */
+ public FallbackLUTInterpolator(TimeInterpolator interpolator, int duration) {
+ mLut = createLUT(interpolator, duration);
+ }
+
+ private static float[] createLUT(TimeInterpolator interpolator, int duration) {
+ long frameIntervalNanos = Choreographer.getInstance().getFrameIntervalNanos();
+ int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS);
+ int numAnimFrames = (int) Math.ceil(duration / animIntervalMs);
+ float values[] = new float[numAnimFrames];
+ float lastFrame = numAnimFrames - 1;
+ for (int i = 0; i < numAnimFrames; i++) {
+ float inValue = i / lastFrame;
+ values[i] = interpolator.getInterpolation(inValue);
+ }
+ return values;
+ }
+
+ @Override
+ public long createNativeInterpolator() {
+ return NativeInterpolatorFactoryHelper.createLutInterpolator(mLut);
+ }
+
+ /**
+ * Used to create a one-shot float[] LUT & native interpolator
+ */
+ public static long createNativeInterpolator(TimeInterpolator interpolator, int duration) {
+ float[] lut = createLUT(interpolator, duration);
+ return NativeInterpolatorFactoryHelper.createLutInterpolator(lut);
+ }
+}
diff --git a/core/java/com/android/internal/view/animation/HasNativeInterpolator.java b/core/java/com/android/internal/view/animation/HasNativeInterpolator.java
new file mode 100644
index 0000000..48ea4da
--- /dev/null
+++ b/core/java/com/android/internal/view/animation/HasNativeInterpolator.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view.animation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This is a class annotation that signals that it is safe to create
+ * a native interpolator counterpart via {@link NativeInterpolatorFactory}
+ *
+ * The idea here is to prevent subclasses of interpolators from being treated as a
+ * NativeInterpolatorFactory, and instead have them fall back to the LUT & LERP
+ * method like a custom interpolator.
+ *
+ * @hide
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface HasNativeInterpolator {
+}
diff --git a/core/java/com/android/internal/view/animation/NativeInterpolatorFactory.java b/core/java/com/android/internal/view/animation/NativeInterpolatorFactory.java
new file mode 100644
index 0000000..fcacd52
--- /dev/null
+++ b/core/java/com/android/internal/view/animation/NativeInterpolatorFactory.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view.animation;
+
+public interface NativeInterpolatorFactory {
+ long createNativeInterpolator();
+}
diff --git a/core/java/com/android/internal/view/animation/NativeInterpolatorFactoryHelper.java b/core/java/com/android/internal/view/animation/NativeInterpolatorFactoryHelper.java
new file mode 100644
index 0000000..7cd75f3
--- /dev/null
+++ b/core/java/com/android/internal/view/animation/NativeInterpolatorFactoryHelper.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view.animation;
+
+/**
+ * Static utility class for constructing native interpolators to keep the
+ * JNI simpler
+ */
+public final class NativeInterpolatorFactoryHelper {
+ private NativeInterpolatorFactoryHelper() {}
+
+ public static native long createAccelerateDecelerateInterpolator();
+ public static native long createAccelerateInterpolator(float factor);
+ public static native long createAnticipateInterpolator(float tension);
+ public static native long createAnticipateOvershootInterpolator(float tension);
+ public static native long createBounceInterpolator();
+ public static native long createCycleInterpolator(float cycles);
+ public static native long createDecelerateInterpolator(float factor);
+ public static native long createLinearInterpolator();
+ public static native long createOvershootInterpolator(float tension);
+ public static native long createLutInterpolator(float[] values);
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 51e2871..0ad2ab2 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -5,6 +5,7 @@
LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
LOCAL_CFLAGS += -U__APPLE__
LOCAL_CFLAGS += -Wno-unused-parameter -Wno-int-to-pointer-cast
+LOCAL_CFLAGS += -Wno-non-virtual-dtor
LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
LOCAL_CPPFLAGS += -Wno-conversion-null
@@ -95,11 +96,11 @@
android/graphics/CanvasProperty.cpp \
android/graphics/ColorFilter.cpp \
android/graphics/DrawFilter.cpp \
+ android/graphics/FontFamily.cpp \
android/graphics/CreateJavaOutputStreamAdaptor.cpp \
android/graphics/Graphics.cpp \
android/graphics/HarfBuzzNGFaceSkia.cpp \
android/graphics/Interpolator.cpp \
- android/graphics/LayerRasterizer.cpp \
android/graphics/MaskFilter.cpp \
android/graphics/Matrix.cpp \
android/graphics/Movie.cpp \
@@ -125,6 +126,7 @@
android/graphics/Xfermode.cpp \
android/graphics/YuvToJpegEncoder.cpp \
android/graphics/pdf/PdfDocument.cpp \
+ android/graphics/pdf/PdfRenderer.cpp \
android_media_AudioRecord.cpp \
android_media_AudioSystem.cpp \
android_media_AudioTrack.cpp \
@@ -155,7 +157,9 @@
android_content_res_Configuration.cpp \
android_animation_PropertyValuesHolder.cpp \
com_android_internal_net_NetworkStatsFactory.cpp \
- com_android_internal_os_Zygote.cpp
+ com_android_internal_os_Zygote.cpp \
+ com_android_internal_util_VirtualRefBasePtr.cpp \
+ com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
@@ -167,6 +171,9 @@
$(call include-path-for, libhardware_legacy)/hardware_legacy \
$(TOP)/frameworks/av/include \
$(TOP)/system/media/camera/include \
+ external/pdfrenderer/core/include/fpdfapi \
+ external/pdfrenderer/core/include/fpdfdoc \
+ external/pdfrenderer/fpdfsdk/include \
external/skia/src/core \
external/skia/src/effects \
external/skia/src/images \
@@ -220,6 +227,7 @@
libharfbuzz_ng \
libz \
libaudioutils \
+ libpdfrenderer \
ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_SHARED_LIBRARIES += libhwui
@@ -229,7 +237,8 @@
LOCAL_CFLAGS += -DUSE_MINIKIN
LOCAL_C_INCLUDES += frameworks/minikin/include \
external/freetype/include
- LOCAL_SRC_FILES += android/graphics/MinikinSkia.cpp
+ LOCAL_SRC_FILES += android/graphics/MinikinSkia.cpp \
+ android/graphics/MinikinUtils.cpp
# note: the freetype include is spurious; minikin itself probably
# shouldn't depend on it
LOCAL_SHARED_LIBRARIES += libminikin libstlport
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 66fbb8e..a4dc824 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -56,7 +56,6 @@
extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env);
extern int register_android_graphics_Graphics(JNIEnv* env);
extern int register_android_graphics_Interpolator(JNIEnv* env);
-extern int register_android_graphics_LayerRasterizer(JNIEnv*);
extern int register_android_graphics_MaskFilter(JNIEnv* env);
extern int register_android_graphics_Movie(JNIEnv* env);
extern int register_android_graphics_NinePatch(JNIEnv*);
@@ -108,6 +107,8 @@
extern int register_android_graphics_CanvasProperty(JNIEnv* env);
extern int register_android_graphics_ColorFilter(JNIEnv* env);
extern int register_android_graphics_DrawFilter(JNIEnv* env);
+extern int register_android_graphics_FontFamily(JNIEnv* env);
+extern int register_android_graphics_LayerRasterizer(JNIEnv*);
extern int register_android_graphics_Matrix(JNIEnv* env);
extern int register_android_graphics_Paint(JNIEnv* env);
extern int register_android_graphics_Path(JNIEnv* env);
@@ -119,6 +120,7 @@
extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
extern int register_android_graphics_Xfermode(JNIEnv* env);
extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
+extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
extern int register_android_view_RenderNode(JNIEnv* env);
extern int register_android_view_RenderNodeAnimator(JNIEnv* env);
@@ -131,6 +133,7 @@
extern int register_android_view_SurfaceControl(JNIEnv* env);
extern int register_android_view_SurfaceSession(JNIEnv* env);
extern int register_android_view_TextureView(JNIEnv* env);
+extern int register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper(JNIEnv *env);
extern int register_android_database_CursorWindow(JNIEnv* env);
extern int register_android_database_SQLiteConnection(JNIEnv* env);
extern int register_android_database_SQLiteGlobal(JNIEnv* env);
@@ -181,6 +184,7 @@
extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
extern int register_com_android_internal_os_Zygote(JNIEnv *env);
+extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
static AndroidRuntime* gCurRuntime = NULL;
@@ -470,6 +474,7 @@
char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];
char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX];
char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
+ char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX];
char dalvikVmLibBuf[PROPERTY_VALUE_MAX];
@@ -623,6 +628,13 @@
mOptions.add(opt);
}
+ strcpy(backgroundgcOptsBuf, "-XX:BackgroundGC=");
+ property_get("dalvik.vm.backgroundgctype", backgroundgcOptsBuf+sizeof("-XX:BackgroundGC=")-1, "");
+ if (backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1] != '\0') {
+ opt.optionString = backgroundgcOptsBuf;
+ mOptions.add(opt);
+ }
+
/*
* Enable or disable dexopt features, such as bytecode verification and
* calculation of register maps for precise GC.
@@ -1205,6 +1217,7 @@
REG_JNI(register_android_view_SurfaceControl),
REG_JNI(register_android_view_SurfaceSession),
REG_JNI(register_android_view_TextureView),
+ REG_JNI(register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper),
REG_JNI(register_com_google_android_gles_jni_EGLImpl),
REG_JNI(register_com_google_android_gles_jni_GLImpl),
REG_JNI(register_android_opengl_jni_EGL14),
@@ -1225,6 +1238,7 @@
REG_JNI(register_android_graphics_CanvasProperty),
REG_JNI(register_android_graphics_ColorFilter),
REG_JNI(register_android_graphics_DrawFilter),
+ REG_JNI(register_android_graphics_FontFamily),
REG_JNI(register_android_graphics_Interpolator),
REG_JNI(register_android_graphics_LayerRasterizer),
REG_JNI(register_android_graphics_MaskFilter),
@@ -1245,6 +1259,7 @@
REG_JNI(register_android_graphics_Xfermode),
REG_JNI(register_android_graphics_YuvImage),
REG_JNI(register_android_graphics_pdf_PdfDocument),
+ REG_JNI(register_android_graphics_pdf_PdfRenderer),
REG_JNI(register_android_database_CursorWindow),
REG_JNI(register_android_database_SQLiteConnection),
@@ -1262,6 +1277,7 @@
REG_JNI(register_android_os_MemoryFile),
REG_JNI(register_com_android_internal_os_ZygoteInit),
REG_JNI(register_com_android_internal_os_Zygote),
+ REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
REG_JNI(register_android_hardware_Camera),
REG_JNI(register_android_hardware_camera2_CameraMetadata),
REG_JNI(register_android_hardware_SensorManager),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index e0fa9ba4..0328517 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -1,838 +1,838 @@
-#include "SkBitmap.h"
-#include "SkPixelRef.h"
-#include "SkImageEncoder.h"
-#include "SkColorPriv.h"
-#include "GraphicsJNI.h"
-#include "SkDither.h"
-#include "SkUnPreMultiply.h"
-#include "SkStream.h"
-
-#include <binder/Parcel.h>
-#include "android_os_Parcel.h"
-#include "android_util_Binder.h"
-#include "android_nio_utils.h"
-#include "CreateJavaOutputStreamAdaptor.h"
-
-#include <jni.h>
-
-#include <Caches.h>
-
-#if 0
- #define TRACE_BITMAP(code) code
-#else
- #define TRACE_BITMAP(code)
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-// Conversions to/from SkColor, for get/setPixels, and the create method, which
-// is basically like setPixels
-
-typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
- int x, int y);
-
-static void FromColor_D32(void* dst, const SkColor src[], int width,
- int, int) {
- SkPMColor* d = (SkPMColor*)dst;
-
- for (int i = 0; i < width; i++) {
- *d++ = SkPreMultiplyColor(*src++);
- }
-}
-
-static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,
- int, int) {
- // SkColor's ordering may be different from SkPMColor
- if (SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER) {
- memcpy(dst, src, width * sizeof(SkColor));
- return;
- }
-
- // order isn't same, repack each pixel manually
- SkPMColor* d = (SkPMColor*)dst;
- for (int i = 0; i < width; i++) {
- SkColor c = *src++;
- *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
- SkColorGetG(c), SkColorGetB(c));
- }
-}
-
-static void FromColor_D565(void* dst, const SkColor src[], int width,
- int x, int y) {
- uint16_t* d = (uint16_t*)dst;
-
- DITHER_565_SCAN(y);
- for (int stop = x + width; x < stop; x++) {
- SkColor c = *src++;
- *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
- DITHER_VALUE(x));
- }
-}
-
-static void FromColor_D4444(void* dst, const SkColor src[], int width,
- int x, int y) {
- SkPMColor16* d = (SkPMColor16*)dst;
-
- DITHER_4444_SCAN(y);
- for (int stop = x + width; x < stop; x++) {
- SkPMColor pmc = SkPreMultiplyColor(*src++);
- *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
-// *d++ = SkPixel32ToPixel4444(pmc);
- }
-}
-
-static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,
- int x, int y) {
- SkPMColor16* d = (SkPMColor16*)dst;
-
- DITHER_4444_SCAN(y);
- for (int stop = x + width; x < stop; x++) {
- SkColor c = *src++;
-
- // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied
- SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
- SkColorGetG(c), SkColorGetB(c));
- *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
-// *d++ = SkPixel32ToPixel4444(pmc);
- }
-}
-
-// can return NULL
-static FromColorProc ChooseFromColorProc(SkBitmap::Config config, bool isPremultiplied) {
- switch (config) {
- case SkBitmap::kARGB_8888_Config:
- return isPremultiplied ? FromColor_D32 : FromColor_D32_Raw;
- case SkBitmap::kARGB_4444_Config:
- return isPremultiplied ? FromColor_D4444 : FromColor_D4444_Raw;
- case SkBitmap::kRGB_565_Config:
- return FromColor_D565;
- default:
- break;
- }
- return NULL;
-}
-
-bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
- int x, int y, int width, int height,
- const SkBitmap& dstBitmap, bool isPremultiplied) {
- SkAutoLockPixels alp(dstBitmap);
- void* dst = dstBitmap.getPixels();
- FromColorProc proc = ChooseFromColorProc(dstBitmap.config(), isPremultiplied);
-
- if (NULL == dst || NULL == proc) {
- return false;
- }
-
- const jint* array = env->GetIntArrayElements(srcColors, NULL);
- const SkColor* src = (const SkColor*)array + srcOffset;
-
- // reset to to actual choice from caller
- dst = dstBitmap.getAddr(x, y);
- // now copy/convert each scanline
- for (int y = 0; y < height; y++) {
- proc(dst, src, width, x, y);
- src += srcStride;
- dst = (char*)dst + dstBitmap.rowBytes();
- }
-
- dstBitmap.notifyPixelsChanged();
-
- env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
- JNI_ABORT);
- return true;
-}
-
-//////////////////// ToColor procs
-
-typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
- SkColorTable*);
-
-static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const SkPMColor* s = (const SkPMColor*)src;
- do {
- *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
- } while (--width != 0);
-}
-
-static void ToColor_S32_Raw(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const SkPMColor* s = (const SkPMColor*)src;
- do {
- SkPMColor c = *s++;
- *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
- SkGetPackedG32(c), SkGetPackedB32(c));
- } while (--width != 0);
-}
-
-static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const SkPMColor* s = (const SkPMColor*)src;
- do {
- SkPMColor c = *s++;
- *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
- SkGetPackedB32(c));
- } while (--width != 0);
-}
-
-static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const SkPMColor16* s = (const SkPMColor16*)src;
- do {
- *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
- } while (--width != 0);
-}
-
-static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const SkPMColor16* s = (const SkPMColor16*)src;
- do {
- SkPMColor c = SkPixel4444ToPixel32(*s++);
- *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
- SkGetPackedG32(c), SkGetPackedB32(c));
- } while (--width != 0);
-}
-
-static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const SkPMColor16* s = (const SkPMColor16*)src;
- do {
- SkPMColor c = SkPixel4444ToPixel32(*s++);
- *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
- SkGetPackedB32(c));
- } while (--width != 0);
-}
-
-static void ToColor_S565(SkColor dst[], const void* src, int width,
- SkColorTable*) {
- SkASSERT(width > 0);
- const uint16_t* s = (const uint16_t*)src;
- do {
- uint16_t c = *s++;
- *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
- SkPacked16ToB32(c));
- } while (--width != 0);
-}
-
-static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
- SkColorTable* ctable) {
- SkASSERT(width > 0);
- const uint8_t* s = (const uint8_t*)src;
- const SkPMColor* colors = ctable->lockColors();
- do {
- *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
- } while (--width != 0);
- ctable->unlockColors();
-}
-
-static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width,
- SkColorTable* ctable) {
- SkASSERT(width > 0);
- const uint8_t* s = (const uint8_t*)src;
- const SkPMColor* colors = ctable->lockColors();
- do {
- SkPMColor c = colors[*s++];
- *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
- SkGetPackedG32(c), SkGetPackedB32(c));
- } while (--width != 0);
- ctable->unlockColors();
-}
-
-static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
- SkColorTable* ctable) {
- SkASSERT(width > 0);
- const uint8_t* s = (const uint8_t*)src;
- const SkPMColor* colors = ctable->lockColors();
- do {
- SkPMColor c = colors[*s++];
- *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
- SkGetPackedB32(c));
- } while (--width != 0);
- ctable->unlockColors();
-}
-
-// can return NULL
-static ToColorProc ChooseToColorProc(const SkBitmap& src, bool isPremultiplied) {
- switch (src.config()) {
- case SkBitmap::kARGB_8888_Config:
- if (src.isOpaque()) return ToColor_S32_Opaque;
- return isPremultiplied ? ToColor_S32_Alpha : ToColor_S32_Raw;
- case SkBitmap::kARGB_4444_Config:
- if (src.isOpaque()) return ToColor_S4444_Opaque;
- return isPremultiplied ? ToColor_S4444_Alpha : ToColor_S4444_Raw;
- case SkBitmap::kRGB_565_Config:
- return ToColor_S565;
- case SkBitmap::kIndex8_Config:
- if (src.getColorTable() == NULL) {
- return NULL;
- }
- if (src.isOpaque()) return ToColor_SI8_Opaque;
- return isPremultiplied ? ToColor_SI8_Raw : ToColor_SI8_Alpha;
- default:
- break;
- }
- return NULL;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-static int getPremulBitmapCreateFlags(bool isMutable) {
- int flags = GraphicsJNI::kBitmapCreateFlag_Premultiplied;
- if (isMutable) flags |= GraphicsJNI::kBitmapCreateFlag_Mutable;
- return flags;
-}
-
-static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
- jint offset, jint stride, jint width, jint height,
- jint configHandle, jboolean isMutable) {
- SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle);
- if (NULL != jColors) {
- size_t n = env->GetArrayLength(jColors);
- if (n < SkAbs32(stride) * (size_t)height) {
- doThrowAIOOBE(env);
- return NULL;
- }
- }
-
- // ARGB_4444 is a deprecated format, convert automatically to 8888
- if (config == SkBitmap::kARGB_4444_Config) {
- config = SkBitmap::kARGB_8888_Config;
- }
-
- SkBitmap bitmap;
- bitmap.setConfig(config, width, height);
-
- jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
- if (NULL == buff) {
- return NULL;
- }
-
- if (jColors != NULL) {
- GraphicsJNI::SetPixels(env, jColors, offset, stride,
- 0, 0, width, height, bitmap, true);
- }
-
- return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff,
- getPremulBitmapCreateFlags(isMutable), NULL, NULL);
-}
-
-static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
- jint dstConfigHandle, jboolean isMutable) {
- const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle);
- SkBitmap::Config dstConfig = static_cast<SkBitmap::Config>(dstConfigHandle);
- SkBitmap result;
- JavaPixelAllocator allocator(env);
-
+#include "SkBitmap.h"
+#include "SkPixelRef.h"
+#include "SkImageEncoder.h"
+#include "SkColorPriv.h"
+#include "GraphicsJNI.h"
+#include "SkDither.h"
+#include "SkUnPreMultiply.h"
+#include "SkStream.h"
+
+#include <binder/Parcel.h>
+#include "android_os_Parcel.h"
+#include "android_util_Binder.h"
+#include "android_nio_utils.h"
+#include "CreateJavaOutputStreamAdaptor.h"
+
+#include <jni.h>
+
+#include <Caches.h>
+
+#if 0
+ #define TRACE_BITMAP(code) code
+#else
+ #define TRACE_BITMAP(code)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Conversions to/from SkColor, for get/setPixels, and the create method, which
+// is basically like setPixels
+
+typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
+ int x, int y);
+
+static void FromColor_D32(void* dst, const SkColor src[], int width,
+ int, int) {
+ SkPMColor* d = (SkPMColor*)dst;
+
+ for (int i = 0; i < width; i++) {
+ *d++ = SkPreMultiplyColor(*src++);
+ }
+}
+
+static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,
+ int, int) {
+ // SkColor's ordering may be different from SkPMColor
+ if (SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER) {
+ memcpy(dst, src, width * sizeof(SkColor));
+ return;
+ }
+
+ // order isn't same, repack each pixel manually
+ SkPMColor* d = (SkPMColor*)dst;
+ for (int i = 0; i < width; i++) {
+ SkColor c = *src++;
+ *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
+ SkColorGetG(c), SkColorGetB(c));
+ }
+}
+
+static void FromColor_D565(void* dst, const SkColor src[], int width,
+ int x, int y) {
+ uint16_t* d = (uint16_t*)dst;
+
+ DITHER_565_SCAN(y);
+ for (int stop = x + width; x < stop; x++) {
+ SkColor c = *src++;
+ *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
+ DITHER_VALUE(x));
+ }
+}
+
+static void FromColor_D4444(void* dst, const SkColor src[], int width,
+ int x, int y) {
+ SkPMColor16* d = (SkPMColor16*)dst;
+
+ DITHER_4444_SCAN(y);
+ for (int stop = x + width; x < stop; x++) {
+ SkPMColor pmc = SkPreMultiplyColor(*src++);
+ *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
+// *d++ = SkPixel32ToPixel4444(pmc);
+ }
+}
+
+static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,
+ int x, int y) {
+ SkPMColor16* d = (SkPMColor16*)dst;
+
+ DITHER_4444_SCAN(y);
+ for (int stop = x + width; x < stop; x++) {
+ SkColor c = *src++;
+
+ // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied
+ SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
+ SkColorGetG(c), SkColorGetB(c));
+ *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
+// *d++ = SkPixel32ToPixel4444(pmc);
+ }
+}
+
+// can return NULL
+static FromColorProc ChooseFromColorProc(SkBitmap::Config config, bool isPremultiplied) {
+ switch (config) {
+ case SkBitmap::kARGB_8888_Config:
+ return isPremultiplied ? FromColor_D32 : FromColor_D32_Raw;
+ case SkBitmap::kARGB_4444_Config:
+ return isPremultiplied ? FromColor_D4444 : FromColor_D4444_Raw;
+ case SkBitmap::kRGB_565_Config:
+ return FromColor_D565;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
+ int x, int y, int width, int height,
+ const SkBitmap& dstBitmap, bool isPremultiplied) {
+ SkAutoLockPixels alp(dstBitmap);
+ void* dst = dstBitmap.getPixels();
+ FromColorProc proc = ChooseFromColorProc(dstBitmap.config(), isPremultiplied);
+
+ if (NULL == dst || NULL == proc) {
+ return false;
+ }
+
+ const jint* array = env->GetIntArrayElements(srcColors, NULL);
+ const SkColor* src = (const SkColor*)array + srcOffset;
+
+ // reset to to actual choice from caller
+ dst = dstBitmap.getAddr(x, y);
+ // now copy/convert each scanline
+ for (int y = 0; y < height; y++) {
+ proc(dst, src, width, x, y);
+ src += srcStride;
+ dst = (char*)dst + dstBitmap.rowBytes();
+ }
+
+ dstBitmap.notifyPixelsChanged();
+
+ env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
+ JNI_ABORT);
+ return true;
+}
+
+//////////////////// ToColor procs
+
+typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
+ SkColorTable*);
+
+static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
+ SkColorTable*) {
+ SkASSERT(width > 0);
+ const SkPMColor* s = (const SkPMColor*)src;
+ do {
+ *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
+ } while (--width != 0);
+}
+
+static void ToColor_S32_Raw(SkColor dst[], const void* src, int width,
+ SkColorTable*) {
+ SkASSERT(width > 0);
+ const SkPMColor* s = (const SkPMColor*)src;
+ do {
+ SkPMColor c = *s++;
+ *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
+ SkGetPackedG32(c), SkGetPackedB32(c));
+ } while (--width != 0);
+}
+
+static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
+ SkColorTable*) {
+ SkASSERT(width > 0);
+ const SkPMColor* s = (const SkPMColor*)src;
+ do {
+ SkPMColor c = *s++;
+ *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
+ SkGetPackedB32(c));
+ } while (--width != 0);
+}
+
+static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
+ SkColorTable*) {
+ SkASSERT(width > 0);
+ const SkPMColor16* s = (const SkPMColor16*)src;
+ do {
+ *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
+ } while (--width != 0);
+}
+
+static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width,
+ SkColorTable*) {
+ SkASSERT(width > 0);
+ const SkPMColor16* s = (const SkPMColor16*)src;
+ do {
+ SkPMColor c = SkPixel4444ToPixel32(*s++);
+ *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
+ SkGetPackedG32(c), SkGetPackedB32(c));
+ } while (--width != 0);
+}
+
+static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
+ SkColorTable*) {
+ SkASSERT(width > 0);
+ const SkPMColor16* s = (const SkPMColor16*)src;
+ do {
+ SkPMColor c = SkPixel4444ToPixel32(*s++);
+ *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
+ SkGetPackedB32(c));
+ } while (--width != 0);
+}
+
+static void ToColor_S565(SkColor dst[], const void* src, int width,
+ SkColorTable*) {
+ SkASSERT(width > 0);
+ const uint16_t* s = (const uint16_t*)src;
+ do {
+ uint16_t c = *s++;
+ *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
+ SkPacked16ToB32(c));
+ } while (--width != 0);
+}
+
+static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
+ SkColorTable* ctable) {
+ SkASSERT(width > 0);
+ const uint8_t* s = (const uint8_t*)src;
+ const SkPMColor* colors = ctable->lockColors();
+ do {
+ *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
+ } while (--width != 0);
+ ctable->unlockColors();
+}
+
+static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width,
+ SkColorTable* ctable) {
+ SkASSERT(width > 0);
+ const uint8_t* s = (const uint8_t*)src;
+ const SkPMColor* colors = ctable->lockColors();
+ do {
+ SkPMColor c = colors[*s++];
+ *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
+ SkGetPackedG32(c), SkGetPackedB32(c));
+ } while (--width != 0);
+ ctable->unlockColors();
+}
+
+static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
+ SkColorTable* ctable) {
+ SkASSERT(width > 0);
+ const uint8_t* s = (const uint8_t*)src;
+ const SkPMColor* colors = ctable->lockColors();
+ do {
+ SkPMColor c = colors[*s++];
+ *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
+ SkGetPackedB32(c));
+ } while (--width != 0);
+ ctable->unlockColors();
+}
+
+// can return NULL
+static ToColorProc ChooseToColorProc(const SkBitmap& src, bool isPremultiplied) {
+ switch (src.config()) {
+ case SkBitmap::kARGB_8888_Config:
+ if (src.isOpaque()) return ToColor_S32_Opaque;
+ return isPremultiplied ? ToColor_S32_Alpha : ToColor_S32_Raw;
+ case SkBitmap::kARGB_4444_Config:
+ if (src.isOpaque()) return ToColor_S4444_Opaque;
+ return isPremultiplied ? ToColor_S4444_Alpha : ToColor_S4444_Raw;
+ case SkBitmap::kRGB_565_Config:
+ return ToColor_S565;
+ case SkBitmap::kIndex8_Config:
+ if (src.getColorTable() == NULL) {
+ return NULL;
+ }
+ if (src.isOpaque()) return ToColor_SI8_Opaque;
+ return isPremultiplied ? ToColor_SI8_Raw : ToColor_SI8_Alpha;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static int getPremulBitmapCreateFlags(bool isMutable) {
+ int flags = GraphicsJNI::kBitmapCreateFlag_Premultiplied;
+ if (isMutable) flags |= GraphicsJNI::kBitmapCreateFlag_Mutable;
+ return flags;
+}
+
+static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
+ jint offset, jint stride, jint width, jint height,
+ jint configHandle, jboolean isMutable) {
+ SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle);
+ if (NULL != jColors) {
+ size_t n = env->GetArrayLength(jColors);
+ if (n < SkAbs32(stride) * (size_t)height) {
+ doThrowAIOOBE(env);
+ return NULL;
+ }
+ }
+
+ // ARGB_4444 is a deprecated format, convert automatically to 8888
+ if (config == SkBitmap::kARGB_4444_Config) {
+ config = SkBitmap::kARGB_8888_Config;
+ }
+
+ SkBitmap bitmap;
+ bitmap.setConfig(config, width, height);
+
+ jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
+ if (NULL == buff) {
+ return NULL;
+ }
+
+ if (jColors != NULL) {
+ GraphicsJNI::SetPixels(env, jColors, offset, stride,
+ 0, 0, width, height, bitmap, true);
+ }
+
+ return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff,
+ getPremulBitmapCreateFlags(isMutable), NULL, NULL);
+}
+
+static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
+ jint dstConfigHandle, jboolean isMutable) {
+ const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle);
+ SkBitmap::Config dstConfig = static_cast<SkBitmap::Config>(dstConfigHandle);
+ SkBitmap result;
+ JavaPixelAllocator allocator(env);
+
if (!src->copyTo(&result, SkBitmapConfigToColorType(dstConfig), &allocator)) {
- return NULL;
- }
- return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(),
- getPremulBitmapCreateFlags(isMutable), NULL, NULL);
-}
-
-static void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
-#ifdef USE_OPENGL_RENDERER
- if (android::uirenderer::Caches::hasInstance()) {
- android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap);
- return;
- }
-#endif // USE_OPENGL_RENDERER
- delete bitmap;
-}
-
-static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
-#ifdef USE_OPENGL_RENDERER
- if (android::uirenderer::Caches::hasInstance()) {
- bool result;
- result = android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap);
- return result ? JNI_TRUE : JNI_FALSE;
- }
-#endif // USE_OPENGL_RENDERER
- bitmap->setPixels(NULL, NULL);
- return JNI_TRUE;
-}
-
-static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
- jint width, jint height, jint configHandle, jint allocSize) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle);
- if (width * height * SkBitmap::ComputeBytesPerPixel(config) > allocSize) {
- // done in native as there's no way to get BytesPerPixel in Java
- doThrowIAE(env, "Bitmap not large enough to support new configuration");
- return;
- }
- SkPixelRef* ref = bitmap->pixelRef();
- SkSafeRef(ref);
- bitmap->setConfig(config, width, height);
- bitmap->setPixelRef(ref);
-
- // notifyPixelsChanged will increment the generation ID even though the actual pixel data
- // hasn't been touched. This signals the renderer that the bitmap (including width, height,
- // and config) has changed.
- ref->notifyPixelsChanged();
- SkSafeUnref(ref);
-}
-
-// These must match the int values in Bitmap.java
-enum JavaEncodeFormat {
- kJPEG_JavaEncodeFormat = 0,
- kPNG_JavaEncodeFormat = 1,
- kWEBP_JavaEncodeFormat = 2
-};
-
-static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
- jint format, jint quality,
- jobject jstream, jbyteArray jstorage) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- SkImageEncoder::Type fm;
-
- switch (format) {
- case kJPEG_JavaEncodeFormat:
- fm = SkImageEncoder::kJPEG_Type;
- break;
- case kPNG_JavaEncodeFormat:
- fm = SkImageEncoder::kPNG_Type;
- break;
- case kWEBP_JavaEncodeFormat:
- fm = SkImageEncoder::kWEBP_Type;
- break;
- default:
- return JNI_FALSE;
- }
-
- bool success = false;
- if (NULL != bitmap) {
- SkAutoLockPixels alp(*bitmap);
-
- if (NULL == bitmap->getPixels()) {
- return JNI_FALSE;
- }
-
- SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
- if (NULL == strm) {
- return JNI_FALSE;
- }
-
- SkImageEncoder* encoder = SkImageEncoder::Create(fm);
- if (NULL != encoder) {
- success = encoder->encodeStream(strm, *bitmap, quality);
- delete encoder;
- }
- delete strm;
- }
- return success ? JNI_TRUE : JNI_FALSE;
-}
-
-static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- bitmap->eraseColor(color);
-}
-
-static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- return static_cast<jint>(bitmap->rowBytes());
-}
-
-static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- return static_cast<jint>(bitmap->config());
-}
-
-static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- return static_cast<jint>(bitmap->getGenerationID());
-}
-
-static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- return !bitmap->isOpaque() ? JNI_TRUE : JNI_FALSE;
-}
-
-static void Bitmap_setAlphaAndPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
- jboolean hasAlpha, jboolean isPremul) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- if (!hasAlpha) {
- bitmap->setAlphaType(kOpaque_SkAlphaType);
- } else if (isPremul) {
- bitmap->setAlphaType(kPremul_SkAlphaType);
- } else {
- bitmap->setAlphaType(kUnpremul_SkAlphaType);
- }
-}
-
-static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
-}
-
-static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
- jboolean hasMipMap) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- bitmap->setHasHardwareMipMap(hasMipMap);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
- if (parcel == NULL) {
- SkDebugf("-------- unparcel parcel is NULL\n");
- return NULL;
- }
-
- android::Parcel* p = android::parcelForJavaObject(env, parcel);
-
- const bool isMutable = p->readInt32() != 0;
- const SkBitmap::Config config = (SkBitmap::Config)p->readInt32();
- const int width = p->readInt32();
- const int height = p->readInt32();
- const int rowBytes = p->readInt32();
- const int density = p->readInt32();
-
- if (SkBitmap::kARGB_8888_Config != config &&
- SkBitmap::kRGB_565_Config != config &&
- SkBitmap::kARGB_4444_Config != config &&
- SkBitmap::kIndex8_Config != config &&
- SkBitmap::kA8_Config != config) {
- SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config);
- return NULL;
- }
-
- SkBitmap* bitmap = new SkBitmap;
-
- bitmap->setConfig(config, width, height, rowBytes);
-
- SkColorTable* ctable = NULL;
- if (config == SkBitmap::kIndex8_Config) {
- int count = p->readInt32();
- if (count > 0) {
- size_t size = count * sizeof(SkPMColor);
- const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
- ctable = new SkColorTable(src, count);
- }
- }
-
- jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
- if (NULL == buffer) {
- SkSafeUnref(ctable);
- delete bitmap;
- return NULL;
- }
-
- SkSafeUnref(ctable);
-
- size_t size = bitmap->getSize();
-
- android::Parcel::ReadableBlob blob;
- android::status_t status = p->readBlob(size, &blob);
- if (status) {
- doThrowRE(env, "Could not read bitmap from parcel blob.");
- delete bitmap;
- return NULL;
- }
-
- bitmap->lockPixels();
- memcpy(bitmap->getPixels(), blob.data(), size);
- bitmap->unlockPixels();
-
- blob.release();
-
- return GraphicsJNI::createBitmap(env, bitmap, buffer, getPremulBitmapCreateFlags(isMutable),
- NULL, NULL, density);
-}
-
-static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
- jlong bitmapHandle,
- jboolean isMutable, jint density,
- jobject parcel) {
- const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- if (parcel == NULL) {
- SkDebugf("------- writeToParcel null parcel\n");
- return JNI_FALSE;
- }
-
- android::Parcel* p = android::parcelForJavaObject(env, parcel);
-
- p->writeInt32(isMutable);
- p->writeInt32(bitmap->config());
- p->writeInt32(bitmap->width());
- p->writeInt32(bitmap->height());
- p->writeInt32(bitmap->rowBytes());
- p->writeInt32(density);
-
- if (bitmap->config() == SkBitmap::kIndex8_Config) {
- SkColorTable* ctable = bitmap->getColorTable();
- if (ctable != NULL) {
- int count = ctable->count();
- p->writeInt32(count);
- memcpy(p->writeInplace(count * sizeof(SkPMColor)),
- ctable->lockColors(), count * sizeof(SkPMColor));
- ctable->unlockColors();
- } else {
- p->writeInt32(0); // indicate no ctable
- }
- }
-
- size_t size = bitmap->getSize();
-
- android::Parcel::WritableBlob blob;
- android::status_t status = p->writeBlob(size, &blob);
- if (status) {
- doThrowRE(env, "Could not write bitmap to parcel blob.");
- return JNI_FALSE;
- }
-
- bitmap->lockPixels();
- const void* pSrc = bitmap->getPixels();
- if (pSrc == NULL) {
- memset(blob.data(), 0, size);
- } else {
- memcpy(blob.data(), pSrc, size);
- }
- bitmap->unlockPixels();
-
- blob.release();
- return JNI_TRUE;
-}
-
-static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
- jlong srcHandle, jlong paintHandle,
- jintArray offsetXY) {
- const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle);
- const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
- SkIPoint offset;
- SkBitmap* dst = new SkBitmap;
- JavaPixelAllocator allocator(env);
-
- src->extractAlpha(dst, paint, &allocator, &offset);
- // If Skia can't allocate pixels for destination bitmap, it resets
- // it, that is set its pixels buffer to NULL, and zero width and height.
- if (dst->getPixels() == NULL && src->getPixels() != NULL) {
- delete dst;
- doThrowOOME(env, "failed to allocate pixels for alpha");
- return NULL;
- }
- if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
- int* array = env->GetIntArrayElements(offsetXY, NULL);
- array[0] = offset.fX;
- array[1] = offset.fY;
- env->ReleaseIntArrayElements(offsetXY, array, 0);
- }
-
- return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(),
- getPremulBitmapCreateFlags(true), NULL, NULL);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
- jint x, jint y, jboolean isPremultiplied) {
- const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- SkAutoLockPixels alp(*bitmap);
-
- ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
- if (NULL == proc) {
- return 0;
- }
- const void* src = bitmap->getAddr(x, y);
- if (NULL == src) {
- return 0;
- }
-
- SkColor dst[1];
- proc(dst, src, 1, bitmap->getColorTable());
- return static_cast<jint>(dst[0]);
-}
-
-static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
- jintArray pixelArray, jint offset, jint stride,
- jint x, jint y, jint width, jint height, jboolean isPremultiplied) {
- const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- SkAutoLockPixels alp(*bitmap);
-
- ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
- if (NULL == proc) {
- return;
- }
- const void* src = bitmap->getAddr(x, y);
- if (NULL == src) {
- return;
- }
-
- SkColorTable* ctable = bitmap->getColorTable();
- jint* dst = env->GetIntArrayElements(pixelArray, NULL);
- SkColor* d = (SkColor*)dst + offset;
- while (--height >= 0) {
- proc(d, src, width, ctable);
- d += stride;
- src = (void*)((const char*)src + bitmap->rowBytes());
- }
- env->ReleaseIntArrayElements(pixelArray, dst, 0);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
- jint x, jint y, jint colorHandle, jboolean isPremultiplied) {
- const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- SkColor color = static_cast<SkColor>(colorHandle);
- SkAutoLockPixels alp(*bitmap);
- if (NULL == bitmap->getPixels()) {
- return;
- }
-
- FromColorProc proc = ChooseFromColorProc(bitmap->config(), isPremultiplied);
- if (NULL == proc) {
- return;
- }
-
- proc(bitmap->getAddr(x, y), &color, 1, x, y);
- bitmap->notifyPixelsChanged();
-}
-
-static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
- jintArray pixelArray, jint offset, jint stride,
- jint x, jint y, jint width, jint height, jboolean isPremultiplied) {
- const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
- x, y, width, height, *bitmap, isPremultiplied);
-}
-
-static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
- jlong bitmapHandle, jobject jbuffer) {
- const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- SkAutoLockPixels alp(*bitmap);
- const void* src = bitmap->getPixels();
-
- if (NULL != src) {
- android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
-
- // the java side has already checked that buffer is large enough
- memcpy(abp.pointer(), src, bitmap->getSize());
- }
-}
-
-static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
- jlong bitmapHandle, jobject jbuffer) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- SkAutoLockPixels alp(*bitmap);
- void* dst = bitmap->getPixels();
-
- if (NULL != dst) {
- android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
- // the java side has already checked that buffer is large enough
- memcpy(dst, abp.pointer(), bitmap->getSize());
- bitmap->notifyPixelsChanged();
- }
-}
-
-static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle,
- jlong bm1Handle) {
- const SkBitmap* bm0 = reinterpret_cast<SkBitmap*>(bm0Handle);
- const SkBitmap* bm1 = reinterpret_cast<SkBitmap*>(bm1Handle);
- if (bm0->width() != bm1->width() ||
- bm0->height() != bm1->height() ||
- bm0->config() != bm1->config()) {
- return JNI_FALSE;
- }
-
- SkAutoLockPixels alp0(*bm0);
- SkAutoLockPixels alp1(*bm1);
-
- // if we can't load the pixels, return false
- if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) {
- return JNI_FALSE;
- }
-
- if (bm0->config() == SkBitmap::kIndex8_Config) {
- SkColorTable* ct0 = bm0->getColorTable();
- SkColorTable* ct1 = bm1->getColorTable();
- if (NULL == ct0 || NULL == ct1) {
- return JNI_FALSE;
- }
- if (ct0->count() != ct1->count()) {
- return JNI_FALSE;
- }
-
- SkAutoLockColors alc0(ct0);
- SkAutoLockColors alc1(ct1);
- const size_t size = ct0->count() * sizeof(SkPMColor);
- if (memcmp(alc0.colors(), alc1.colors(), size) != 0) {
- return JNI_FALSE;
- }
- }
-
- // now compare each scanline. We can't do the entire buffer at once,
- // since we don't care about the pixel values that might extend beyond
- // the width (since the scanline might be larger than the logical width)
- const int h = bm0->height();
- const size_t size = bm0->width() * bm0->bytesPerPixel();
- for (int y = 0; y < h; y++) {
- if (memcmp(bm0->getAddr(0, y), bm1->getAddr(0, y), size) != 0) {
- return JNI_FALSE;
- }
- }
- return JNI_TRUE;
-}
-
-static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- bitmap->lockPixels();
- bitmap->unlockPixels();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-#include <android_runtime/AndroidRuntime.h>
-
-static JNINativeMethod gBitmapMethods[] = {
- { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;",
- (void*)Bitmap_creator },
- { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;",
- (void*)Bitmap_copy },
- { "nativeDestructor", "(J)V", (void*)Bitmap_destructor },
- { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle },
- { "nativeReconfigure", "(JIIII)V", (void*)Bitmap_reconfigure },
- { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
- (void*)Bitmap_compress },
- { "nativeErase", "(JI)V", (void*)Bitmap_erase },
- { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
- { "nativeConfig", "(J)I", (void*)Bitmap_config },
- { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
- { "nativeSetAlphaAndPremultiplied", "(JZZ)V", (void*)Bitmap_setAlphaAndPremultiplied},
- { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap },
- { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap },
- { "nativeCreateFromParcel",
- "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
- (void*)Bitmap_createFromParcel },
- { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z",
- (void*)Bitmap_writeToParcel },
- { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;",
- (void*)Bitmap_extractAlpha },
- { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId },
- { "nativeGetPixel", "(JIIZ)I", (void*)Bitmap_getPixel },
- { "nativeGetPixels", "(J[IIIIIIIZ)V", (void*)Bitmap_getPixels },
- { "nativeSetPixel", "(JIIIZ)V", (void*)Bitmap_setPixel },
- { "nativeSetPixels", "(J[IIIIIIIZ)V", (void*)Bitmap_setPixels },
- { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
- (void*)Bitmap_copyPixelsToBuffer },
- { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
- (void*)Bitmap_copyPixelsFromBuffer },
- { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs },
- { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
-};
-
-#define kClassPathName "android/graphics/Bitmap"
-
-int register_android_graphics_Bitmap(JNIEnv* env)
-{
- return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
- gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
-}
+ return NULL;
+ }
+ return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(),
+ getPremulBitmapCreateFlags(isMutable), NULL, NULL);
+}
+
+static void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+#ifdef USE_OPENGL_RENDERER
+ if (android::uirenderer::Caches::hasInstance()) {
+ android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap);
+ return;
+ }
+#endif // USE_OPENGL_RENDERER
+ delete bitmap;
+}
+
+static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+#ifdef USE_OPENGL_RENDERER
+ if (android::uirenderer::Caches::hasInstance()) {
+ bool result;
+ result = android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap);
+ return result ? JNI_TRUE : JNI_FALSE;
+ }
+#endif // USE_OPENGL_RENDERER
+ bitmap->setPixels(NULL, NULL);
+ return JNI_TRUE;
+}
+
+static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
+ jint width, jint height, jint configHandle, jint allocSize) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle);
+ if (width * height * SkBitmap::ComputeBytesPerPixel(config) > allocSize) {
+ // done in native as there's no way to get BytesPerPixel in Java
+ doThrowIAE(env, "Bitmap not large enough to support new configuration");
+ return;
+ }
+ SkPixelRef* ref = bitmap->pixelRef();
+ SkSafeRef(ref);
+ bitmap->setConfig(config, width, height);
+ bitmap->setPixelRef(ref);
+
+ // notifyPixelsChanged will increment the generation ID even though the actual pixel data
+ // hasn't been touched. This signals the renderer that the bitmap (including width, height,
+ // and config) has changed.
+ ref->notifyPixelsChanged();
+ SkSafeUnref(ref);
+}
+
+// These must match the int values in Bitmap.java
+enum JavaEncodeFormat {
+ kJPEG_JavaEncodeFormat = 0,
+ kPNG_JavaEncodeFormat = 1,
+ kWEBP_JavaEncodeFormat = 2
+};
+
+static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
+ jint format, jint quality,
+ jobject jstream, jbyteArray jstorage) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ SkImageEncoder::Type fm;
+
+ switch (format) {
+ case kJPEG_JavaEncodeFormat:
+ fm = SkImageEncoder::kJPEG_Type;
+ break;
+ case kPNG_JavaEncodeFormat:
+ fm = SkImageEncoder::kPNG_Type;
+ break;
+ case kWEBP_JavaEncodeFormat:
+ fm = SkImageEncoder::kWEBP_Type;
+ break;
+ default:
+ return JNI_FALSE;
+ }
+
+ bool success = false;
+ if (NULL != bitmap) {
+ SkAutoLockPixels alp(*bitmap);
+
+ if (NULL == bitmap->getPixels()) {
+ return JNI_FALSE;
+ }
+
+ SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
+ if (NULL == strm) {
+ return JNI_FALSE;
+ }
+
+ SkImageEncoder* encoder = SkImageEncoder::Create(fm);
+ if (NULL != encoder) {
+ success = encoder->encodeStream(strm, *bitmap, quality);
+ delete encoder;
+ }
+ delete strm;
+ }
+ return success ? JNI_TRUE : JNI_FALSE;
+}
+
+static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ bitmap->eraseColor(color);
+}
+
+static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ return static_cast<jint>(bitmap->rowBytes());
+}
+
+static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ return static_cast<jint>(bitmap->config());
+}
+
+static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ return static_cast<jint>(bitmap->getGenerationID());
+}
+
+static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ return !bitmap->isOpaque() ? JNI_TRUE : JNI_FALSE;
+}
+
+static void Bitmap_setAlphaAndPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
+ jboolean hasAlpha, jboolean isPremul) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ if (!hasAlpha) {
+ bitmap->setAlphaType(kOpaque_SkAlphaType);
+ } else if (isPremul) {
+ bitmap->setAlphaType(kPremul_SkAlphaType);
+ } else {
+ bitmap->setAlphaType(kUnpremul_SkAlphaType);
+ }
+}
+
+static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
+}
+
+static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
+ jboolean hasMipMap) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ bitmap->setHasHardwareMipMap(hasMipMap);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
+ if (parcel == NULL) {
+ SkDebugf("-------- unparcel parcel is NULL\n");
+ return NULL;
+ }
+
+ android::Parcel* p = android::parcelForJavaObject(env, parcel);
+
+ const bool isMutable = p->readInt32() != 0;
+ const SkBitmap::Config config = (SkBitmap::Config)p->readInt32();
+ const int width = p->readInt32();
+ const int height = p->readInt32();
+ const int rowBytes = p->readInt32();
+ const int density = p->readInt32();
+
+ if (SkBitmap::kARGB_8888_Config != config &&
+ SkBitmap::kRGB_565_Config != config &&
+ SkBitmap::kARGB_4444_Config != config &&
+ SkBitmap::kIndex8_Config != config &&
+ SkBitmap::kA8_Config != config) {
+ SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config);
+ return NULL;
+ }
+
+ SkBitmap* bitmap = new SkBitmap;
+
+ bitmap->setConfig(config, width, height, rowBytes);
+
+ SkColorTable* ctable = NULL;
+ if (config == SkBitmap::kIndex8_Config) {
+ int count = p->readInt32();
+ if (count > 0) {
+ size_t size = count * sizeof(SkPMColor);
+ const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
+ ctable = new SkColorTable(src, count);
+ }
+ }
+
+ jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
+ if (NULL == buffer) {
+ SkSafeUnref(ctable);
+ delete bitmap;
+ return NULL;
+ }
+
+ SkSafeUnref(ctable);
+
+ size_t size = bitmap->getSize();
+
+ android::Parcel::ReadableBlob blob;
+ android::status_t status = p->readBlob(size, &blob);
+ if (status) {
+ doThrowRE(env, "Could not read bitmap from parcel blob.");
+ delete bitmap;
+ return NULL;
+ }
+
+ bitmap->lockPixels();
+ memcpy(bitmap->getPixels(), blob.data(), size);
+ bitmap->unlockPixels();
+
+ blob.release();
+
+ return GraphicsJNI::createBitmap(env, bitmap, buffer, getPremulBitmapCreateFlags(isMutable),
+ NULL, NULL, density);
+}
+
+static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
+ jlong bitmapHandle,
+ jboolean isMutable, jint density,
+ jobject parcel) {
+ const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ if (parcel == NULL) {
+ SkDebugf("------- writeToParcel null parcel\n");
+ return JNI_FALSE;
+ }
+
+ android::Parcel* p = android::parcelForJavaObject(env, parcel);
+
+ p->writeInt32(isMutable);
+ p->writeInt32(bitmap->config());
+ p->writeInt32(bitmap->width());
+ p->writeInt32(bitmap->height());
+ p->writeInt32(bitmap->rowBytes());
+ p->writeInt32(density);
+
+ if (bitmap->config() == SkBitmap::kIndex8_Config) {
+ SkColorTable* ctable = bitmap->getColorTable();
+ if (ctable != NULL) {
+ int count = ctable->count();
+ p->writeInt32(count);
+ memcpy(p->writeInplace(count * sizeof(SkPMColor)),
+ ctable->lockColors(), count * sizeof(SkPMColor));
+ ctable->unlockColors();
+ } else {
+ p->writeInt32(0); // indicate no ctable
+ }
+ }
+
+ size_t size = bitmap->getSize();
+
+ android::Parcel::WritableBlob blob;
+ android::status_t status = p->writeBlob(size, &blob);
+ if (status) {
+ doThrowRE(env, "Could not write bitmap to parcel blob.");
+ return JNI_FALSE;
+ }
+
+ bitmap->lockPixels();
+ const void* pSrc = bitmap->getPixels();
+ if (pSrc == NULL) {
+ memset(blob.data(), 0, size);
+ } else {
+ memcpy(blob.data(), pSrc, size);
+ }
+ bitmap->unlockPixels();
+
+ blob.release();
+ return JNI_TRUE;
+}
+
+static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
+ jlong srcHandle, jlong paintHandle,
+ jintArray offsetXY) {
+ const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle);
+ const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+ SkIPoint offset;
+ SkBitmap* dst = new SkBitmap;
+ JavaPixelAllocator allocator(env);
+
+ src->extractAlpha(dst, paint, &allocator, &offset);
+ // If Skia can't allocate pixels for destination bitmap, it resets
+ // it, that is set its pixels buffer to NULL, and zero width and height.
+ if (dst->getPixels() == NULL && src->getPixels() != NULL) {
+ delete dst;
+ doThrowOOME(env, "failed to allocate pixels for alpha");
+ return NULL;
+ }
+ if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
+ int* array = env->GetIntArrayElements(offsetXY, NULL);
+ array[0] = offset.fX;
+ array[1] = offset.fY;
+ env->ReleaseIntArrayElements(offsetXY, array, 0);
+ }
+
+ return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(),
+ getPremulBitmapCreateFlags(true), NULL, NULL);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
+ jint x, jint y, jboolean isPremultiplied) {
+ const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ SkAutoLockPixels alp(*bitmap);
+
+ ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
+ if (NULL == proc) {
+ return 0;
+ }
+ const void* src = bitmap->getAddr(x, y);
+ if (NULL == src) {
+ return 0;
+ }
+
+ SkColor dst[1];
+ proc(dst, src, 1, bitmap->getColorTable());
+ return static_cast<jint>(dst[0]);
+}
+
+static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
+ jintArray pixelArray, jint offset, jint stride,
+ jint x, jint y, jint width, jint height, jboolean isPremultiplied) {
+ const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ SkAutoLockPixels alp(*bitmap);
+
+ ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
+ if (NULL == proc) {
+ return;
+ }
+ const void* src = bitmap->getAddr(x, y);
+ if (NULL == src) {
+ return;
+ }
+
+ SkColorTable* ctable = bitmap->getColorTable();
+ jint* dst = env->GetIntArrayElements(pixelArray, NULL);
+ SkColor* d = (SkColor*)dst + offset;
+ while (--height >= 0) {
+ proc(d, src, width, ctable);
+ d += stride;
+ src = (void*)((const char*)src + bitmap->rowBytes());
+ }
+ env->ReleaseIntArrayElements(pixelArray, dst, 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
+ jint x, jint y, jint colorHandle, jboolean isPremultiplied) {
+ const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ SkColor color = static_cast<SkColor>(colorHandle);
+ SkAutoLockPixels alp(*bitmap);
+ if (NULL == bitmap->getPixels()) {
+ return;
+ }
+
+ FromColorProc proc = ChooseFromColorProc(bitmap->config(), isPremultiplied);
+ if (NULL == proc) {
+ return;
+ }
+
+ proc(bitmap->getAddr(x, y), &color, 1, x, y);
+ bitmap->notifyPixelsChanged();
+}
+
+static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
+ jintArray pixelArray, jint offset, jint stride,
+ jint x, jint y, jint width, jint height, jboolean isPremultiplied) {
+ const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
+ x, y, width, height, *bitmap, isPremultiplied);
+}
+
+static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
+ jlong bitmapHandle, jobject jbuffer) {
+ const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ SkAutoLockPixels alp(*bitmap);
+ const void* src = bitmap->getPixels();
+
+ if (NULL != src) {
+ android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
+
+ // the java side has already checked that buffer is large enough
+ memcpy(abp.pointer(), src, bitmap->getSize());
+ }
+}
+
+static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
+ jlong bitmapHandle, jobject jbuffer) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ SkAutoLockPixels alp(*bitmap);
+ void* dst = bitmap->getPixels();
+
+ if (NULL != dst) {
+ android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
+ // the java side has already checked that buffer is large enough
+ memcpy(dst, abp.pointer(), bitmap->getSize());
+ bitmap->notifyPixelsChanged();
+ }
+}
+
+static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle,
+ jlong bm1Handle) {
+ const SkBitmap* bm0 = reinterpret_cast<SkBitmap*>(bm0Handle);
+ const SkBitmap* bm1 = reinterpret_cast<SkBitmap*>(bm1Handle);
+ if (bm0->width() != bm1->width() ||
+ bm0->height() != bm1->height() ||
+ bm0->config() != bm1->config()) {
+ return JNI_FALSE;
+ }
+
+ SkAutoLockPixels alp0(*bm0);
+ SkAutoLockPixels alp1(*bm1);
+
+ // if we can't load the pixels, return false
+ if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) {
+ return JNI_FALSE;
+ }
+
+ if (bm0->config() == SkBitmap::kIndex8_Config) {
+ SkColorTable* ct0 = bm0->getColorTable();
+ SkColorTable* ct1 = bm1->getColorTable();
+ if (NULL == ct0 || NULL == ct1) {
+ return JNI_FALSE;
+ }
+ if (ct0->count() != ct1->count()) {
+ return JNI_FALSE;
+ }
+
+ SkAutoLockColors alc0(ct0);
+ SkAutoLockColors alc1(ct1);
+ const size_t size = ct0->count() * sizeof(SkPMColor);
+ if (memcmp(alc0.colors(), alc1.colors(), size) != 0) {
+ return JNI_FALSE;
+ }
+ }
+
+ // now compare each scanline. We can't do the entire buffer at once,
+ // since we don't care about the pixel values that might extend beyond
+ // the width (since the scanline might be larger than the logical width)
+ const int h = bm0->height();
+ const size_t size = bm0->width() * bm0->bytesPerPixel();
+ for (int y = 0; y < h; y++) {
+ if (memcmp(bm0->getAddr(0, y), bm1->getAddr(0, y), size) != 0) {
+ return JNI_FALSE;
+ }
+ }
+ return JNI_TRUE;
+}
+
+static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapHandle) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+ bitmap->lockPixels();
+ bitmap->unlockPixels();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include <android_runtime/AndroidRuntime.h>
+
+static JNINativeMethod gBitmapMethods[] = {
+ { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;",
+ (void*)Bitmap_creator },
+ { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;",
+ (void*)Bitmap_copy },
+ { "nativeDestructor", "(J)V", (void*)Bitmap_destructor },
+ { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle },
+ { "nativeReconfigure", "(JIIII)V", (void*)Bitmap_reconfigure },
+ { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
+ (void*)Bitmap_compress },
+ { "nativeErase", "(JI)V", (void*)Bitmap_erase },
+ { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
+ { "nativeConfig", "(J)I", (void*)Bitmap_config },
+ { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
+ { "nativeSetAlphaAndPremultiplied", "(JZZ)V", (void*)Bitmap_setAlphaAndPremultiplied},
+ { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap },
+ { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap },
+ { "nativeCreateFromParcel",
+ "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
+ (void*)Bitmap_createFromParcel },
+ { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z",
+ (void*)Bitmap_writeToParcel },
+ { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;",
+ (void*)Bitmap_extractAlpha },
+ { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId },
+ { "nativeGetPixel", "(JIIZ)I", (void*)Bitmap_getPixel },
+ { "nativeGetPixels", "(J[IIIIIIIZ)V", (void*)Bitmap_getPixels },
+ { "nativeSetPixel", "(JIIIZ)V", (void*)Bitmap_setPixel },
+ { "nativeSetPixels", "(J[IIIIIIIZ)V", (void*)Bitmap_setPixels },
+ { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
+ (void*)Bitmap_copyPixelsToBuffer },
+ { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
+ (void*)Bitmap_copyPixelsFromBuffer },
+ { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs },
+ { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
+};
+
+#define kClassPathName "android/graphics/Bitmap"
+
+int register_android_graphics_Bitmap(JNIEnv* env)
+{
+ return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
+ gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
+}
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 2adbf3a..f7acbd7 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -30,6 +30,7 @@
#ifdef USE_MINIKIN
#include <minikin/Layout.h>
#include "MinikinSkia.h"
+#include "MinikinUtils.h"
#endif
#include "TextLayout.h"
@@ -820,7 +821,7 @@
}
#ifdef USE_MINIKIN
- static void drawGlyphsToSkia(SkCanvas *canvas, SkPaint *paint, Layout *layout, float x, float y) {
+ static void drawGlyphsToSkia(SkCanvas* canvas, SkPaint* paint, Layout* layout, float x, float y) {
size_t nGlyphs = layout->nGlyphs();
uint16_t *glyphs = new uint16_t[nGlyphs];
SkPoint *pos = new SkPoint[nGlyphs];
@@ -865,15 +866,7 @@
#ifdef USE_MINIKIN
Layout layout;
- TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
- layout.setFontCollection(resolvedFace->fFontCollection);
- FontStyle style = resolvedFace->fStyle;
- char css[256];
- sprintf(css, "font-size: %d; font-weight: %d; font-style: %s",
- (int)paint->getTextSize(),
- style.getWeight() * 100,
- style.getItalic() ? "italic" : "normal");
- layout.setProperties(css);
+ MinikinUtils::SetLayoutProperties(&layout, paint, flags, typeface);
layout.doLayout(textArray + start, count);
drawGlyphsToSkia(canvas, paint, &layout, x, y);
#else
diff --git a/core/jni/android/graphics/CanvasProperty.cpp b/core/jni/android/graphics/CanvasProperty.cpp
index 70e2db5..cfa9cd8 100644
--- a/core/jni/android/graphics/CanvasProperty.cpp
+++ b/core/jni/android/graphics/CanvasProperty.cpp
@@ -18,7 +18,7 @@
#include "GraphicsJNI.h"
#include <android_runtime/AndroidRuntime.h>
-#include <utils/VirtualLightRefBase.h>
+#include <utils/RefBase.h>
#include <CanvasProperty.h>
namespace android {
@@ -27,22 +27,13 @@
#ifdef USE_OPENGL_RENDERER
-static jlong incRef(VirtualLightRefBase* ptr) {
- ptr->incStrong(0);
- return reinterpret_cast<jlong>(ptr);
-}
-
static jlong createFloat(JNIEnv* env, jobject clazz, jfloat initialValue) {
- return incRef(new CanvasPropertyPrimitive(initialValue));
+ return reinterpret_cast<jlong>(new CanvasPropertyPrimitive(initialValue));
}
static jlong createPaint(JNIEnv* env, jobject clazz, jlong paintPtr) {
const SkPaint* paint = reinterpret_cast<const SkPaint*>(paintPtr);
- return incRef(new CanvasPropertyPaint(*paint));
-}
-
-static void unref(JNIEnv* env, jobject clazz, jlong containerPtr) {
- reinterpret_cast<VirtualLightRefBase*>(containerPtr)->decStrong(0);
+ return reinterpret_cast<jlong>(new CanvasPropertyPaint(*paint));
}
#endif
@@ -57,7 +48,6 @@
#ifdef USE_OPENGL_RENDERER
{ "nCreateFloat", "(F)J", (void*) createFloat },
{ "nCreatePaint", "(J)J", (void*) createPaint },
- { "nUnref", "(J)V", (void*) unref },
#endif
};
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
new file mode 100644
index 0000000..041790f
--- /dev/null
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Minikin"
+
+#include "JNIHelp.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include "SkTypeface.h"
+#include "GraphicsJNI.h"
+#include <ScopedPrimitiveArray.h>
+#include <ScopedUtfChars.h>
+
+#ifdef USE_MINIKIN
+#include <minikin/FontFamily.h>
+#include "MinikinSkia.h"
+#endif
+
+namespace android {
+
+static jlong FontFamily_create(JNIEnv* env, jobject clazz) {
+#ifdef USE_MINIKIN
+ return (jlong)new FontFamily();
+#else
+ return 0;
+#endif
+}
+
+static void FontFamily_unref(JNIEnv* env, jobject clazz, jlong familyPtr) {
+#ifdef USE_MINIKIN
+ FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr);
+ fontFamily->Unref();
+#endif
+}
+
+static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong familyPtr, jstring path) {
+#ifdef USE_MINIKIN
+ NPE_CHECK_RETURN_ZERO(env, path);
+ ScopedUtfChars str(env, path);
+ ALOGD("addFont %s", str.c_str());
+ SkTypeface* face = SkTypeface::CreateFromFile(str.c_str());
+ if (face == NULL) {
+ ALOGE("addFont failed to create font %s", str.c_str());
+ return false;
+ }
+ MinikinFont* minikinFont = new MinikinFontSkia(face);
+ FontFamily* fontFamily = (FontFamily*)familyPtr;
+ return fontFamily->addFont(minikinFont);
+#else
+ return false;
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static JNINativeMethod gFontFamilyMethods[] = {
+ { "nCreateFamily", "()J", (void*)FontFamily_create },
+ { "nUnrefFamily", "(J)V", (void*)FontFamily_unref },
+ { "nAddFont", "(JLjava/lang/String;)Z", (void*)FontFamily_addFont },
+};
+
+int register_android_graphics_FontFamily(JNIEnv* env)
+{
+ return android::AndroidRuntime::registerNativeMethods(env,
+ "android/graphics/FontFamily",
+ gFontFamilyMethods, NELEM(gFontFamilyMethods));
+}
+
+}
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index e4c74b2..ed28c24 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -167,6 +167,7 @@
static jclass gPaint_class;
static jfieldID gPaint_nativeInstanceID;
+static jfieldID gPaint_nativeTypefaceID;
static jclass gPicture_class;
static jfieldID gPicture_nativeInstanceID;
@@ -334,6 +335,16 @@
return p;
}
+android::TypefaceImpl* GraphicsJNI::getNativeTypeface(JNIEnv* env, jobject paint) {
+ SkASSERT(env);
+ SkASSERT(paint);
+ SkASSERT(env->IsInstanceOf(paint, gPaint_class));
+ jlong typefaceHandle = env->GetLongField(paint, gPaint_nativeTypefaceID);
+ android::TypefaceImpl* p = reinterpret_cast<android::TypefaceImpl*>(typefaceHandle);
+ SkASSERT(p);
+ return p;
+}
+
SkPicture* GraphicsJNI::getNativePicture(JNIEnv* env, jobject picture)
{
SkASSERT(env);
@@ -698,6 +709,7 @@
gPaint_class = make_globalref(env, "android/graphics/Paint");
gPaint_nativeInstanceID = getFieldIDCheck(env, gPaint_class, "mNativePaint", "J");
+ gPaint_nativeTypefaceID = getFieldIDCheck(env, gPaint_class, "mNativeTypeface", "J");
gPicture_class = make_globalref(env, "android/graphics/Picture");
gPicture_nativeInstanceID = getFieldIDCheck(env, gPicture_class, "mNativePicture", "J");
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index cb154aa..db7b6d9 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -8,6 +8,7 @@
#include "SkPoint.h"
#include "SkRect.h"
#include "SkImageDecoder.h"
+#include "TypefaceImpl.h"
#include <jni.h>
class SkBitmapRegionDecoder;
@@ -46,10 +47,15 @@
static SkCanvas* getNativeCanvas(JNIEnv*, jobject canvas);
static SkPaint* getNativePaint(JNIEnv*, jobject paint);
+ static android::TypefaceImpl* getNativeTypeface(JNIEnv*, jobject paint);
static SkBitmap* getNativeBitmap(JNIEnv*, jobject bitmap);
static SkPicture* getNativePicture(JNIEnv*, jobject picture);
static SkRegion* getNativeRegion(JNIEnv*, jobject region);
+ // Given the 'native' long held by the Rasterizer.java object, return a
+ // ref to its SkRasterizer* (or NULL).
+ static SkRasterizer* refNativeRasterizer(jlong rasterizerHandle);
+
/** Return the corresponding native config from the java Config enum,
or kNo_Config if the java object is null.
*/
diff --git a/core/jni/android/graphics/LayerRasterizer.cpp b/core/jni/android/graphics/LayerRasterizer.cpp
deleted file mode 100644
index 79dc275..0000000
--- a/core/jni/android/graphics/LayerRasterizer.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-#include "SkLayerRasterizer.h"
-#include <jni.h>
-
-class SkLayerRasterizerGlue {
-public:
- static jlong create(JNIEnv* env, jobject) {
- return reinterpret_cast<jlong>(new SkLayerRasterizer());
- }
-
- static void addLayer(JNIEnv* env, jobject, jlong layerHandle, jlong paintHandle, jfloat dx, jfloat dy) {
- SkLayerRasterizer* layer = reinterpret_cast<SkLayerRasterizer *>(layerHandle);
- const SkPaint* paint = reinterpret_cast<SkPaint *>(paintHandle);
- SkASSERT(layer);
- SkASSERT(paint);
- layer->addLayer(*paint, dx, dy);
- }
-};
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#include <android_runtime/AndroidRuntime.h>
-
-static JNINativeMethod gLayerRasterizerMethods[] = {
- { "nativeConstructor", "()J", (void*)SkLayerRasterizerGlue::create },
- { "nativeAddLayer", "(JJFF)V", (void*)SkLayerRasterizerGlue::addLayer }
-};
-
-int register_android_graphics_LayerRasterizer(JNIEnv* env)
-{
- return android::AndroidRuntime::registerNativeMethods(env,
- "android/graphics/LayerRasterizer",
- gLayerRasterizerMethods,
- SK_ARRAY_COUNT(gLayerRasterizerMethods));
-}
diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp
index 23af860..cbd20e9 100644
--- a/core/jni/android/graphics/Matrix.cpp
+++ b/core/jni/android/graphics/Matrix.cpp
@@ -50,10 +50,17 @@
SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
return obj->isIdentity() ? JNI_TRUE : JNI_FALSE;
}
+
+ static jboolean isAffine(JNIEnv* env, jobject clazz, jlong objHandle) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ return obj->asAffine(NULL) ? JNI_TRUE : JNI_FALSE;
+ }
+
static jboolean rectStaysRect(JNIEnv* env, jobject clazz, jlong objHandle) {
SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
return obj->rectStaysRect() ? JNI_TRUE : JNI_FALSE;
}
+
static void reset(JNIEnv* env, jobject clazz, jlong objHandle) {
SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
obj->reset();
@@ -302,6 +309,7 @@
{"finalizer", "(J)V", (void*) SkMatrixGlue::finalizer},
{"native_create","(J)J", (void*) SkMatrixGlue::create},
{"native_isIdentity","(J)Z", (void*) SkMatrixGlue::isIdentity},
+ {"native_isAffine","(J)Z", (void*) SkMatrixGlue::isAffine},
{"native_rectStaysRect","(J)Z", (void*) SkMatrixGlue::rectStaysRect},
{"native_reset","(J)V", (void*) SkMatrixGlue::reset},
{"native_set","(JJ)V", (void*) SkMatrixGlue::set},
diff --git a/core/jni/android/graphics/MinikinSkia.cpp b/core/jni/android/graphics/MinikinSkia.cpp
index 622c935..243fa10 100644
--- a/core/jni/android/graphics/MinikinSkia.cpp
+++ b/core/jni/android/graphics/MinikinSkia.cpp
@@ -16,7 +16,6 @@
#include <SkTypeface.h>
#include <SkPaint.h>
-#include <SkFP.h>
#define LOG_TAG "Minikin"
#include <cutils/log.h>
@@ -44,19 +43,37 @@
return !!glyph;
}
+static void MinikinFontSkia_SetSkiaPaint(SkTypeface* typeface, SkPaint* skPaint, const MinikinPaint& paint) {
+ skPaint->setTypeface(typeface);
+ skPaint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ // TODO: set more paint parameters from Minikin
+ skPaint->setTextSize(paint.size);
+}
+
float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id,
const MinikinPaint &paint) const {
- SkPaint skpaint;
- skpaint.setTypeface(mTypeface);
- skpaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- // TODO: set more paint parameters from Minikin
- skpaint.setTextSize(paint.size);
+ SkPaint skPaint;
uint16_t glyph16 = glyph_id;
SkScalar skWidth;
+ MinikinFontSkia_SetSkiaPaint(mTypeface, &skPaint, paint);
+ skPaint.getTextWidths(&glyph16, sizeof(glyph16), &skWidth, NULL);
+#ifdef VERBOSE
+ ALOGD("width for typeface %d glyph %d = %f", mTypeface->uniqueID(), glyph_id, skWidth);
+#endif
+ return skWidth;
+}
+
+void MinikinFontSkia::GetBounds(MinikinRect* bounds, uint32_t glyph_id,
+ const MinikinPaint& paint) const {
+ SkPaint skPaint;
+ uint16_t glyph16 = glyph_id;
SkRect skBounds;
- skpaint.getTextWidths(&glyph16, sizeof(glyph16), &skWidth, &skBounds);
- // TODO: get bounds information
- return SkScalarToFP(skWidth);
+ MinikinFontSkia_SetSkiaPaint(mTypeface, &skPaint, paint);
+ skPaint.getTextWidths(&glyph16, sizeof(glyph16), NULL, &skBounds);
+ bounds->mLeft = skBounds.fLeft;
+ bounds->mTop = skBounds.fTop;
+ bounds->mRight = skBounds.fRight;
+ bounds->mBottom = skBounds.fBottom;
}
bool MinikinFontSkia::GetTable(uint32_t tag, uint8_t *buf, size_t *size) {
diff --git a/core/jni/android/graphics/MinikinSkia.h b/core/jni/android/graphics/MinikinSkia.h
index 0edb557..7a8954d 100644
--- a/core/jni/android/graphics/MinikinSkia.h
+++ b/core/jni/android/graphics/MinikinSkia.h
@@ -27,6 +27,9 @@
float GetHorizontalAdvance(uint32_t glyph_id,
const MinikinPaint &paint) const;
+ void GetBounds(MinikinRect* bounds, uint32_t glyph_id,
+ const MinikinPaint &paint) const;
+
// If buf is NULL, just update size
bool GetTable(uint32_t tag, uint8_t *buf, size_t *size);
@@ -36,7 +39,6 @@
private:
SkTypeface *mTypeface;
-
};
} // namespace android
\ No newline at end of file
diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp
new file mode 100644
index 0000000..ee04d6f
--- /dev/null
+++ b/core/jni/android/graphics/MinikinUtils.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SkPaint.h"
+#include "minikin/Layout.h"
+#include "TypefaceImpl.h"
+
+#include "MinikinUtils.h"
+
+namespace android {
+
+void MinikinUtils::SetLayoutProperties(Layout* layout, SkPaint* paint, int flags,
+ TypefaceImpl* typeface) {
+ TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
+ layout->setFontCollection(resolvedFace->fFontCollection);
+ FontStyle style = resolvedFace->fStyle;
+ char css[256];
+ sprintf(css, "font-size: %d; font-weight: %d; font-style: %s; -minikin-bidi: %d",
+ (int)paint->getTextSize(),
+ style.getWeight() * 100,
+ style.getItalic() ? "italic" : "normal",
+ flags);
+ layout->setProperties(css);
+}
+
+}
\ No newline at end of file
diff --git a/core/jni/android/graphics/MinikinUtils.h b/core/jni/android/graphics/MinikinUtils.h
new file mode 100644
index 0000000..42f5e2f
--- /dev/null
+++ b/core/jni/android/graphics/MinikinUtils.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Utilities for making Minikin work, especially from existing objects like
+ * SkPaint and so on.
+ **/
+
+ // TODO: does this really need to be separate from MinikinSkia?
+
+#ifndef ANDROID_MINIKIN_UTILS_H
+#define ANDROID_MINIKIN_UTILS_H
+
+namespace android {
+
+class MinikinUtils {
+public:
+ static void SetLayoutProperties(Layout* layout, SkPaint* paint, int flags,
+ TypefaceImpl* face);
+};
+
+} // namespace android
+
+#endif // ANDROID_MINIKIN_UTILS_H
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 22c17dd..43e80dc 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -36,6 +36,12 @@
#include "utils/Blur.h"
#include "TextLayout.h"
+#ifdef USE_MINIKIN
+#include <minikin/Layout.h>
+#include "MinikinSkia.h"
+#include "MinikinUtils.h"
+#endif
+
// temporary for debugging
#include <Caches.h>
#include <utils/Log.h>
@@ -100,16 +106,33 @@
*dst = *src;
}
+ // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
+ static const uint32_t sFilterBitmapFlag = 0x02;
+
static jint getFlags(JNIEnv* env, jobject paint) {
NPE_CHECK_RETURN_ZERO(env, paint);
- int result;
- result = GraphicsJNI::getNativePaint(env, paint)->getFlags();
+ SkPaint* nativePaint = GraphicsJNI::getNativePaint(env, paint);
+ uint32_t result = nativePaint->getFlags();
+ result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away.
+ if (nativePaint->getFilterLevel() != SkPaint::kNone_FilterLevel) {
+ result |= sFilterBitmapFlag;
+ }
return static_cast<jint>(result);
}
static void setFlags(JNIEnv* env, jobject paint, jint flags) {
NPE_CHECK_RETURN_VOID(env, paint);
- GraphicsJNI::getNativePaint(env, paint)->setFlags(flags);
+ SkPaint* nativePaint = GraphicsJNI::getNativePaint(env, paint);
+ // Instead of modifying 0x02, change the filter level.
+ nativePaint->setFilterLevel(flags & sFilterBitmapFlag
+ ? SkPaint::kLow_FilterLevel
+ : SkPaint::kNone_FilterLevel);
+ // Don't pass through filter flag, which is no longer stored in paint's flags.
+ flags &= ~sFilterBitmapFlag;
+ // Use the existing value for 0x02.
+ const uint32_t existing0x02Flag = nativePaint->getFlags() & sFilterBitmapFlag;
+ flags |= existing0x02Flag;
+ nativePaint->setFlags(flags);
}
static jint getHinting(JNIEnv* env, jobject paint) {
@@ -292,7 +315,7 @@
static jlong setRasterizer(JNIEnv* env, jobject clazz, jlong objHandle, jlong rasterizerHandle) {
SkPaint* obj = reinterpret_cast<SkPaint*>(objHandle);
- SkRasterizer* rasterizer = reinterpret_cast<SkRasterizer*>(rasterizerHandle);
+ SkAutoTUnref<SkRasterizer> rasterizer(GraphicsJNI::refNativeRasterizer(rasterizerHandle));
return reinterpret_cast<jlong>(obj->setRasterizer(rasterizer));
}
@@ -494,8 +517,16 @@
const jchar* textArray = env->GetCharArrayElements(text, NULL);
jfloat result = 0;
+#ifdef USE_MINIKIN
+ Layout layout;
+ TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
+ MinikinUtils::SetLayoutProperties(&layout, paint, bidiFlags, typeface);
+ layout.doLayout(textArray + index, count);
+ result = layout.getAdvance();
+#else
TextLayout::getTextRunAdvances(paint, textArray, index, count, textLength,
bidiFlags, NULL /* dont need all advances */, &result);
+#endif
env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
return result;
@@ -520,8 +551,16 @@
SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
jfloat width = 0;
+#ifdef USE_MINIKIN
+ Layout layout;
+ TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
+ MinikinUtils::SetLayoutProperties(&layout, paint, bidiFlags, typeface);
+ layout.doLayout(textArray + start, count);
+ width = layout.getAdvance();
+#else
TextLayout::getTextRunAdvances(paint, textArray, start, count, textLength,
bidiFlags, NULL /* dont need all advances */, &width);
+#endif
env->ReleaseStringChars(text, textArray);
return width;
@@ -540,15 +579,23 @@
SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
jfloat width = 0;
+#ifdef USE_MINIKIN
+ Layout layout;
+ TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
+ MinikinUtils::SetLayoutProperties(&layout, paint, bidiFlags, typeface);
+ layout.doLayout(textArray, textLength);
+ width = layout.getAdvance();
+#else
TextLayout::getTextRunAdvances(paint, textArray, 0, textLength, textLength,
bidiFlags, NULL /* dont need all advances */, &width);
+#endif
env->ReleaseStringChars(text, textArray);
return width;
}
- static int dotextwidths(JNIEnv* env, SkPaint* paint, const jchar text[], int count, jfloatArray widths,
- jint bidiFlags) {
+ static int dotextwidths(JNIEnv* env, SkPaint* paint, TypefaceImpl* typeface, const jchar text[], int count,
+ jfloatArray widths, jint bidiFlags) {
NPE_CHECK_RETURN_ZERO(env, paint);
NPE_CHECK_RETURN_ZERO(env, text);
@@ -568,27 +615,36 @@
AutoJavaFloatArray autoWidths(env, widths, count);
jfloat* widthsArray = autoWidths.ptr();
+#ifdef USE_MINIKIN
+ Layout layout;
+ MinikinUtils::SetLayoutProperties(&layout, paint, bidiFlags, typeface);
+ layout.doLayout(text, count);
+ layout.getAdvances(widthsArray);
+#else
TextLayout::getTextRunAdvances(paint, text, 0, count, count,
bidiFlags, widthsArray, NULL /* dont need totalAdvance */);
+#endif
return count;
}
- static jint getTextWidths___CIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text,
+ static jint getTextWidths___CIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray text,
jint index, jint count, jint bidiFlags, jfloatArray widths) {
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+ TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
const jchar* textArray = env->GetCharArrayElements(text, NULL);
- count = dotextwidths(env, paint, textArray + index, count, widths, bidiFlags);
+ count = dotextwidths(env, paint, typeface, textArray + index, count, widths, bidiFlags);
env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
JNI_ABORT);
return count;
}
- static jint getTextWidths__StringIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jstring text,
+ static jint getTextWidths__StringIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring text,
jint start, jint end, jint bidiFlags, jfloatArray widths) {
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+ TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
const jchar* textArray = env->GetStringChars(text, NULL);
- int count = dotextwidths(env, paint, textArray + start, end - start, widths, bidiFlags);
+ int count = dotextwidths(env, paint, typeface, textArray + start, end - start, widths, bidiFlags);
env->ReleaseStringChars(text, textArray);
return count;
}
@@ -634,7 +690,7 @@
return count;
}
- static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, const jchar *text,
+ static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, TypefaceImpl* typeface, const jchar *text,
jint start, jint count, jint contextCount, jint flags,
jfloatArray advances, jint advancesIndex) {
NPE_CHECK_RETURN_ZERO(env, paint);
@@ -657,8 +713,16 @@
jfloat* advancesArray = new jfloat[count];
jfloat totalAdvance = 0;
+#ifdef USE_MINIKIN
+ Layout layout;
+ MinikinUtils::SetLayoutProperties(&layout, paint, flags, typeface);
+ layout.doLayout(text + start, count);
+ layout.getAdvances(advancesArray);
+ totalAdvance = layout.getAdvance();
+#else
TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags,
advancesArray, &totalAdvance);
+#endif
if (advances != NULL) {
env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
@@ -668,22 +732,26 @@
}
static jfloat getTextRunAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
+ jlong typefaceHandle,
jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
jint flags, jfloatArray advances, jint advancesIndex) {
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+ TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
jchar* textArray = env->GetCharArrayElements(text, NULL);
- jfloat result = doTextRunAdvances(env, paint, textArray + contextIndex,
+ jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextIndex,
index - contextIndex, count, contextCount, flags, advances, advancesIndex);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
return result;
}
static jfloat getTextRunAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
+ jlong typefaceHandle,
jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
jfloatArray advances, jint advancesIndex) {
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+ TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
const jchar* textArray = env->GetStringChars(text, NULL);
- jfloat result = doTextRunAdvances(env, paint, textArray + contextStart,
+ jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextStart,
start - contextStart, end - start, contextEnd - contextStart, flags,
advances, advancesIndex);
env->ReleaseStringChars(text, textArray);
@@ -954,11 +1022,11 @@
{"native_measureText","(Ljava/lang/String;III)F", (void*) SkPaintGlue::measureText_StringIII},
{"native_breakText","([CIIFI[F)I", (void*) SkPaintGlue::breakTextC},
{"native_breakText","(Ljava/lang/String;ZFI[F)I", (void*) SkPaintGlue::breakTextS},
- {"native_getTextWidths","(J[CIII[F)I", (void*) SkPaintGlue::getTextWidths___CIII_F},
- {"native_getTextWidths","(JLjava/lang/String;III[F)I", (void*) SkPaintGlue::getTextWidths__StringIII_F},
- {"native_getTextRunAdvances","(J[CIIIII[FI)F",
+ {"native_getTextWidths","(JJ[CIII[F)I", (void*) SkPaintGlue::getTextWidths___CIII_F},
+ {"native_getTextWidths","(JJLjava/lang/String;III[F)I", (void*) SkPaintGlue::getTextWidths__StringIII_F},
+ {"native_getTextRunAdvances","(JJ[CIIIII[FI)F",
(void*) SkPaintGlue::getTextRunAdvances___CIIIII_FI},
- {"native_getTextRunAdvances","(JLjava/lang/String;IIIII[FI)F",
+ {"native_getTextRunAdvances","(JJLjava/lang/String;IIIII[FI)F",
(void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI},
diff --git a/core/jni/android/graphics/Rasterizer.cpp b/core/jni/android/graphics/Rasterizer.cpp
index b6450d0..a05d19b 100644
--- a/core/jni/android/graphics/Rasterizer.cpp
+++ b/core/jni/android/graphics/Rasterizer.cpp
@@ -22,30 +22,82 @@
#include "jni.h"
#include "GraphicsJNI.h"
+#include "SkLayerRasterizer.h"
#include <android_runtime/AndroidRuntime.h>
-#include "SkRasterizer.h"
+// Rasterizer.java holds a pointer (jlong) to this guy
+class NativeRasterizer {
+public:
+ NativeRasterizer() {}
+ virtual ~NativeRasterizer() {}
+
+ // Can return NULL, or a ref to the skia rasterizer.
+ virtual SkRasterizer* refRasterizer() { return NULL; }
+};
+
+class NativeLayerRasterizer : public NativeRasterizer {
+public:
+ SkLayerRasterizer::Builder fBuilder;
+
+ virtual SkRasterizer* refRasterizer() {
+ return fBuilder.snapshotRasterizer();
+ }
+};
+
+SkRasterizer* GraphicsJNI::refNativeRasterizer(jlong rasterizerHandle) {
+ NativeRasterizer* nr = reinterpret_cast<NativeRasterizer*>(rasterizerHandle);
+ return nr ? nr->refRasterizer() : NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
namespace android {
class SkRasterizerGlue {
public:
-
static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) {
- SkRasterizer* obj = reinterpret_cast<SkRasterizer *>(objHandle);
- SkSafeUnref(obj);
+ delete reinterpret_cast<NativeRasterizer *>(objHandle);
}
};
-static JNINativeMethod methods[] = {
+static JNINativeMethod gRasterizerMethods[] = {
{"finalizer", "(J)V", (void*) SkRasterizerGlue::finalizer}
};
int register_android_graphics_Rasterizer(JNIEnv* env) {
- int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Rasterizer", methods,
- sizeof(methods) / sizeof(methods[0]));
+ int result = AndroidRuntime::registerNativeMethods(env, "android/graphics/Rasterizer", gRasterizerMethods,
+ sizeof(gRasterizerMethods) / sizeof(gRasterizerMethods[0]));
return result;
}
+class SkLayerRasterizerGlue {
+public:
+ static jlong create(JNIEnv* env, jobject) {
+ return reinterpret_cast<jlong>(new NativeLayerRasterizer);
+ }
+
+ static void addLayer(JNIEnv* env, jobject, jlong layerHandle, jlong paintHandle, jfloat dx, jfloat dy) {
+ NativeLayerRasterizer* nr = reinterpret_cast<NativeLayerRasterizer *>(layerHandle);
+ const SkPaint* paint = reinterpret_cast<SkPaint *>(paintHandle);
+ SkASSERT(nr);
+ SkASSERT(paint);
+ nr->fBuilder.addLayer(*paint, dx, dy);
+ }
+};
+
+static JNINativeMethod gLayerRasterizerMethods[] = {
+ { "nativeConstructor", "()J", (void*)SkLayerRasterizerGlue::create },
+ { "nativeAddLayer", "(JJFF)V", (void*)SkLayerRasterizerGlue::addLayer }
+};
+
+int register_android_graphics_LayerRasterizer(JNIEnv* env)
+{
+ return android::AndroidRuntime::registerNativeMethods(env,
+ "android/graphics/LayerRasterizer",
+ gLayerRasterizerMethods,
+ SK_ARRAY_COUNT(gLayerRasterizerMethods));
}
+
+}
+
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 9279758..bf58918 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -367,6 +367,7 @@
bool forceLTR = false;
bool forceRTL = false;
+ ALOGD("computeValues dirFlags=%d", dirFlags);
switch (dirFlags & kBidi_Mask) {
case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index a349a7f..b20c246 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -18,6 +18,7 @@
#include <android_runtime/AndroidRuntime.h>
#include "GraphicsJNI.h"
+#include <ScopedPrimitiveArray.h>
#include "SkStream.h"
#include "SkTypeface.h"
#include "TypefaceImpl.h"
@@ -62,7 +63,7 @@
}
static jlong Typeface_createFromTypeface(JNIEnv* env, jobject, jlong familyHandle, jint style) {
- SkTypeface* family = reinterpret_cast<SkTypeface*>(familyHandle);
+ TypefaceImpl* family = reinterpret_cast<TypefaceImpl*>(familyHandle);
TypefaceImpl* face = TypefaceImpl_createFromTypeface(family, (SkTypeface::Style)style);
// Try to find the closest matching font, using the standard heuristic
if (NULL == face) {
@@ -114,6 +115,16 @@
return reinterpret_cast<jlong>(TypefaceImpl_createFromFile(str.c_str()));
}
+static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray) {
+ ScopedLongArrayRO families(env, familyArray);
+ return reinterpret_cast<jlong>(TypefaceImpl_createFromFamilies(families.get(), families.size()));
+}
+
+static void Typeface_setDefault(JNIEnv *env, jobject, jlong faceHandle) {
+ TypefaceImpl* face = reinterpret_cast<TypefaceImpl*>(faceHandle);
+ return TypefaceImpl_setDefault(face);
+}
+
///////////////////////////////////////////////////////////////////////////////
static JNINativeMethod gTypefaceMethods[] = {
@@ -125,6 +136,9 @@
(void*)Typeface_createFromAsset },
{ "nativeCreateFromFile", "(Ljava/lang/String;)J",
(void*)Typeface_createFromFile },
+ { "nativeCreateFromArray", "([J)J",
+ (void*)Typeface_createFromArray },
+ { "nativeSetDefault", "(J)V", (void*)Typeface_setDefault },
};
int register_android_graphics_Typeface(JNIEnv* env)
diff --git a/core/jni/android/graphics/TypefaceImpl.cpp b/core/jni/android/graphics/TypefaceImpl.cpp
index f6d3a6e..958cd85 100644
--- a/core/jni/android/graphics/TypefaceImpl.cpp
+++ b/core/jni/android/graphics/TypefaceImpl.cpp
@@ -20,6 +20,10 @@
* being, that choice is hidden under the USE_MINIKIN compile-time flag.
*/
+#define LOG_TAG "TypefaceImpl"
+
+#include "jni.h" // for jlong, remove when being passed proper type
+
#include "SkStream.h"
#include "SkTypeface.h"
@@ -48,48 +52,49 @@
return FontStyle(weight, italic);
}
-TypefaceImpl* gDefaultTypeface;
+TypefaceImpl* gDefaultTypeface = NULL;
pthread_once_t gDefaultTypefaceOnce = PTHREAD_ONCE_INIT;
-// TODO: this currently builds a font collection from hardcoded paths.
-// It will get replaced by an implementation that parses the XML files.
+// This installs a default typeface (from a hardcoded path) that allows
+// layouts to work (not crash on null pointer) before the default
+// typeface is set.
+// TODO: investigate why layouts are being created before Typeface.java
+// class initialization.
static FontCollection *makeFontCollection() {
std::vector<FontFamily *>typefaces;
const char *fns[] = {
"/system/fonts/Roboto-Regular.ttf",
- "/system/fonts/Roboto-Italic.ttf",
- "/system/fonts/Roboto-BoldItalic.ttf",
- "/system/fonts/Roboto-Light.ttf",
- "/system/fonts/Roboto-Thin.ttf",
- "/system/fonts/Roboto-Bold.ttf",
- "/system/fonts/Roboto-ThinItalic.ttf",
- "/system/fonts/Roboto-LightItalic.ttf"
};
FontFamily *family = new FontFamily();
for (size_t i = 0; i < sizeof(fns)/sizeof(fns[0]); i++) {
const char *fn = fns[i];
+ ALOGD("makeFontCollection adding %s", fn);
SkTypeface *skFace = SkTypeface::CreateFromFile(fn);
- MinikinFont *font = new MinikinFontSkia(skFace);
- family->addFont(font);
+ if (skFace != NULL) {
+ MinikinFont *font = new MinikinFontSkia(skFace);
+ family->addFont(font);
+ font->Unref();
+ } else {
+ ALOGE("failed to create font %s", fn);
+ }
}
typefaces.push_back(family);
- family = new FontFamily();
- const char *fn = "/system/fonts/NotoSansDevanagari-Regular.ttf";
- SkTypeface *skFace = SkTypeface::CreateFromFile(fn);
- MinikinFont *font = new MinikinFontSkia(skFace);
- family->addFont(font);
- typefaces.push_back(family);
-
- return new FontCollection(typefaces);
+ FontCollection *result = new FontCollection(typefaces);
+ family->Unref();
+ return result;
}
static void getDefaultTypefaceOnce() {
Layout::init();
- gDefaultTypeface = new TypefaceImpl;
- gDefaultTypeface->fFontCollection = makeFontCollection();
- gDefaultTypeface->fStyle = FontStyle();
+ if (gDefaultTypeface == NULL) {
+ // We expect the client to set a default typeface, but provide a
+ // default so we can make progress before that happens.
+ gDefaultTypeface = new TypefaceImpl;
+ gDefaultTypeface->fFontCollection = makeFontCollection();
+ gDefaultTypeface->fStyle = FontStyle();
+ }
}
TypefaceImpl* TypefaceImpl_resolveDefault(TypefaceImpl* src) {
@@ -106,19 +111,25 @@
TypefaceImpl* result = new TypefaceImpl;
if (result != 0) {
result->fFontCollection = resolvedFace->fFontCollection;
+ result->fFontCollection->Ref();
result->fStyle = styleFromSkiaStyle(style);
}
return result;
}
static TypefaceImpl* createFromSkTypeface(SkTypeface* typeface) {
+ if (typeface == NULL) {
+ return NULL;
+ }
MinikinFont* minikinFont = new MinikinFontSkia(typeface);
std::vector<FontFamily *> typefaces;
FontFamily* family = new FontFamily();
family->addFont(minikinFont);
+ minikinFont->Unref();
typefaces.push_back(family);
TypefaceImpl* result = new TypefaceImpl;
result->fFontCollection = new FontCollection(typefaces);
+ family->Unref();
result->fStyle = FontStyle(); // TODO: improve
return result;
}
@@ -146,7 +157,21 @@
return createFromSkTypeface(face);
}
+TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size) {
+ ALOGD("createFromFamilies size=%d", size);
+ std::vector<FontFamily *>familyVec;
+ for (size_t i = 0; i < size; i++) {
+ FontFamily* family = reinterpret_cast<FontFamily*>(families[i]);
+ familyVec.push_back(family);
+ }
+ TypefaceImpl* result = new TypefaceImpl;
+ result->fFontCollection = new FontCollection(familyVec);
+ result->fStyle = FontStyle(); // TODO: improve
+ return result;
+}
+
void TypefaceImpl_unref(TypefaceImpl* face) {
+ face->fFontCollection->Unref();
delete face;
}
@@ -159,6 +184,10 @@
return result;
}
+void TypefaceImpl_setDefault(TypefaceImpl* face) {
+ gDefaultTypeface = face;
+}
+
#else // USE_MINIKIN
/* Just use SkTypeface instead. */
@@ -189,6 +218,11 @@
return face;
}
+TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size) {
+ // Should never be called in non-Minikin builds
+ return 0;
+}
+
void TypefaceImpl_unref(TypefaceImpl* face) {
SkSafeUnref(face);
}
@@ -197,6 +231,9 @@
return face->style();
}
+void TypefaceImpl_setDefault(TypefaceImpl* face) {
+}
+
#endif // USE_MINIKIN
}
diff --git a/core/jni/android/graphics/TypefaceImpl.h b/core/jni/android/graphics/TypefaceImpl.h
index 4c51bec..4e92bce 100644
--- a/core/jni/android/graphics/TypefaceImpl.h
+++ b/core/jni/android/graphics/TypefaceImpl.h
@@ -18,6 +18,8 @@
#ifndef ANDROID_TYPEFACE_IMPL_H
#define ANDROID_TYPEFACE_IMPL_H
+#include "jni.h" // for jlong, eventually remove
+#include "SkTypeface.h"
#include <androidfw/AssetManager.h>
#ifdef USE_MINIKIN
@@ -51,10 +53,16 @@
TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset);
+// When we remove the USE_MINIKIN ifdef, probably a good idea to move the casting
+// (from jlong to FontFamily*) to the caller in Typeface.cpp.
+TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size);
+
void TypefaceImpl_unref(TypefaceImpl* face);
int TypefaceImpl_getStyle(TypefaceImpl* face);
+void TypefaceImpl_setDefault(TypefaceImpl* face);
+
}
#endif // ANDROID_TYPEFACE_IMPL_H
\ No newline at end of file
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
new file mode 100644
index 0000000..15de24a
--- /dev/null
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "GraphicsJNI.h"
+#include "SkBitmap.h"
+#include "SkMatrix.h"
+#include "fpdfview.h"
+#include "fsdk_rendercontext.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <vector>
+#include <utils/Log.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android {
+
+static const int RENDER_MODE_FOR_DISPLAY = 1;
+static const int RENDER_MODE_FOR_PRINT = 2;
+
+static struct {
+ jfieldID x;
+ jfieldID y;
+} gPointClassInfo;
+
+static Mutex sLock;
+
+static int sUnmatchedInitRequestCount = 0;
+
+static void initializeLibraryIfNeeded() {
+ Mutex::Autolock _l(sLock);
+ if (sUnmatchedInitRequestCount == 0) {
+ FPDF_InitLibrary(NULL);
+ }
+ sUnmatchedInitRequestCount++;
+}
+
+static void destroyLibraryIfNeeded() {
+ Mutex::Autolock _l(sLock);
+ sUnmatchedInitRequestCount--;
+ if (sUnmatchedInitRequestCount == 0) {
+ FPDF_DestroyLibrary();
+ }
+}
+
+static int getBlock(void* param, unsigned long position, unsigned char* outBuffer,
+ unsigned long size) {
+ const int fd = reinterpret_cast<intptr_t>(param);
+ const int readCount = pread(fd, outBuffer, size, position);
+ if (readCount < 0) {
+ ALOGE("Cannot read from file descriptor. Error:%d", errno);
+ return 0;
+ }
+ return 1;
+}
+
+static jlong nativeCreate(JNIEnv* env, jclass thiz, jint fd, jlong size) {
+ initializeLibraryIfNeeded();
+
+ FPDF_FILEACCESS loader;
+ loader.m_FileLen = size;
+ loader.m_Param = reinterpret_cast<void*>(intptr_t(fd));
+ loader.m_GetBlock = &getBlock;
+
+ FPDF_DOCUMENT document = FPDF_LoadCustomDocument(&loader, NULL);
+
+ if (!document) {
+ const long error = FPDF_GetLastError();
+ jniThrowException(env, "java/io/IOException",
+ "cannot create document. Error:" + error);
+ destroyLibraryIfNeeded();
+ return -1;
+ }
+
+ return reinterpret_cast<jlong>(document);
+}
+
+static jlong nativeOpenPageAndGetSize(JNIEnv* env, jclass thiz, jlong documentPtr,
+ jint pageIndex, jobject outSize) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+ FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
+
+ if (!page) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "cannot load page");
+ return -1;
+ }
+
+ double width = 0;
+ double height = 0;
+
+ const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
+
+ if (!result) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "cannot get page size");
+ return -1;
+ }
+
+ env->SetIntField(outSize, gPointClassInfo.x, width);
+ env->SetIntField(outSize, gPointClassInfo.y, height);
+
+ return reinterpret_cast<jlong>(page);
+}
+
+static void nativeClosePage(JNIEnv* env, jclass thiz, jlong pagePtr) {
+ FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
+ FPDF_ClosePage(page);
+}
+
+static void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+ FPDF_CloseDocument(document);
+ destroyLibraryIfNeeded();
+}
+
+static jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+ return FPDF_GetPageCount(document);
+}
+
+static jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+ return FPDF_VIEWERREF_GetPrintScaling(document);
+}
+
+static void DropContext(void* data) {
+ delete (CRenderContext*) data;
+}
+
+static void renderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int destLeft, int destTop,
+ int destRight, int destBottom, SkMatrix* transform, int flags) {
+ // Note: this code ignores the currently unused RENDER_NO_NATIVETEXT,
+ // FPDF_RENDER_LIMITEDIMAGECACHE, FPDF_RENDER_FORCEHALFTONE, FPDF_GRAYSCALE,
+ // and FPDF_ANNOT flags. To add support for that refer to FPDF_RenderPage_Retail
+ // in fpdfview.cpp
+
+ CRenderContext* pContext = FX_NEW CRenderContext;
+
+ CPDF_Page* pPage = (CPDF_Page*) page;
+ pPage->SetPrivateData((void*) 1, pContext, DropContext);
+
+ CFX_FxgeDevice* fxgeDevice = FX_NEW CFX_FxgeDevice;
+ pContext->m_pDevice = fxgeDevice;
+
+ // Reverse the bytes (last argument TRUE) since the Android
+ // format is ARGB while the renderer uses BGRA internally.
+ fxgeDevice->Attach((CFX_DIBitmap*) bitmap, 0, TRUE);
+
+ CPDF_RenderOptions* renderOptions = pContext->m_pOptions;
+
+ if (!renderOptions) {
+ renderOptions = FX_NEW CPDF_RenderOptions;
+ pContext->m_pOptions = renderOptions;
+ }
+
+ if (flags & FPDF_LCD_TEXT) {
+ renderOptions->m_Flags |= RENDER_CLEARTYPE;
+ } else {
+ renderOptions->m_Flags &= ~RENDER_CLEARTYPE;
+ }
+
+ const CPDF_OCContext::UsageType usage = (flags & FPDF_PRINTING)
+ ? CPDF_OCContext::Print : CPDF_OCContext::View;
+
+ renderOptions->m_AddFlags = flags >> 8;
+ renderOptions->m_pOCContext = new CPDF_OCContext(pPage->m_pDocument, usage);
+
+ fxgeDevice->SaveState();
+
+ FX_RECT clip;
+ clip.left = destLeft;
+ clip.right = destRight;
+ clip.top = destTop;
+ clip.bottom = destBottom;
+ fxgeDevice->SetClip_Rect(&clip);
+
+ CPDF_RenderContext* pageContext = FX_NEW CPDF_RenderContext;
+ pContext->m_pContext = pageContext;
+ pageContext->Create(pPage);
+
+ CFX_AffineMatrix matrix;
+ if (!transform) {
+ pPage->GetDisplayMatrix(matrix, destLeft, destTop, destRight - destLeft,
+ destBottom - destTop, 0);
+ } else {
+ // PDF's coordinate system origin is left-bottom while
+ // in graphics it is the top-left, so remap the origin.
+ matrix.Set(1, 0, 0, -1, 0, pPage->GetPageHeight());
+ matrix.Scale(transform->getScaleX(), transform->getScaleY());
+ matrix.Rotate(transform->getSkewX(), transform->getSkewY());
+ matrix.Translate(transform->getTranslateX(), transform->getTranslateY());
+ }
+ pageContext->AppendObjectList(pPage, &matrix);
+
+ pContext->m_pRenderer = FX_NEW CPDF_ProgressiveRenderer;
+ pContext->m_pRenderer->Start(pageContext, fxgeDevice, renderOptions, NULL);
+
+ fxgeDevice->RestoreState();
+
+ pPage->RemovePrivateData((void*) 1);
+
+ delete pContext;
+}
+
+static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong pagePtr,
+ jlong bitmapPtr, jint destLeft, jint destTop, jint destRight, jint destBottom,
+ jlong matrixPtr, jint renderMode) {
+
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+ FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
+ SkBitmap* skBitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
+ SkMatrix* skMatrix = reinterpret_cast<SkMatrix*>(matrixPtr);
+
+ skBitmap->lockPixels();
+
+ const int stride = skBitmap->width() * 4;
+
+ FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(skBitmap->width(), skBitmap->height(),
+ FPDFBitmap_BGRA, skBitmap->getPixels(), stride);
+
+ if (!bitmap) {
+ ALOGE("Erorr creating bitmap");
+ return;
+ }
+
+ int renderFlags = 0;
+ if (renderMode == RENDER_MODE_FOR_DISPLAY) {
+ renderFlags |= FPDF_LCD_TEXT;
+ } else if (renderMode == RENDER_MODE_FOR_PRINT) {
+ renderFlags |= FPDF_PRINTING;
+ }
+
+ renderPageBitmap(bitmap, page, destLeft, destTop, destRight,
+ destBottom, skMatrix, renderFlags);
+
+ skBitmap->unlockPixels();
+}
+
+static JNINativeMethod gPdfRenderer_Methods[] = {
+ {"nativeCreate", "(IJ)J", (void*) nativeCreate},
+ {"nativeClose", "(J)V", (void*) nativeClose},
+ {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
+ {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting},
+ {"nativeRenderPage", "(JJJIIIIJI)V", (void*) nativeRenderPage},
+ {"nativeOpenPageAndGetSize", "(JILandroid/graphics/Point;)J", (void*) nativeOpenPageAndGetSize},
+ {"nativeClosePage", "(J)V", (void*) nativeClosePage}
+};
+
+int register_android_graphics_pdf_PdfRenderer(JNIEnv* env) {
+ int result = android::AndroidRuntime::registerNativeMethods(
+ env, "android/graphics/pdf/PdfRenderer", gPdfRenderer_Methods,
+ NELEM(gPdfRenderer_Methods));
+
+ jclass clazz = env->FindClass("android/graphics/Point");
+ gPointClassInfo.x = env->GetFieldID(clazz, "x", "I");
+ gPointClassInfo.y = env->GetFieldID(clazz, "y", "I");
+
+ return result;
+};
+
+};
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 05a99a3..fa2cfe3 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -489,8 +489,13 @@
sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
- SortedVector<String8> vendorSections = vTags->getAllSectionNames();
- size_t vendorSectionCount = vendorSections.size();
+ SortedVector<String8> vendorSections;
+ size_t vendorSectionCount = 0;
+
+ if (vTags != 0) {
+ vendorSections = vTags->getAllSectionNames();
+ vendorSectionCount = vendorSections.size();
+ }
// First, find the section by the longest string match
const char *section = NULL;
@@ -561,7 +566,7 @@
"Could not find tag name for key '%s')", key);
return 0;
}
- } else {
+ } else if (vTags != 0) {
// Match vendor tags (typically com.*)
const String8 sectionName(section);
const String8 tagName(keyTagName);
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index fae6698..27d3f39 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -51,6 +51,12 @@
#include <RenderNode.h>
#include <CanvasProperty.h>
+#ifdef USE_MINIKIN
+#include <minikin/Layout.h>
+#include "MinikinSkia.h"
+#include "MinikinUtils.h"
+#endif
+
#include <TextLayout.h>
#include <TextLayoutCache.h>
@@ -661,8 +667,58 @@
return 0;
}
+#ifdef USE_MINIKIN
+static void renderTextLayout(OpenGLRenderer* renderer, Layout* layout,
+ jfloat x, jfloat y, SkPaint* paint) {
+ size_t nGlyphs = layout->nGlyphs();
+ float* pos = new float[nGlyphs * 2];
+ uint16_t* glyphs = new uint16_t[nGlyphs];
+ SkTypeface* lastFace = 0;
+ SkTypeface* skFace = 0;
+ size_t start = 0;
+ MinikinRect b;
+ layout->getBounds(&b);
+ android::uirenderer::Rect bounds(b.mLeft, b.mTop, b.mRight, b.mBottom);
+ bounds.translate(x, y);
+ float totalAdvance = layout->getAdvance();
+
+ for (size_t i = 0; i < nGlyphs; i++) {
+ MinikinFontSkia* mfs = static_cast<MinikinFontSkia *>(layout->getFont(i));
+ skFace = mfs->GetSkTypeface();
+ glyphs[i] = layout->getGlyphId(i);
+ pos[2 * i] = layout->getX(i);
+ pos[2 * i + 1] = layout->getY(i);
+ if (i > 0 && skFace != lastFace) {
+ paint->setTypeface(lastFace);
+ size_t glyphsCount = i - start;
+ int bytesCount = glyphsCount * sizeof(jchar);
+ renderer->drawText((const char*) (glyphs + start), bytesCount, glyphsCount,
+ x, y, pos + 2 * start, paint, totalAdvance, bounds);
+ start = i;
+ }
+ lastFace = skFace;
+ }
+ if (skFace != NULL) {
+ paint->setTypeface(skFace);
+ size_t glyphsCount = nGlyphs - start;
+ int bytesCount = glyphsCount * sizeof(jchar);
+ renderer->drawText((const char*) (glyphs + start), bytesCount, glyphsCount,
+ x, y, pos + 2 * start, paint, totalAdvance, bounds);
+ }
+ delete[] glyphs;
+ delete[] pos;
+}
+#endif
+
static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
- jfloat x, jfloat y, int flags, SkPaint* paint) {
+ jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) {
+#ifdef USE_MINIKIN
+ Layout layout;
+ MinikinUtils::SetLayoutProperties(&layout, paint, flags, typeface);
+ layout.doLayout(text, count);
+ x += xOffsetForTextAlign(paint, layout.getAdvance());
+ renderTextLayout(renderer, &layout, x, y, paint);
+#else
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
text, 0, count, count, flags);
if (value == NULL) {
@@ -680,6 +736,7 @@
renderer->drawText((const char*) glyphs, bytesCount, glyphsCount,
x, y, positions, paint, totalAdvance, bounds);
+#endif
}
static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count,
@@ -698,7 +755,14 @@
static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
jint start, jint count, jint contextCount, jfloat x, jfloat y,
- int flags, SkPaint* paint) {
+ int flags, SkPaint* paint, TypefaceImpl* typeface) {
+#ifdef USE_MINIKIN
+ Layout layout;
+ MinikinUtils::SetLayoutProperties(&layout, paint, flags, typeface);
+ layout.doLayout(text + start, count);
+ x += xOffsetForTextAlign(paint, layout.getAdvance());
+ renderTextLayout(renderer, &layout, x, y, paint);
+#else
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
text, start, count, contextCount, flags);
if (value == NULL) {
@@ -716,27 +780,30 @@
renderer->drawText((const char*) glyphs, bytesCount, glyphsCount,
x, y, positions, paint, totalAdvance, bounds);
+#endif
}
static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
jlong rendererPtr, jcharArray text, jint index, jint count,
- jfloat x, jfloat y, jint flags, jlong paintPtr) {
+ jfloat x, jfloat y, jint flags, jlong paintPtr, jlong typefacePtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
jchar* textArray = env->GetCharArrayElements(text, NULL);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
+ TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
- renderText(renderer, textArray + index, count, x, y, flags, paint);
+ renderText(renderer, textArray + index, count, x, y, flags, paint, typeface);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject clazz,
jlong rendererPtr, jstring text, jint start, jint end,
- jfloat x, jfloat y, jint flags, jlong paintPtr) {
+ jfloat x, jfloat y, jint flags, jlong paintPtr, jlong typefacePtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
const jchar* textArray = env->GetStringChars(text, NULL);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
+ TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
- renderText(renderer, textArray + start, end - start, x, y, flags, paint);
+ renderText(renderer, textArray + start, end - start, x, y, flags, paint, typeface);
env->ReleaseStringChars(text, textArray);
}
@@ -769,28 +836,30 @@
static void android_view_GLES20Canvas_drawTextRunArray(JNIEnv* env, jobject clazz,
jlong rendererPtr, jcharArray text, jint index, jint count,
jint contextIndex, jint contextCount, jfloat x, jfloat y, jint dirFlags,
- jlong paintPtr) {
+ jlong paintPtr, jlong typefacePtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
jchar* textArray = env->GetCharArrayElements(text, NULL);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
+ TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
renderTextRun(renderer, textArray + contextIndex, index - contextIndex,
- count, contextCount, x, y, dirFlags, paint);
+ count, contextCount, x, y, dirFlags, paint, typeface);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject clazz,
jlong rendererPtr, jstring text, jint start, jint end,
jint contextStart, int contextEnd, jfloat x, jfloat y, jint dirFlags,
- jlong paintPtr) {
+ jlong paintPtr, jlong typefacePtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
const jchar* textArray = env->GetStringChars(text, NULL);
jint count = end - start;
jint contextCount = contextEnd - contextStart;
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
+ TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
renderTextRun(renderer, textArray + contextStart, start - contextStart,
- count, contextCount, x, y, dirFlags, paint);
+ count, contextCount, x, y, dirFlags, paint, typeface);
env->ReleaseStringChars(text, textArray);
}
@@ -1028,16 +1097,16 @@
{ "nSetupPaintFilter", "(JII)V", (void*) android_view_GLES20Canvas_setupPaintFilter },
{ "nResetPaintFilter", "(J)V", (void*) android_view_GLES20Canvas_resetPaintFilter },
- { "nDrawText", "(J[CIIFFIJ)V", (void*) android_view_GLES20Canvas_drawTextArray },
- { "nDrawText", "(JLjava/lang/String;IIFFIJ)V",
+ { "nDrawText", "(J[CIIFFIJJ)V", (void*) android_view_GLES20Canvas_drawTextArray },
+ { "nDrawText", "(JLjava/lang/String;IIFFIJJ)V",
(void*) android_view_GLES20Canvas_drawText },
{ "nDrawTextOnPath", "(J[CIIJFFIJ)V", (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
{ "nDrawTextOnPath", "(JLjava/lang/String;IIJFFIJ)V",
(void*) android_view_GLES20Canvas_drawTextOnPath },
- { "nDrawTextRun", "(J[CIIIIFFIJ)V", (void*) android_view_GLES20Canvas_drawTextRunArray },
- { "nDrawTextRun", "(JLjava/lang/String;IIIIFFIJ)V",
+ { "nDrawTextRun", "(J[CIIIIFFIJJ)V", (void*) android_view_GLES20Canvas_drawTextRunArray },
+ { "nDrawTextRun", "(JLjava/lang/String;IIIIFFIJJ)V",
(void*) android_view_GLES20Canvas_drawTextRun },
{ "nDrawPosText", "(J[CII[FJ)V", (void*) android_view_GLES20Canvas_drawPosTextArray },
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 4715c26..b0defdb 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -80,6 +80,7 @@
jobject clazz, jlong renderNodePtr, jboolean caching) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setCaching(caching);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setStaticMatrix(JNIEnv* env,
@@ -87,6 +88,7 @@
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
renderNode->mutateStagingProperties().setStaticMatrix(matrix);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setAnimationMatrix(JNIEnv* env,
@@ -94,24 +96,28 @@
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
renderNode->mutateStagingProperties().setAnimationMatrix(matrix);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setClipToBounds(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jboolean clipToBounds) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setClipToBounds(clipToBounds);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setProjectBackwards(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jboolean shouldProject) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setProjectBackwards(shouldProject);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setProjectionReceiver(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jboolean shouldRecieve) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setProjectionReceiver(shouldRecieve);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setOutlineRoundRect(JNIEnv* env,
@@ -119,7 +125,7 @@
jint right, jint bottom, jfloat radius) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().mutableOutline().setRoundRect(left, top, right, bottom, radius);
- renderNode->mutateStagingProperties().updateClipPath();
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setOutlineConvexPath(JNIEnv* env,
@@ -127,21 +133,21 @@
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
SkPath* outlinePath = reinterpret_cast<SkPath*>(outlinePathPtr);
renderNode->mutateStagingProperties().mutableOutline().setConvexPath(outlinePath);
- renderNode->mutateStagingProperties().updateClipPath();
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setOutlineEmpty(JNIEnv* env,
jobject clazz, jlong renderNodePtr) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().mutableOutline().setEmpty();
- renderNode->mutateStagingProperties().updateClipPath();
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setClipToOutline(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jboolean clipToOutline) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().mutableOutline().setShouldClip(clipToOutline);
- renderNode->mutateStagingProperties().updateClipPath();
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setRevealClip(JNIEnv* env,
@@ -150,115 +156,133 @@
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().mutableRevealClip().set(
shouldClip, inverseClip, x, y, radius);
- renderNode->mutateStagingProperties().updateClipPath();
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setAlpha(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float alpha) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setAlpha(alpha);
+ renderNode->setPropertyFieldsDirty(RenderNode::ALPHA);
}
static void android_view_RenderNode_setHasOverlappingRendering(JNIEnv* env,
jobject clazz, jlong renderNodePtr, bool hasOverlappingRendering) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setHasOverlappingRendering(hasOverlappingRendering);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setElevation(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float elevation) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setElevation(elevation);
+ renderNode->setPropertyFieldsDirty(RenderNode::Z);
}
static void android_view_RenderNode_setTranslationX(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float tx) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setTranslationX(tx);
+ renderNode->setPropertyFieldsDirty(RenderNode::TRANSLATION_X | RenderNode::X);
}
static void android_view_RenderNode_setTranslationY(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float ty) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setTranslationY(ty);
+ renderNode->setPropertyFieldsDirty(RenderNode::TRANSLATION_Y | RenderNode::Y);
}
static void android_view_RenderNode_setTranslationZ(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float tz) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setTranslationZ(tz);
+ renderNode->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z | RenderNode::Z);
}
static void android_view_RenderNode_setRotation(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float rotation) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setRotation(rotation);
+ renderNode->setPropertyFieldsDirty(RenderNode::ROTATION);
}
static void android_view_RenderNode_setRotationX(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float rx) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setRotationX(rx);
+ renderNode->setPropertyFieldsDirty(RenderNode::ROTATION_X);
}
static void android_view_RenderNode_setRotationY(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float ry) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setRotationY(ry);
+ renderNode->setPropertyFieldsDirty(RenderNode::ROTATION_Y);
}
static void android_view_RenderNode_setScaleX(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float sx) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setScaleX(sx);
+ renderNode->setPropertyFieldsDirty(RenderNode::SCALE_X);
}
static void android_view_RenderNode_setScaleY(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float sy) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setScaleY(sy);
+ renderNode->setPropertyFieldsDirty(RenderNode::SCALE_Y);
}
static void android_view_RenderNode_setPivotX(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float px) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setPivotX(px);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setPivotY(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float py) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setPivotY(py);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setCameraDistance(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float distance) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setCameraDistance(distance);
+ renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
}
static void android_view_RenderNode_setLeft(JNIEnv* env,
jobject clazz, jlong renderNodePtr, int left) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setLeft(left);
+ renderNode->setPropertyFieldsDirty(RenderNode::X);
}
static void android_view_RenderNode_setTop(JNIEnv* env,
jobject clazz, jlong renderNodePtr, int top) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setTop(top);
+ renderNode->setPropertyFieldsDirty(RenderNode::Y);
}
static void android_view_RenderNode_setRight(JNIEnv* env,
jobject clazz, jlong renderNodePtr, int right) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setRight(right);
+ renderNode->setPropertyFieldsDirty(RenderNode::X);
}
static void android_view_RenderNode_setBottom(JNIEnv* env,
jobject clazz, jlong renderNodePtr, int bottom) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setBottom(bottom);
+ renderNode->setPropertyFieldsDirty(RenderNode::Y);
}
static void android_view_RenderNode_setLeftTopRightBottom(JNIEnv* env,
@@ -266,18 +290,21 @@
int right, int bottom) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom);
+ renderNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
static void android_view_RenderNode_offsetLeftAndRight(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float offset) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().offsetLeftRight(offset);
+ renderNode->setPropertyFieldsDirty(RenderNode::X);
}
static void android_view_RenderNode_offsetTopAndBottom(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float offset) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().offsetTopBottom(offset);
+ renderNode->setPropertyFieldsDirty(RenderNode::Y);
}
// ----------------------------------------------------------------------------
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index 3be013b..ea2f96e 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -62,7 +62,7 @@
mWeakThis = NULL;
}
- virtual void onAnimationFinished(BaseAnimator*) {
+ virtual void onAnimationFinished(BaseRenderNodeAnimator*) {
JNIEnv* env = getEnv(mJvm);
env->CallStaticVoidMethod(
gRenderNodeAnimatorClassInfo.clazz,
@@ -81,13 +81,6 @@
return static_cast<RenderPropertyAnimator::RenderProperty>(property);
}
-static inline RenderPropertyAnimator::DeltaValueType toDeltaType(jint deltaType) {
- LOG_ALWAYS_FATAL_IF(deltaType != RenderPropertyAnimator::DELTA
- && deltaType != RenderPropertyAnimator::ABSOLUTE,
- "Invalid delta type %d", deltaType);
- return static_cast<RenderPropertyAnimator::DeltaValueType>(deltaType);
-}
-
static inline CanvasPropertyPaintAnimator::PaintField toPaintField(jint field) {
LOG_ALWAYS_FATAL_IF(field < 0
|| field > CanvasPropertyPaintAnimator::ALPHA,
@@ -96,48 +89,48 @@
}
static jlong createAnimator(JNIEnv* env, jobject clazz, jobject weakThis,
- jint propertyRaw, jint deltaTypeRaw, jfloat deltaValue) {
+ jint propertyRaw, jfloat finalValue) {
RenderPropertyAnimator::RenderProperty property = toRenderProperty(propertyRaw);
- RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
- BaseAnimator* animator = new RenderPropertyAnimator(property, deltaType, deltaValue);
- animator->incStrong(0);
+ BaseRenderNodeAnimator* animator = new RenderPropertyAnimator(property, finalValue);
animator->setListener(new AnimationListenerBridge(env, weakThis));
return reinterpret_cast<jlong>( animator );
}
static jlong createCanvasPropertyFloatAnimator(JNIEnv* env, jobject clazz,
- jobject weakThis, jlong canvasPropertyPtr, jint deltaTypeRaw, jfloat deltaValue) {
- RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
+ jobject weakThis, jlong canvasPropertyPtr, jfloat finalValue) {
CanvasPropertyPrimitive* canvasProperty = reinterpret_cast<CanvasPropertyPrimitive*>(canvasPropertyPtr);
- BaseAnimator* animator = new CanvasPropertyPrimitiveAnimator(canvasProperty, deltaType, deltaValue);
- animator->incStrong(0);
+ BaseRenderNodeAnimator* animator = new CanvasPropertyPrimitiveAnimator(canvasProperty, finalValue);
animator->setListener(new AnimationListenerBridge(env, weakThis));
return reinterpret_cast<jlong>( animator );
}
static jlong createCanvasPropertyPaintAnimator(JNIEnv* env, jobject clazz,
jobject weakThis, jlong canvasPropertyPtr, jint paintFieldRaw,
- jint deltaTypeRaw, jfloat deltaValue) {
- RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
+ jfloat finalValue) {
CanvasPropertyPaint* canvasProperty = reinterpret_cast<CanvasPropertyPaint*>(canvasPropertyPtr);
CanvasPropertyPaintAnimator::PaintField paintField = toPaintField(paintFieldRaw);
- BaseAnimator* animator = new CanvasPropertyPaintAnimator(
- canvasProperty, paintField, deltaType, deltaValue);
- animator->incStrong(0);
+ BaseRenderNodeAnimator* animator = new CanvasPropertyPaintAnimator(
+ canvasProperty, paintField, finalValue);
animator->setListener(new AnimationListenerBridge(env, weakThis));
return reinterpret_cast<jlong>( animator );
}
static void setDuration(JNIEnv* env, jobject clazz, jlong animatorPtr, jint duration) {
LOG_ALWAYS_FATAL_IF(duration < 0, "Duration cannot be negative");
- BaseAnimator* animator = reinterpret_cast<BaseAnimator*>(animatorPtr);
+ BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
animator->setDuration(duration);
}
-static void unref(JNIEnv* env, jobject clazz, jlong objPtr) {
- VirtualLightRefBase* obj = reinterpret_cast<VirtualLightRefBase*>(objPtr);
- obj->decStrong(0);
+static jint getDuration(JNIEnv* env, jobject clazz, jlong animatorPtr) {
+ BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
+ return static_cast<jint>(animator->duration());
+}
+
+static void setInterpolator(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong interpolatorPtr) {
+ BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
+ Interpolator* interpolator = reinterpret_cast<Interpolator*>(interpolatorPtr);
+ animator->setInterpolator(interpolator);
}
#endif
@@ -150,11 +143,12 @@
static JNINativeMethod gMethods[] = {
#ifdef USE_OPENGL_RENDERER
- { "nCreateAnimator", "(Ljava/lang/ref/WeakReference;IIF)J", (void*) createAnimator },
- { "nCreateCanvasPropertyFloatAnimator", "(Ljava/lang/ref/WeakReference;JIF)J", (void*) createCanvasPropertyFloatAnimator },
- { "nCreateCanvasPropertyPaintAnimator", "(Ljava/lang/ref/WeakReference;JIIF)J", (void*) createCanvasPropertyPaintAnimator },
+ { "nCreateAnimator", "(Ljava/lang/ref/WeakReference;IF)J", (void*) createAnimator },
+ { "nCreateCanvasPropertyFloatAnimator", "(Ljava/lang/ref/WeakReference;JF)J", (void*) createCanvasPropertyFloatAnimator },
+ { "nCreateCanvasPropertyPaintAnimator", "(Ljava/lang/ref/WeakReference;JIF)J", (void*) createCanvasPropertyPaintAnimator },
{ "nSetDuration", "(JI)V", (void*) setDuration },
- { "nUnref", "(J)V", (void*) unref },
+ { "nGetDuration", "(J)I", (void*) getDuration },
+ { "nSetInterpolator", "(JJ)V", (void*) setInterpolator },
#endif
};
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index cdd036e..2c10212 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -26,8 +26,11 @@
#include <android_runtime/android_view_Surface.h>
#include <system/window.h>
+#include "android_view_GraphicBuffer.h"
+
#include <Animator.h>
#include <RenderNode.h>
+#include <renderthread/CanvasContext.h>
#include <renderthread/RenderProxy.h>
#include <renderthread/RenderTask.h>
#include <renderthread/RenderThread.h>
@@ -67,11 +70,31 @@
jobject mRunnable;
};
+class SetAtlasTask : public RenderTask {
+public:
+ SetAtlasTask(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size)
+ : mBuffer(buffer)
+ , mMap(map)
+ , mMapSize(size) {
+ }
+
+ virtual void run() {
+ CanvasContext::setTextureAtlas(mBuffer, mMap, mMapSize);
+ mMap = 0;
+ delete this;
+ }
+
+private:
+ sp<GraphicBuffer> mBuffer;
+ int64_t* mMap;
+ size_t mMapSize;
+};
+
class OnFinishedEvent {
public:
- OnFinishedEvent(BaseAnimator* animator, AnimationListener* listener)
+ OnFinishedEvent(BaseRenderNodeAnimator* animator, AnimationListener* listener)
: animator(animator), listener(listener) {}
- sp<BaseAnimator> animator;
+ sp<BaseRenderNodeAnimator> animator;
sp<AnimationListener> listener;
};
@@ -104,7 +127,7 @@
virtual ~RootRenderNode() {}
- virtual void callOnFinished(BaseAnimator* animator, AnimationListener* listener) {
+ virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) {
OnFinishedEvent event(animator, listener);
mOnFinishedEvents.push_back(event);
}
@@ -127,9 +150,18 @@
std::vector<OnFinishedEvent> mOnFinishedEvents;
};
-static void android_view_ThreadedRenderer_postToRenderThread(JNIEnv* env, jobject clazz,
- jobject jrunnable) {
- RenderTask* task = new JavaTask(env, jrunnable);
+static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz,
+ jobject graphicBuffer, jlongArray atlasMapArray) {
+ sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer);
+ jsize len = env->GetArrayLength(atlasMapArray);
+ if (len <= 0) {
+ ALOGW("Failed to initialize atlas, invalid map length: %d", len);
+ return;
+ }
+ int64_t* map = new int64_t[len];
+ env->GetLongArrayRegion(atlasMapArray, 0, len, map);
+
+ SetAtlasTask* task = new SetAtlasTask(buffer, map, len);
RenderThread::getInstance().queue(task);
}
@@ -275,7 +307,7 @@
static JNINativeMethod gMethods[] = {
#ifdef USE_OPENGL_RENDERER
- { "postToRenderThread", "(Ljava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_postToRenderThread },
+ { "nSetAtlas", "(Landroid/view/GraphicBuffer;[J)V", (void*) android_view_ThreadedRenderer_setAtlas },
{ "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
{ "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
{ "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
diff --git a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
new file mode 100644
index 0000000..ce6f207
--- /dev/null
+++ b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+namespace android {
+
+static void incStrong(JNIEnv* env, jobject clazz, jlong objPtr) {
+ VirtualLightRefBase* obj = reinterpret_cast<VirtualLightRefBase*>(objPtr);
+ obj->incStrong(0);
+}
+
+static void decStrong(JNIEnv* env, jobject clazz, jlong objPtr) {
+ VirtualLightRefBase* obj = reinterpret_cast<VirtualLightRefBase*>(objPtr);
+ obj->decStrong(0);
+}
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "com/android/internal/util/VirtualRefBasePtr";
+
+static JNINativeMethod gMethods[] = {
+ { "nIncStrong", "(J)V", (void*) incStrong },
+ { "nDecStrong", "(J)V", (void*) decStrong },
+};
+
+int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv* env) {
+ return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+
+} // namespace android
diff --git a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
new file mode 100644
index 0000000..704e1be
--- /dev/null
+++ b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <Interpolator.h>
+
+namespace android {
+
+using namespace uirenderer;
+
+#ifdef USE_OPENGL_RENDERER
+
+static jlong createAccelerateDecelerateInterpolator(JNIEnv* env, jobject clazz) {
+ return reinterpret_cast<jlong>(new AccelerateDecelerateInterpolator());
+}
+
+static jlong createAccelerateInterpolator(JNIEnv* env, jobject clazz, jfloat factor) {
+ return reinterpret_cast<jlong>(new AccelerateInterpolator(factor));
+}
+
+static jlong createAnticipateInterpolator(JNIEnv* env, jobject clazz, jfloat tension) {
+ return reinterpret_cast<jlong>(new AnticipateInterpolator(tension));
+}
+
+static jlong createAnticipateOvershootInterpolator(JNIEnv* env, jobject clazz, jfloat tension) {
+ return reinterpret_cast<jlong>(new AnticipateOvershootInterpolator(tension));
+}
+
+static jlong createBounceInterpolator(JNIEnv* env, jobject clazz) {
+ return reinterpret_cast<jlong>(new BounceInterpolator());
+}
+
+static jlong createCycleInterpolator(JNIEnv* env, jobject clazz, jfloat cycles) {
+ return reinterpret_cast<jlong>(new CycleInterpolator(cycles));
+}
+
+static jlong createDecelerateInterpolator(JNIEnv* env, jobject clazz, jfloat factor) {
+ return reinterpret_cast<jlong>(new DecelerateInterpolator(factor));
+}
+
+static jlong createLinearInterpolator(JNIEnv* env, jobject clazz) {
+ return reinterpret_cast<jlong>(new LinearInterpolator());
+}
+
+static jlong createOvershootInterpolator(JNIEnv* env, jobject clazz, jfloat tension) {
+ return reinterpret_cast<jlong>(new OvershootInterpolator(tension));
+}
+
+static jlong createLutInterpolator(JNIEnv* env, jobject clazz, jfloatArray jlut) {
+ jsize len = env->GetArrayLength(jlut);
+ if (len <= 0) {
+ return 0;
+ }
+ float* lut = new float[len];
+ env->GetFloatArrayRegion(jlut, 0, len, lut);
+ return reinterpret_cast<jlong>(new LUTInterpolator(lut, len));
+}
+
+#endif
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "com/android/internal/view/animation/NativeInterpolatorFactoryHelper";
+
+static JNINativeMethod gMethods[] = {
+#ifdef USE_OPENGL_RENDERER
+ { "createAccelerateDecelerateInterpolator", "()J", (void*) createAccelerateDecelerateInterpolator },
+ { "createAccelerateInterpolator", "(F)J", (void*) createAccelerateInterpolator },
+ { "createAnticipateInterpolator", "(F)J", (void*) createAnticipateInterpolator },
+ { "createAnticipateOvershootInterpolator", "(F)J", (void*) createAnticipateOvershootInterpolator },
+ { "createBounceInterpolator", "()J", (void*) createBounceInterpolator },
+ { "createCycleInterpolator", "(F)J", (void*) createCycleInterpolator },
+ { "createDecelerateInterpolator", "(F)J", (void*) createDecelerateInterpolator },
+ { "createLinearInterpolator", "()J", (void*) createLinearInterpolator },
+ { "createOvershootInterpolator", "(F)J", (void*) createOvershootInterpolator },
+ { "createLutInterpolator", "([F)J", (void*) createLutInterpolator },
+#endif
+};
+
+int register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper(JNIEnv* env) {
+ return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+
+} // namespace android
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..1880a15
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..aecb4d2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..8401f91
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..5832865
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..6d14962
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..aee057c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..fb5801e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..fdb5271
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..b8c7397
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..d0395a8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..59bb437
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..c053b90
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..eb30a79
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..1af0bff
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..3b36e7d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..c12d20a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..882365b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..f6c7094
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..0e326c9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..8bf1170
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..cedb66e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..257d7ba
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..e07b36e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..ef94200
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..ad67004
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..50796e2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..ba7be9e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..bdbfe78
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..fe89951
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..840c88f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..621d1d2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..fd8be89
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_off_qntm_alpha.png b/core/res/res/drawable-hdpi/scrubber_control_off_qntm_alpha.png
index f1023ea..5a99528 100644
--- a/core/res/res/drawable-hdpi/scrubber_control_off_qntm_alpha.png
+++ b/core/res/res/drawable-hdpi/scrubber_control_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_on_qntm_alpha.png b/core/res/res/drawable-hdpi/scrubber_control_on_qntm_alpha.png
index 15ceeee..79de664 100644
--- a/core/res/res/drawable-hdpi/scrubber_control_on_qntm_alpha.png
+++ b/core/res/res/drawable-hdpi/scrubber_control_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-hdpi/switch_off_qntm_alpha.9.png
index 90b1498..73e8f1c 100644
--- a/core/res/res/drawable-hdpi/switch_off_qntm_alpha.9.png
+++ b/core/res/res/drawable-hdpi/switch_off_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-hdpi/switch_on_qntm_alpha.9.png
index b535758..ff6affe 100644
--- a/core/res/res/drawable-hdpi/switch_on_qntm_alpha.9.png
+++ b/core/res/res/drawable-hdpi/switch_on_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..0f44ff9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..9d5dda0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..e4ce802
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..d1806ac
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..ab9315b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..46e90e6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..e8c56ff
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..59dcb7e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..e9bd4a2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..1d05037
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..91b40de
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..c531cab
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..11bb387
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..8843210
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..6ff2f3d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..a03c1e2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..0a22e1a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..2e2469c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..c1054d9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..cf8d80a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..9d9e870
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..1bad701
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..a84a54f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..4d8050b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..374172c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..233036e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..61d9b58
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..274e983
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..acf16e5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..ee48241
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..dbbb736
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..bcabd0d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_off_qntm_alpha.png b/core/res/res/drawable-mdpi/scrubber_control_off_qntm_alpha.png
index 1833704..e40cba8 100644
--- a/core/res/res/drawable-mdpi/scrubber_control_off_qntm_alpha.png
+++ b/core/res/res/drawable-mdpi/scrubber_control_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_on_qntm_alpha.png b/core/res/res/drawable-mdpi/scrubber_control_on_qntm_alpha.png
index e64d3f2..437a3e3 100644
--- a/core/res/res/drawable-mdpi/scrubber_control_on_qntm_alpha.png
+++ b/core/res/res/drawable-mdpi/scrubber_control_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-mdpi/switch_off_qntm_alpha.9.png
index ffd6c39..8949b52 100644
--- a/core/res/res/drawable-mdpi/switch_off_qntm_alpha.9.png
+++ b/core/res/res/drawable-mdpi/switch_off_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-mdpi/switch_on_qntm_alpha.9.png
index 15faff0..d727683 100644
--- a/core/res/res/drawable-mdpi/switch_on_qntm_alpha.9.png
+++ b/core/res/res/drawable-mdpi/switch_on_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
index 8eb00fa..668cff7 100644
--- a/core/res/res/drawable-nodpi/platlogo.xml
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -18,22 +18,21 @@
<viewport android:viewportHeight="25" android:viewportWidth="25" />
- <group>
- <path
- android:name="shadow"
- android:pathData="m12,2.5 a11,11 0 1,0 1,0
- M6.5,7.5
- l5,0 l0,7 l7,0 l0,5 l-12,0 z"
- android:fill="#40000000"
- />
- <path
- android:name="circle-L-ranch"
- android:pathData="m12,1.5 a11,11 0 1,0 1,0
- M6.5,6.5
- l5,0 l0,7 l7,0 l0,5 l-12,0 z"
- android:fill="#FFFFFF40"
- />
- </group>
+ <path
+ android:name="shadow"
+ android:pathData="m12,2.5 a11,11 0 1,0 1,0
+ M6.5,7.5
+ l5,0 l0,7 l7,0 l0,5 l-12,0 z"
+ android:fill="#40000000"
+ />
+ <path
+ android:name="circle-L-ranch"
+ android:pathData="m12,1.5 a11,11 0 1,0 1,0
+ M6.5,6.5
+ l5,0 l0,7 l7,0 l0,5 l-12,0 z"
+ android:fill="#FFFFFF40"
+ />
+
</vector>
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
index 37df348..b8ddb77 100644
--- a/core/res/res/drawable-nodpi/stat_sys_adb.xml
+++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml
@@ -18,13 +18,13 @@
<viewport android:viewportHeight="25" android:viewportWidth="25" />
- <group>
- <path
- android:name="adb"
- android:pathData="m3,3l8,0l0,11l11,0l0,8l-18,0z"
- android:fill="#FFFFFFFF"
- />
- </group>
+
+ <path
+ android:name="adb"
+ android:pathData="m3,3l8,0l0,11l11,0l0,8l-19,0z"
+ android:fill="#FFFFFFFF"
+ />
+
</vector>
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..25500e8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..b136e25
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..6a94e30
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..d386421
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..c811385
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..58b3267
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..0659e72
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..b4227d1
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..714ef00
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..139595b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..4491107
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..20eb752
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..532c9f2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..0d78a32
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..af29678
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..23eb9e3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..cd11e14
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..b10db83
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..efeb6fb
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..83080af
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..b9cc322
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..3b5f9c4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..58c93db
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..0f1d010
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..05a7a0f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..9345035
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..5f149b7
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..191f369
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..44e08e6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..5a9dfa0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..ee921c6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..567bb0c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_off_qntm_alpha.png b/core/res/res/drawable-xhdpi/scrubber_control_off_qntm_alpha.png
index ad72f06..729e0bf 100644
--- a/core/res/res/drawable-xhdpi/scrubber_control_off_qntm_alpha.png
+++ b/core/res/res/drawable-xhdpi/scrubber_control_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_on_qntm_alpha.png b/core/res/res/drawable-xhdpi/scrubber_control_on_qntm_alpha.png
index 7aceed1..d018a7c 100644
--- a/core/res/res/drawable-xhdpi/scrubber_control_on_qntm_alpha.png
+++ b/core/res/res/drawable-xhdpi/scrubber_control_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/switch_off_qntm_alpha.9.png
index 309b528..a7a972c 100644
--- a/core/res/res/drawable-xhdpi/switch_off_qntm_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/switch_off_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/switch_on_qntm_alpha.9.png
index 139795e..dd8910b 100644
--- a/core/res/res/drawable-xhdpi/switch_on_qntm_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/switch_on_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..1881f54
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..6f8ec2d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..c954ed9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..9d1a47e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..ce63631
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..430c134
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..cdebf83
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..40ceadb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..fb13eb2
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..d716fba
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..b8be041
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..bad0c3c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..a6368fb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..234e5d1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..3e7796d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..0673999
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..4779944
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..866f7b7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..76aae57
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..0cd470a1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..0015b39
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..2f69f5b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..77142fd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..2f81277
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..d37fe60
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..cb62079
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..82dc428
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..2cba2fb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..5de1952
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..1c22a17
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..7f652fc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..076acbd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_off_qntm_alpha.png b/core/res/res/drawable-xxhdpi/scrubber_control_off_qntm_alpha.png
index c11b0ae..a2b5716 100644
--- a/core/res/res/drawable-xxhdpi/scrubber_control_off_qntm_alpha.png
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_on_qntm_alpha.png b/core/res/res/drawable-xxhdpi/scrubber_control_on_qntm_alpha.png
index cde797e..caabc2c 100644
--- a/core/res/res/drawable-xxhdpi/scrubber_control_on_qntm_alpha.png
+++ b/core/res/res/drawable-xxhdpi/scrubber_control_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/switch_off_qntm_alpha.9.png
index 9e234af..8d79a13 100644
--- a/core/res/res/drawable-xxhdpi/switch_off_qntm_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/switch_off_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/switch_on_qntm_alpha.9.png
index b371eab..e0e4ef9 100644
--- a/core/res/res/drawable-xxhdpi/switch_on_qntm_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/switch_on_qntm_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_quantum_anim.xml b/core/res/res/drawable/btn_check_quantum_anim.xml
index 4b329ad..96715a4 100644
--- a/core/res/res/drawable/btn_check_quantum_anim.xml
+++ b/core/res/res/drawable/btn_check_quantum_anim.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,21 +14,92 @@
limitations under the License.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:versionCode="1" >
+<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:state_checked="true">
+ <bitmap android:src="@drawable/btn_check_anim_00015_qntm_alpha"
+ android:tint="?attr/colorControlActivated"
+ android:alpha="?attr/disabledAlpha" />
+ </item>
+ <item android:state_enabled="false">
+ <bitmap android:src="@drawable/btn_check_anim_00000_qntm_alpha"
+ android:tint="?attr/colorControlNormal"
+ android:alpha="?attr/disabledAlpha" />
+ </item>
+ <item android:state_checked="true" android:id="@+id/on">
+ <bitmap android:src="@drawable/btn_check_anim_00015_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:id="@+id/off">
+ <bitmap android:src="@drawable/btn_check_anim_00000_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+ <transition android:fromId="@+id/off" android:toId="@+id/on" android:reversible="true">
+ <animation-list>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_check_anim_00000_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_check_anim_00001_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_check_anim_00002_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_check_anim_00003_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_check_anim_00004_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_check_anim_00005_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_check_anim_00006_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_check_anim_00007_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_check_anim_00008_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_check_anim_00009_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_check_anim_00010_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_check_anim_00011_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_check_anim_00012_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_check_anim_00013_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_check_anim_00014_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_check_anim_00015_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ </animation-list>
+ </transition>
+</animated-selector>
- <size
- android:height="32dp"
- android:width="32dp" />
-
- <viewport
- android:viewportHeight="320"
- android:viewportWidth="320" />
-
- <group>
- <path
- android:name="check"
- android:pathData="M 232.1,80.6 L 248.5,92.1 L 145.2,239.5 L 71.5,187.8 L 83,171.5 L 140.3,211.7 z"
- android:fill="?attr/colorControlActivated" />
- </group>
-</vector>
diff --git a/core/res/res/drawable/btn_color_quantum.xml b/core/res/res/drawable/btn_color_quantum.xml
deleted file mode 100644
index 2da9226..0000000
--- a/core/res/res/drawable/btn_color_quantum.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<touch-feedback xmlns:android="http://schemas.android.com/apk/res/android"
- android:tint="?attr/colorButtonPressedColored">
- <selector>
- <item android:state_enabled="false">
- <nine-patch android:src="@drawable/btn_qntm_alpha"
- android:tint="?attr/colorButtonNormal"
- android:alpha="?attr/disabledAlpha" />
- </item>
- <item>
- <nine-patch android:src="@drawable/btn_qntm_alpha"
- android:tint="?attr/colorButtonNormalColored" />
- </item>
- </selector>
-</touch-feedback>
diff --git a/core/res/res/drawable/btn_radio_quantum_anim.xml b/core/res/res/drawable/btn_radio_quantum_anim.xml
new file mode 100644
index 0000000..5068b7a
--- /dev/null
+++ b/core/res/res/drawable/btn_radio_quantum_anim.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:state_checked="true">
+ <bitmap android:src="@drawable/btn_radio_anim_00015_qntm_alpha"
+ android:tint="?attr/colorControlActivated"
+ android:alpha="?attr/disabledAlpha" />
+ </item>
+ <item android:state_enabled="false">
+ <bitmap android:src="@drawable/btn_radio_anim_00000_qntm_alpha"
+ android:tint="?attr/colorControlNormal"
+ android:alpha="?attr/disabledAlpha" />
+ </item>
+ <item android:state_checked="true" android:id="@+id/on">
+ <bitmap android:src="@drawable/btn_radio_anim_00015_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:id="@+id/off">
+ <bitmap android:src="@drawable/btn_radio_anim_00000_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+ <transition android:fromId="@+id/off" android:toId="@+id/on" android:reversible="true">
+ <animation-list>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_radio_anim_00000_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_radio_anim_00001_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_radio_anim_00002_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_radio_anim_00003_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_radio_anim_00004_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_radio_anim_00005_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_radio_anim_00006_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_radio_anim_00007_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_radio_anim_00008_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_radio_anim_00009_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_radio_anim_00010_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_radio_anim_00011_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_radio_anim_00012_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_radio_anim_00013_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_radio_anim_00014_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="33">
+ <bitmap android:src="@drawable/btn_radio_anim_00015_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ </animation-list>
+ </transition>
+</animated-selector>
diff --git a/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml b/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
index d172b05..f82fe7a 100644
--- a/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
+++ b/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
@@ -16,22 +16,26 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false">
- <bitmap android:src="@drawable/scrubber_track_qntm_alpha"
+ <nine-patch android:src="@drawable/scrubber_track_qntm_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item>
<layer-list>
<item android:id="@id/background">
- <bitmap android:src="@drawable/scrubber_track_qntm_alpha"
+ <nine-patch android:src="@drawable/scrubber_track_qntm_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item android:id="@id/secondaryProgress">
- <bitmap android:src="@drawable/scrubber_primary_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
+ <scale android:scaleWidth="100%">
+ <nine-patch android:src="@drawable/scrubber_primary_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </scale>
</item>
<item android:id="@id/progress">
- <bitmap android:src="@drawable/scrubber_primary_qntm_alpha"
- android:tint="?attr/colorControlActivated" />
+ <scale android:scaleWidth="100%">
+ <nine-patch android:src="@drawable/scrubber_primary_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </scale>
</item>
</layer-list>
</item>
diff --git a/core/res/res/layout-xlarge/screen_action_bar.xml b/core/res/res/layout-xlarge/screen_action_bar.xml
index d2fe9fa..02c99fe 100644
--- a/core/res/res/layout-xlarge/screen_action_bar.xml
+++ b/core/res/res/layout-xlarge/screen_action_bar.xml
@@ -34,7 +34,7 @@
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
style="?android:attr/actionBarStyle"
- android:sharedElementName="android:action_bar"
+ android:viewName="android:action_bar"
android:gravity="top">
<com.android.internal.widget.ActionBarView
android:id="@+id/action_bar"
diff --git a/core/res/res/layout/alert_dialog_leanback.xml b/core/res/res/layout/alert_dialog_leanback.xml
new file mode 100644
index 0000000..8655aea
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_leanback.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/parentPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/leanback_alert_dialog_horizontal_margin"
+ android:layout_marginRight="@dimen/leanback_alert_dialog_horizontal_margin"
+ android:layout_marginTop="@dimen/leanback_alert_dialog_vertical_margin"
+ android:layout_marginBottom="@dimen/leanback_alert_dialog_vertical_margin"
+ android:orientation="vertical">
+
+ <LinearLayout android:id="@+id/topPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <LinearLayout android:id="@+id/title_template"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_vertical|start"
+ android:minHeight="@dimen/alert_dialog_title_height"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip">
+ <ImageView android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingEnd="8dip"
+ android:src="@null" />
+ <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
+ style="?android:attr/windowTitleStyle"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart" />
+ </LinearLayout>
+ <!-- If the client uses a customTitle, it will be added here. -->
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/contentPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:minHeight="64dp">
+ <ScrollView android:id="@+id/scrollView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToPadding="false">
+ <TextView android:id="@+id/message"
+ style="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
+ android:paddingTop="8dip"
+ android:paddingBottom="8dip"/>
+ </ScrollView>
+ </LinearLayout>
+
+ <FrameLayout android:id="@+id/customPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:minHeight="64dp">
+ <FrameLayout android:id="@+android:id/custom"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </FrameLayout>
+
+ <LinearLayout android:id="@+id/buttonPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ android:orientation="vertical">
+ <LinearLayout
+ style="?android:attr/buttonBarStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layoutDirection="locale"
+ android:measureWithLargestChild="true">
+ <Button android:id="@+id/button2"
+ android:layout_width="wrap_content"
+ android:layout_gravity="start"
+ android:layout_weight="1"
+ android:maxLines="2"
+ style="?android:attr/buttonBarButtonStyle"
+ android:textSize="14sp"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ android:layout_height="wrap_content" />
+ <Button android:id="@+id/button3"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_weight="1"
+ android:maxLines="2"
+ style="?android:attr/buttonBarButtonStyle"
+ android:textSize="14sp"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ android:layout_height="wrap_content" />
+ <Button android:id="@+id/button1"
+ android:layout_width="wrap_content"
+ android:layout_gravity="end"
+ android:layout_weight="1"
+ android:maxLines="2"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ style="?android:attr/buttonBarButtonStyle"
+ android:textSize="14sp"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+ </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/alert_dialog_leanback_button_panel_right.xml b/core/res/res/layout/alert_dialog_leanback_button_panel_right.xml
new file mode 100644
index 0000000..096b015
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_leanback_button_panel_right.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/parentPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/leanback_alert_dialog_horizontal_margin"
+ android:layout_marginRight="@dimen/leanback_alert_dialog_horizontal_margin"
+ android:layout_marginTop="@dimen/leanback_alert_dialog_vertical_margin"
+ android:layout_marginBottom="@dimen/leanback_alert_dialog_vertical_margin"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:id="@+id/leftPanel"
+ android:layout_width="0dp"
+ android:layout_weight="0.66"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout android:id="@+id/topPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <LinearLayout android:id="@+id/title_template"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_vertical|start"
+ android:minHeight="@dimen/alert_dialog_title_height"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip">
+ <ImageView android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingEnd="8dip"
+ android:src="@null" />
+ <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
+ style="?android:attr/windowTitleStyle"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart" />
+ </LinearLayout>
+ <!-- If the client uses a customTitle, it will be added here. -->
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/contentPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:minHeight="64dp">
+ <ScrollView android:id="@+id/scrollView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToPadding="false">
+ <TextView android:id="@+id/message"
+ style="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
+ android:paddingTop="8dip"
+ android:paddingBottom="8dip"/>
+ </ScrollView>
+ </LinearLayout>
+
+ <FrameLayout android:id="@+id/customPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:minHeight="64dp">
+ <FrameLayout android:id="@+android:id/custom"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </FrameLayout>
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/buttonPanel"
+ android:layout_width="0dp"
+ android:layout_weight="0.33"
+ android:layout_height="match_parent"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ android:paddingLeft="32dp"
+ android:paddingRight="32dp"
+ android:orientation="horizontal">
+ <LinearLayout
+ style="?android:attr/buttonBarStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:orientation="vertical"
+ android:layoutDirection="locale"
+ android:measureWithLargestChild="true">
+ <Button android:id="@+id/button1"
+ android:layout_width="match_parent"
+ android:gravity="center_vertical"
+ android:layout_weight="1"
+ android:maxLines="2"
+ style="?android:attr/buttonBarButtonStyle"
+ android:textSize="14sp"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ android:layout_height="wrap_content" />
+ <Button android:id="@+id/button3"
+ android:layout_width="match_parent"
+ android:gravity="center_vertical"
+ android:layout_weight="1"
+ android:maxLines="2"
+ style="?android:attr/buttonBarButtonStyle"
+ android:textSize="14sp"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ android:layout_height="wrap_content" />
+ <Button android:id="@+id/button2"
+ android:layout_width="match_parent"
+ android:gravity="center_vertical"
+ android:layout_weight="1"
+ android:maxLines="2"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ style="?android:attr/buttonBarButtonStyle"
+ android:textSize="14sp"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+ </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/alert_dialog_micro.xml b/core/res/res/layout/alert_dialog_micro.xml
index f8eb46c..abdbd16 100644
--- a/core/res/res/layout/alert_dialog_micro.xml
+++ b/core/res/res/layout/alert_dialog_micro.xml
@@ -20,6 +20,8 @@
android:id="@+id/parentPanel"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:background="@android:color/white"
+ android:layout_gravity="center"
android:orientation="vertical">
<LinearLayout android:id="@+id/topPanel"
diff --git a/core/res/res/layout/progress_dialog_leanback.xml b/core/res/res/layout/progress_dialog_leanback.xml
new file mode 100644
index 0000000..6bcad7a
--- /dev/null
+++ b/core/res/res/layout/progress_dialog_leanback.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="2dip"
+ android:background="@android:color/leanback_dark_gray" />
+ <LinearLayout android:id="@+id/body"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:baselineAligned="false"
+ android:padding="16dip">
+
+ <ProgressBar android:id="@android:id/progress"
+ style="?android:attr/progressBarStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:max="10000"
+ android:layout_marginEnd="16dip" />
+
+ <TextView android:id="@+id/message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index 77f537b..eb237b3 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -34,7 +34,7 @@
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
style="?attr/actionBarStyle"
- android:sharedElementName="android:action_bar"
+ android:viewName="android:action_bar"
android:gravity="top">
<com.android.internal.widget.ActionBarView
android:id="@+id/action_bar"
diff --git a/core/res/res/layout/screen_custom_title.xml b/core/res/res/layout/screen_custom_title.xml
index d02cc8b..c8952bf 100644
--- a/core/res/res/layout/screen_custom_title.xml
+++ b/core/res/res/layout/screen_custom_title.xml
@@ -31,7 +31,7 @@
<FrameLayout android:id="@android:id/title_container"
android:layout_width="match_parent"
android:layout_height="?android:attr/windowTitleSize"
- android:sharedElementName="android:title"
+ android:viewName="android:title"
style="?android:attr/windowTitleBackgroundStyle">
</FrameLayout>
<FrameLayout android:id="@android:id/content"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 790567e..6809000 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="UNIT">%2$s</xliff:g><xliff:g id="NUMBER">%1$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> dae"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> dag <xliff:g id="HOURS">%2$d</xliff:g> uur"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> dag <xliff:g id="HOURS">%2$d</xliff:g> uur"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> uur"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> u. <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> u. <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> minute"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min. <xliff:g id="SECONDS">%2$d</xliff:g> s."</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min. <xliff:g id="SECONDS">%2$d</xliff:g> s."</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sekondes"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sekonde"</string>
<string name="untitled" msgid="4638956954852782576">"<Titelloos>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinkroniseer"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Te veel <xliff:g id="CONTENT_TYPE">%s</xliff:g> uitgevee."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet se berging is vol. Vee \'n aantal lêers uit om spasie vry te maak."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Horlosieberging is vol! Vee \'n paar lêers uit om plek te maak."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Foon se berging is vol. Vee \'n aantal lêers uit om spasie vry te maak."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netwerk kan dalk gemonitor word"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Deur \'n onbekende derde party"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Luitoestel aan"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Sit tans af…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Jou tablet gaan nou afskakel."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Jou horlosie gaan nou afskakel."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Jou foon gaan nou afsit."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Wil jy afskakel?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Herlaai na veilige modus"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Vliegtuigmodus"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegtuigmodus is AAN"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegtuigmodus is AF"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Instellings"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Dienste wat jou geld kos"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Doen dinge wat jou geld kan kos."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Jou boodskappe"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"deïnstalleer kortpaaie"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Laat die program toe om Tuisskerm-kortpaaie te verwyder sonder gebruikerinmenging."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"herlei uitgaande oproepe"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Laat die program toe om te sien watter nommer tydens \'n uitgaande oproep geskakel word, met die opsie om die oproep na \'n ander nommer te herlei of die oproep heeltemal te beëindig."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Laat die program toe om uitgaande oproepe te verwerk en die nommer wat geskakel moet word te verander. Hierdie toestemming laat die program toe om uitgaande oproepe te monitor, herlei, of te voorkom."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"ontvang teksboodskappe (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Laat die program toe om SMS-boodskappe te ontvang en te verwerk. Dit beteken dat die program boodskappe wat na jou toestel gestuur is, kan monitor of uitvee, sonder dat jy dit gesien het."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"ontvang teksboodskappe (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Laat die program toe om die inhoud van die aktiewe venster op te haal. Kwaadwillige programme kan die hele venster se inhoud ophaal, en al die teks ondersoek, behalwe wagwoorde."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"aktiveer toeganklikheid tydelik"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Laat \'n program toe om toeganklikheid tydelik op die toestel te aktiveer. Kwaadwillige programme kan sonder die toestemming van die gebruiker toeganklikheid verkry."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"haal vensterteken"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Laat \'n program toe om die vensterteken te gaan haal. Kwaadwillige programme kan dalk ongemagtigde interaksie met die programvenster uitvoer deur die stelsel te verpersoonlik."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"haal raamstatistiek"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Laat \'n program toe om raamstatistiek in te samel. Kwaadwillige programme kan dalk die raamstatistiek van vensters van ander programme af naboots."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"haal vensterinligting op"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Laat \'n program toe om inligting oor vensters vanaf die vensterbestuurder op te haal. Kwaadwillige programme kan moontlik inligting ophaal wat vir interne stelselgebruik bedoel is."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filter gebeure"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Laat \'n program toe om \'n invoerfilter te registreer wat die stroom van alle gebruikergebeure filter voordat dit versend word. Kwaadwillige programme kan moontlik die stelsel-UI beheer sonder gebruikers se tussentrede."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"vergroot skerm"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Laat \'n program toe om die inhoud van \'n skerm te vergroot. Kwaadwillige programme kan die skerminhoud so omskep dat die toestel onbruikbaar word."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"gedeeltelike afskakeling"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Plaas die aktiwiteitbestuurder in \'n afsluitingstatus. Doen nie \'n volledige afsluiting nie."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"verhoed program-oorskakelings"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Laat die program toe om \'n kennisgewing uit te saai dat \'n SMS-boodskap ontvang is. Kwaadwillige programme kan dit dalk gebruik om inkomende SMS-boodskappe na te maak."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"stuur WAP-PUSH-ontvange uitsending"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Laat die program toe om \'n kennisgewing uit te saai dat \'n WAP PUSH-boodskap ontvang is. Kwaadwillige programme kan dit dalk gebruik om MMS-boodskap-ontvangsbewyse na te maak of die inhoud van enige webbladsy stilweg te vervang met kwaadwillige variante."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"stuur uitsending vir netwerktelling"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Laat die program toe om \'n kennisgewing uit te saai dat netwerke tellings moet kry. Nooit vir normale programme nodig nie."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"beperk hoeveelheid lopende prosesse"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Laat die program toe om die maksimum getal prosesse te beheer wat sal loop. Nooit nodig vir normale programme nie."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"dwing agtergrondprogramme om te sluit"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n VPN-diens te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"bind aan \'n muurpapier"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n muurpapier te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"verbind met \'n steminteraksiediens"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Laat die houer toe om met die topvlak-koppelvlak van \'n steminteraksiediens te verbind. Behoort nooit vir normale programme nodig te wees nie."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"koppel aan \'n afstandskerm"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Dit laat die houer toe om aan die top-koppelvlak van \'n afstandskerm te koppel. Behoort nooit vir gewone programme nodig te wees nie."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind aan \'n legstukdiens"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n legstuk-diens te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bind aan \'n roeteverskafferdiens"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Laat die houer toe om aan enige geregistreerde roeteverskaffers te bind. Behoort nooit vir normale programme nodig te wees nie."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"skakel met \'n toestel-admin"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Laat die houer toe om bedoelings na \'n toesteladministrateur te stuur. Dit moet nooit vir normale programme nodig wees nie."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"bind aan \'n TV-invoer"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Laat die program toe om enige geïnstalleer mediadekodeerder te gebruik om te kan dekodeer vir terugspeel."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"bestuur vertroude eiebewyse"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Laat die program CA-sertifikate as vertroude eiebewyse installeer en deïnstalleer."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"laat program gedurende ledige tyd loop"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Met hierdie toestemming kan die Android-stelsel die program in die agtergrond laat loop terwyl die toestel nie gebruik word nie."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"bind aan ledige dienste"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Hierdie toestemming laat die Android-stelsel toe om aan \'n program se ledige dienste te bind."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lees/skryf na bronne wat diag besit"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Laat die program toe om na enige hulpbron wat deur die diag-groep besit word, te skryf, byvoorbeeld lêers in /dev. Dit kan potensieel stelselstabiliteit en sekuriteit affekteer. Dit moet NET gebruik word vir hardewarespesifieke diagnose deur die vervaardiger of operateur."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"aktiveer of deaktiveer programkomponente"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Laat die program toe om persoonlike profielinligting wat op jou toestel gestoor is, soos jou naam en kontakbesonderhede, te lees. Dit beteken dat die program jou kan identifiseer en jou profielinligting moontlik aan ander mense kan stuur."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"verander jou eie kontakkaart"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Laat die program toe om persoonlike profielinligting, soos jou naam en kontakinligting, wat op jou toestel gestoor is, te verander of daarby te voeg. Dit beteken dat die program jou kan identifiseer en moontlik jou profielinligting na ander mense kan stuur."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"liggaamsensors (soos hartklopmonitors)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Laat die program toe om toegang tot data te verkry vanaf sensors wat jy gebruik om te meet wat binne jou liggaam aangaan, soos hartklop."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"lees jou sosiale stroom"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Laat die program toe om toegang tot sosiale opdaterings van jou en jou vriende te verkry en dit te sinkroniseer. Wees versigtig wanneer jy inligting deel -- dit laat die program toe om kommunikasie tussen jou en jou vriende op sosiale netwerke te lees, ongeag vertroulikheid. Let wel: hierdie toestemming mag dalk nie op alle sosiale netwerke afgedwing word nie."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"skryf aan jou sosiale stroom"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Laat die program toe om die foonkenmerke van die toestel te beheer. \'n Program met hierdie toestemming kan tussen netwerke wissel, die foonradio aan en af skakel, en dies meer, sonder om jou ooit te laat weet."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lees foonstatus en identiteit"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Laat die program toe om toegang tot die foonfunksies van die toestel te verkry. Hierdie toestemming laat die program toe om te bepaal wat die foonnommer en toestel-IDs is, of die oproep aan die gang is, en die afgeleë nommer wat deur \'n oproep verbind word."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"lees presiese foonstate"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Gee die program toegang tot presiese foonstate. Hierdie toestemming laat die program toe om die werklike oproepstatus te bepaal, of \'n oproep aktief is en of dit in die agtergrond is. Dit kan ook mislukte oproepe, presiese dataverbindingstatus en mislukte dataverbindings bepaal."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"verhoed dat tablet slaap"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"verhoed foon om te slaap"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Laat die program toe om die tablet te keer om te slaap."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Verander WiMAX-status"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Laat die program toe om die tablet aan WiMAX-netwerke te koppel en daarvan te ontkoppel."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Laat die program toe om die foon aan WiMAX-netwerke te koppel en daarvan te ontkoppel."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"gee telling vir netwerke"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Laat die program toe om netwerke te gradeer en beïnvloed watter netwerke die tablet moet verkies."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Laat die program toe om netwerke te gradeer en beïnvloed watter netwerke die foon moet verkies."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"bind saam met Bluetooth-toestelle"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Laat die program toe om die opstelling van Bluetooth op die tablet te sien, en om verbindings met saamgebinde toestelle te maak en te aanvaar."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Laat die program toe om die opstelling van die Bluetooth op die foon te sien, en om verbindings met saamgebinde toestelle te maak en te aanvaar."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Laat die program toe om kennisgewings op te haal, te bestudeer en te verwyder, insluitende die kennisgewings wat deur ander programme geplaas is."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind aan \'n kennisgewingluisteraardiens"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Laat die houer toe om aan die top-koppelvlak van \'n kennisgewingluisteraardiens te bind. Behoort nooit vir gewone programme nodig te wees nie."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"verbind met \'n toestandverskafferdiens"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Laat die houer toe om met die topvlak-koppelvlak van \'n toestandverskafferdiens te verbind. Behoort nooit vir normale programme nodig te wees nie."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"roep die opstellingprogram op wat deur die diensverskaffer voorsien is"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Laat die houer toe om die opstellingsprogram wat deur die diensverskaffer voorsien word, op te roep. Behoort nooit vir gewone programme nodig te wees nie."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"luister vir waarnemings oor netwerktoestande"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Laat \'n program luister vir waarnemings oor netwerktoestande. Behoort nooit nodig te wees vir normale programme nie."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"verander invoertoestelkalibrasie"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Laat die program toe om die kalibrasieparameters van die raakskerm te wysig. Dit behoort nooit vir normale programme nodig te wees nie."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"gaan in by DRM-sertifikate"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Laat \'n program toe om DRM-sertifikate op te stel en te gebruik. Behoort nooit vir normale programme nodig te wees nie."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Stel wagwoordreëls"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Beheer lengte en watter karakters wat in die skermontsluit-wagwoorde gebruik word."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitor pogings om skerm te ontsluit"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Laat \'n program toe om toegang tot keyguard se veilige berging te kry."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Beheer wys en versteek van keyguard"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Laat \'n program toe om keyguard te beheer."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Luister na vertrouenstaatveranderinge."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Laat \'n program toe om vir veranderinge in vertrouenstaat te luister."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Verbind met \'n vertrouensagentdiens"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Laat \'n program toe om met \'n vertrouensagentdiens te verbind."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Tree in wisselwerking met opdatering- en terugstellingstelsel"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Laat \'n program met die terugstellingstelsel en stelselopdaterings in wisselwerking tree."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Raak twee keer vir zoembeheer"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Muurpapier"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Verander muurpapier"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Kennisgewingluisteraar"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Toestandverskaffer"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN geaktiveer"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN is geaktiveer deur <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Raak om die netwerk te bestuur."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 7fac03f..56bdd24 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> ቀኖች"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> ቀን <xliff:g id="HOURS">%2$d</xliff:g> ሰዓ"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> ቀን <xliff:g id="HOURS">%2$d</xliff:g> ሰዓ"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> ሰዓ"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> ሰዓ <xliff:g id="MINUTES">%2$d</xliff:g> ደቂቃ"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> ሰዓ <xliff:g id="MINUTES">%2$d</xliff:g> ደቂቃ"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> ደቂቃዎች"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> ደቂቃ <xliff:g id="SECONDS">%2$d</xliff:g> ሴ"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> ደቂቃ <xliff:g id="SECONDS">%2$d</xliff:g> ሴ"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> ሴ"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> ሴ"</string>
<string name="untitled" msgid="4638956954852782576">"<ርዕስ አልባ>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -57,7 +46,7 @@
<string name="badPin" msgid="9015277645546710014">"የተየበከው የድሮ ፒን ትክክል አይደለም።"</string>
<string name="badPuk" msgid="5487257647081132201">"የተየብከው PUK ትክክል አይደለም።"</string>
<string name="mismatchPin" msgid="609379054496863419">"ያስገባሃቸው ፒኖች አይዛመዱም"</string>
- <string name="invalidPin" msgid="3850018445187475377">"ከ4 እስከ 8 ቁጥሮች የያዘ ፒን ተይብ"</string>
+ <string name="invalidPin" msgid="3850018445187475377">"ከ4 እስከ 8 ቁጥሮች የያዘ PIN ተይብ"</string>
<string name="invalidPuk" msgid="8761456210898036513">"8 ወይም ከዛ በላይ የሆኑ ቁጥሮችንPUK ተይብ።"</string>
<string name="needPuk" msgid="919668385956251611">"SIM ካርድዎ PUK-የተቆለፈ ነው።የPUK ኮዱን በመተየብ ይክፈቱት።"</string>
<string name="needPuk2" msgid="4526033371987193070">" SIM ለመክፈት PUK2 ተይብ።"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"ሥምሪያ"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"በጣም ብዙ <xliff:g id="CONTENT_TYPE">%s</xliff:g> ስርዞች።"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"የጡባዊ ተኮ ማከማቻ ሙሉ ነው! ቦታ ነፃ ለማድረግ አንዳንድ ፋይሎች ሰርዝ።"</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"የእጅ ሰዓት ማከማቻ ሙሉ ነው። ቦታ ለማስለቀቅ አንዳንድ ፋይሎችን ይሰርዙ።"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"የስልክ ማከማቻ ሙሉ ነው! ቦታ ነፃ ለማድረግ አንዳንድ ፋይሎች ሰርዝ።"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"አውታረ መረብ በክትትል ውስጥ ሊሆን ይችላል"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ባልታወቀ ሶስተኛ ወገን"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"መጥሪያ በርቷል"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"በመዝጋት ላይ..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"ጡባዊዎ ይዘጋል።"</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"የእርስዎ የእጅ ሰዓት ይዘጋል።"</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"ስልክዎ ይዘጋል።"</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"ዘግተህ መውጣት ትፈልጋለህ?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"በአስተማማኝ ኹነታ ውስጥ ዳግም አስጀምር"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"የአውሮፕላን ሁነታ"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"የአውሮፕላንሁነታ በርቷል"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"የአውሮፕላንሁነታ ጠፍቷል"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"ቅንብሮች"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"ገንዘብ የሚያስወጥዎ አገልግሎቶች"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ገንዘብ የሚያስወጡህን ነገሮች አድርግ።"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"መልዕክቶችዎ"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"አቋራጮችን ያራግፋል"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"መተግበሪያው ያለተጠቃሚ ጣልቃ-ገብነት የመነሻ ማያ ገጽ አቋራጮችን እንዲያስወግድ ያስችለዋል።"</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"የወጪ ጥሪዎች አቅጣጫ ቀይር"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"በወጪ ጥሪ ጊዜ ጥሪውን ወደተለየ ቁጥር ከማዞር ወይም ጥሪውን በአጠቃላይ ከመተው አማራጭ ጋር እየተደወለለት ያለውን ቁጥር እንዲያይ ያስችለዋል።"</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"መተግበሪያው ወጪ ጥሪዎችን እንዲያስኬድና የሚደወለውን ቁጥር እንዲቀይር ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው ወጪ ጥሪዎችን እንዲቆጣጠር፣ አቅጣጫ እንዲየስቀይር ወይም እንዲያግድ ይፈቅድለታል።"</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"የፅሁፍ መልዕክቶችን ተቀበል (ኤስ.ኤም.ኤስ.)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"መተግበሪያው የኤስ.ኤም.ኤስ. መልእክቶችን እንዲያነብ እና እንዲያካሂድ ይፈቅዳል። ይህ ማለት መተግበሪያው ወደ መሳሪያህ የተላኩ መልእክቶችን ላንተ ሳያሳይህ ሊቆጣጠር ወይም ሊሰርዝ ይችላል።"</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"የፅሁፍ መልዕክቶችን ተቀበል (ኤም.ኤም.ኤስ.)"</string>
@@ -286,13 +270,13 @@
<string name="permlab_sendRespondViaMessageRequest" msgid="8713889105305943200">"የበመልዕክት-በኩል-ምላሽ-ስጥ ክስተቶችን ይላኩ"</string>
<string name="permdesc_sendRespondViaMessageRequest" msgid="7107648548468778734">"መተግበሪያው ሌሎች የመልዕክት መላኪያ መተግበሪያዎች ለመጪ ጥሪዎች በመልዕክት-በኩል-ምላሽ-መስጠት ስራን እንዲይዙ ጥያቄዎች እንዲልክላቸው ያስችለዋል።"</string>
<string name="permlab_readSms" msgid="8745086572213270480">"የጽሑፍ መልዕክቶችዎን ያንብቡ (ኤስ.ኤም.ኤስ. ወይም ኤም.ኤም.ኤስ.)"</string>
- <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"መገለጫው በጡባዊ ተኮዎ ወይም በSIM ካርድዎ የተከማቹ የኤስኤምኤስ. መልዕክቶችን እንዲያነብ ይፈቅድለታል። ይህ መተግበሪያው ይዘት ወይም ሚስጥራዊነትን ከግምት ሳያስገባ ሁሉንም የኤስኤምኤስ መልዕክቶች እንዲያነብ ይፈቅድለታል።"</string>
+ <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"መገለጫው በጡባዊ ቱኮህ ወይም በSIM ካርድህ የተከማቹ የኤስ.ኤም.ኤስ. መልእክቶችን እንዲያነብ ይፈቅድለታል። ይህ መተግበሪያው ይዘት ወይም ሚስጥራዊነትን ከግምት ሳያስገባ ሁሉንም የኤስ.ኤም.ኤስ. መልእክቶች እንዲያነብ ይፈቅድለታል።"</string>
<string name="permdesc_readSms" product="default" msgid="3695967533457240550">"መገለጫው በስልክዎ ወይም በSIM ካርድዎ የተከማቹ የኤስ.ኤም.ኤስ. መልዕክቶችን እንዲያነብ ይፈቅድለታል። ይህ መተግበሪያው ይዘት ወይም ሚስጥራዊነትን ከግምት ሳያስገባ ሁሉንም የኤስ.ኤም.ኤስ. መልዕክቶች እንዲያነብ ይፈቅድለታል።"</string>
<string name="permlab_writeSms" msgid="3216950472636214774">"የጽሑፍ መልዕክቶችህን አርትዕ (ኤስ.ኤም.ኤስ. ወይም ኤም.ኤም.ኤስ.)"</string>
<string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"በጡባዊ ተኮህ ወይም ሲም ካርድህ ላይ ኤስ ኤም ኤስ መልዕክቶችን ለመፃፍ ለመተግበሪያው ይፈቅዳሉ፡፡መልዕክቶችህን ተንኮል አዘል መተግበሪያዎች ሊሰርዙ ይችላሉ፡፡"</string>
<string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"በስልክዎ ወይም ሲም ካርድዎ ላይ ኤስ ኤም ኤስ መልዕክቶችን ለመፃፍ ለመተግበሪያው ይፈቅዳሉ። መልዕክቶችዎን ተንኮል አዘል መተግበሪያዎች ሊሰርዙ ይችላሉ።"</string>
<string name="permlab_receiveWapPush" msgid="5991398711936590410">"የፅሁፍ መልዕክቶችን ተቀበል (WAP)"</string>
- <string name="permdesc_receiveWapPush" msgid="748232190220583385">"መተግበሪያው የWAP መልዕክቶችን እንዲያነብ እና እንዲያካሂድ ይፈቅዳል። ይህ ፈቃድ የተላኩልዎን መልዕክቶች ለእርስዎ ሳያሳይዎ የመቆጣጠር ወይም የመሰረዝ ብቃትን ያጠቃልላል።"</string>
+ <string name="permdesc_receiveWapPush" msgid="748232190220583385">"መተግበሪያው የWAP መልእክቶችን እንዲያነብ እና እንዲያካሂድ ይፈቅዳል። ይህ ፈቃድ የተላኩልህን መልእክቶች ላንተ ሳያሳይህ የመቆጣጠር ወይም የመሰረዝ ብቃትን ያጠቃልላል።"</string>
<string name="permlab_getTasks" msgid="6466095396623933906">"አሂድ መተግበሪያዎችን ሰርስረው ያውጡ"</string>
<string name="permdesc_getTasks" msgid="7454215995847658102">"መተግበሪያው በአሁኑ ጊዜና በቅርቡ እየተካሄዱ ስላሉ ተግባሮችን መረጃ ሰርስሮ እንዲያወጣ ይፈቅድለታል። ይህ መተግበሪያው በመሳሪያው ላይ የትኛዎቹ መተግበሪያዎች ጥቅም ላይ ስለመዋላቸው መረጃ እንዲያገኝ ሊፈቅድለት ይችላል።"</string>
<string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"በተለያዩ ተጠቃሚዎች መካከል መስተጋብር መፍጠር"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"የነቃ መስኮት ይዘትን ለመበርበር ለመተግበሪያው ይፈቅዳሉ፡፡ ጠቅላላውን የመስኮት ይዘት ለመበርበር እና ከይለፍ ቃል በስተቀር ሁሉንም ጽሑፉን ለማየት ጎጂ መተግበሪያዎች ይችላሉ፡፡"</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"ተደራሽነት በጊዜያዊነት ያነቃል"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"አንድ መተግበሪያ በጊዜያዊነት በመሣሪያው ላይ ተደራሽነትን እንዲያነቃ ያስችለዋል። ተንኮል-አዘል መተግበሪያዎች ያለተጠቃሚው ፍቃድ ተደራሽነትን ሊያነቁ ይችላሉ።"</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"የመስኮት ማስመሰያ ሰርስሮ ያወጣል"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"አንድ መተግበሪያ የመስኮት ማስመሰያውን ሰርስሮ እንዲያወጣ ያስችላል። ተንኮል-አዘል ዌር ስርዓቱት በማስመሰል ከመተግበሪያው መስኮት ጋር ያልተፈቀደ መስተጋብር ሊፈጥሩ ይችላሉ።"</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"የክፈፍ ስታቲስቲክሶችን ሰርስሮ ያወጣል"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"አንድ መተግበሪያ የክፈፍ ስታቲስቲክስን እንዲሰበስብ ያስችላል። ተንኮል-አዘል ዌር የሌሎች መተግበሪያዎች የክፈፍ ስታቲስቲክሶችን ሊመለከቱ ይችላሉ።"</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"የመስኮት መረጃን አምጣ"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"አንድ መተግበሪያ ከመስኮት አቀናባሪው ሆኖ ስለመስኮቱ መረጃ እንዲያመጣ ያስችለዋል። ተንኮል-አዘል መተግበሪያዎች ለውስጣዊ ስርዓት ጥቅም የታሰበ መረጃን ሊወስዱ ይችላሉ።"</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"ክስተቶችን አጣራ"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"አንድ መተግበሪያ የሁሉንም ተጠቃሚዎች ክስተቶች ከመላካቸው በፊት እነሱን የሚያጣራ የግቤት ማጣሪያ እንዲመዘግብ ያስችለዋል። ተንኮል-አዘል መተግበሪያዎች ተጠቃሚው ጣልቃ ሳይገባ የስርዓቱን በይነገጽ ሊቆጣጠሩት ይችላሉ።"</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"ማሳያን አጉላ"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"አንድ መተግበሪያ የአንድ ማሳያ ይዘት እንዲያጎላ ይፈቅድለታል። ተንኮል-አዘል መተግበሪያዎች መሣሪያውን ከጥቅም ውጪ በሚያደርገው ሁኔታ የማሳያ ይዘቱ ሊለውጡት ይችላሉ።"</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"ከፊል ዝጋ"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"የእንቅስቃሴውን አደራጅ ወደ ዝጋ ሁነታ አስቀምጥ።ሙሉ ለሙሉ ዝጋ አያከናውንም።"</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"የትግበራ መቀያየርን ተከላከል"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"ኤስ ኤም ኤስ መልዕክት መቀበሉን ማሳወቂያ እንዲያሰራጭ ለመተግበሪያው ይፈቅዳሉ፡፡ መጪ ኤስ ኤም ኤስ መልዕክቶችን አመሳስሎ በማቅረብ ተንኮል አዘል መተግበሪያዎች ይሄንን ሊጠቀሙበት ይችላሉ፡፡"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"የWAP-PUSH ደርስዋል ስርጭት ላክ"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"የWAP PUSH መልዕክት እንደተቀበለ ማሳወቂያ ለማሰራጨት ለመተግበሪያው ይፈቅዳሉ፡፡ ኤም ኤም ኤስ መልዕክት መቀበልን ለማስመሰል ወይም በተንኮል አዘል መሰሎች ለማንኛውም የድር ገፅ ይዘት በዝምታ ለመተካት ተንኮል አዘል መተግበሪያዎች ሊጠቀሙበት ይችላሉ፡፡"</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ለአውታረ መረቦች የነጥብ ስጥ ስርጭት ይልካል"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"መተግበሪያው አውታረ መረቦች ነጥብ እንዲያዝለት የሚፈልጉት አንድ ማሳወቂያ እንዲያሰራጭ ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"የአሂድ ሂደቶችን ቁጥር ወስን"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"የሚሄዱ ሂደቶችን የመጨረሻ ቁጥር ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ፡፡ ለመደበኛ መተግበሪያዎች መቼም አያስፈልግም፡፡"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"የጀርባ መተግበሪያዎች እንዲዘጉ አስገድዳቸው"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"የVPN ግልጋሎትን ወደ ከፍተኛ-ደረጃ በየነ ገጽ ለማሳር ለመያዣው ይፈቅዳሉ፡፡ለተለመዱ መተግበሪያዎች አያስፈልግም፡፡"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"በልጣፍ ጠርዝ"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ልጣፍ ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"ከአንድ የድምጽ በይነተገናኝ ጋር ይሰሩ"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"ያዢው የአንድ የድምጽ በይነግንኙነት አገልግሎት የከፍተኛ ደረጃ በይነገጽ እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ከአንድ የርቀት ማሳያ ጋር ይጠርዛል"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ያዢው ከአንድ የርቀት ማሳያ ከፍተኛ-ደረጃ በይነገጽ ጋር እንዲጠርዝ ይፈቅድለታል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ወደ ፍርግም አገልግሎት አያይዝ"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ፍርግም አገልግሎት ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"ከመንገድ አቅራቢዎች አገልግሎት ጋር ያስተሳስሩ"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"አቃፊው ከማናቸውም የተመዘገቡ የመንገድ አቅራቢዎች ጋር እንዲተሳሰር ይፈቅድለታል። ለመደበኛ መተግበሪያዎች በጭራሽ ሊያስፈልግ አይገባም።"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ከመሣሪያ አስተዳደር ጋር ተገናኝ"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ያዡ በይነመረብን ለመሣሪያ አስተዳዳሪ ለመላክ ይፈቅዳሉ። ለመደበኛ መተግበሪያዎች በፍፁም አያስፈልግም።"</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"ከአንድ የቴሌቪዥን ግብዓት ጋር እሰር"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"ባለቤቱ ከአንድ የቴሌቪዥን ግብዓት ከፍተኛ-ደረጃ በይነገጽ ጋር እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"የመሣሪያ አስተዳዳሪ ያክሉ ወይም ያስወግዱ"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"ያዢው ንቁ የመሣሪያ አስተዳዳሪዎች እንዲያክል ወይም እንዲያስወግድ ያስችለዋል። ለመደበኛ መተግበሪያዎች ጭራሽ ሊያስፈልግ አይገባም።"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"የማያ ገፀ አቀማመጥን ለውጥ"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ለመልሰህ አጫውት ፍታን በማንኛውም የተጫኑ በማህደረ መረጃ ዲኮደር ለመጠቀም ለመተግበሪያ ይፈቅዳል።"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"የታመኑ ምስክርነቶችን ያስተዳድሩ"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"መተግበሪያው CA የምስክር ወረቀቶችን እንደሚታመኑ ምስክርነቶች አንዲጭን እና እንዲያራግፍ ይፍቀዱ።"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"ስራ በተፈታበት ጊዜ ላይ መተግበሪያውን አሂድ"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ይህ ፍቃድ መሣሪያው ስራ ላይ ባልሆነ ጊዜ የAndroid ስርዓቱ መተግበሪያውን በጀርባ ውስጥ እንዲያሂደው ያስችለዋል።"</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"ከስራ ፈት አገልግሎቶች ጋር ይሰሩ"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"ይህ ፍቃድ የAndroid ስርዓቱ የአንድ መተግበሪያ ስራ-ፈት አገልግሎቶችን እንዲያስር ያስችለዋል።"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"በdiag ባለቤትነት ያሉ ንብረቶችን አንብብ/ፃፍ"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"በዲያግ ቡድን ባለቤትነት ወደ አለ ማንኛውም ንብረት ለምሳሌ በ/dev ያሉ ፋይሎች ለማንበብ እና ለመፃፍ ለመተግበሪያው ይፈቅዳሉ። ይህ በመሰረቱ የስርዓት መረጋጋትን እና ደህንነትን ሊጎዳ ይችላል። ይህ ውስን የሀርድዌር-ተኮር ዲያግኖስቲክስ በአምራቹ ወይም ከዋኙ ብቻ መሆን አለበት።"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"የመተግበሪያ ምንዝሮችን አንቃ ወይም አቦዝን"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"መተግበሪያው ልክ እንደ ስምዎ እና የእውቂያ መረጃዎ ያሉ በመሳሪያዎ ላይ የተከማቹ የግል መገለጫ መረጃዎችን እንዲያነብ ይፈቅድለታል። ይህም ማለት መተግበሪያው ለይቶ ሊያውቁዎ እና የመገለጫ መረጃዎን ለሌሎች ሊልክ ይችላል።"</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"የራስህን የዕውቂያ ካርድ አስተካክል"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"መተግበሪያው ልክ እንደ ስምዎ እና የእውቂያ መረጃዎ ያሉ በመሳሪያዎ ላይ የተከማቹ የግል መገለጫ መረጃዎችን እንዲቀይር ወይም እንዲያክልባቸው ይፈቅድለታል። ይህም ማለት መተግበሪያው ለይቶ ሊያውቅዎ እና የመገለጫ መረጃዎን ለሌሎች ሊልክ ይችላል።"</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"የሰውነት መመርመሪያዎች (እንደ የልብ ምት መቆጣጠሪያዎች)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"መተግበሪያው እርስዎ በሰውነትዎ ውስጥ እየተካሄዱ ያሉ እንደ የልብ ምት የመሳሰሉ ነገሮችን ለመለካት የሚጠቀሙበትን ውሂብ ከመመርመሪያዎቹ ላይ እንዲደርስ ይፈቅድለታል።"</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"የአንተን ማህበራዊ የውይይት ክፍሎች አንብብ"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"መተግበሪያው የአንተንና የጓኞችህን ማህበራዊ ዝማኔዎችን እንዲደርስባቸው እና እንዲያመሳስላቸው ይፈቅድለታል። መረጃ ስታጋራ ተጠንቀቅ -- ይህ መተግበሪያው ሚስጥራዊነትን ከግምት ሳያስገባ በማህበራዊ አውታረ መረቦች በአንተ እና በጓደኞችህ መካከል የሚደረጉ ግንኙነቶችን እንዲያነብ ይፈቅድለታል። ማስታወሻ፦ ይህ ፈቃድ ለሁሉም ማህበራዊ አውታር መረቦች ላይ ላይፈጸም ይችላል።"</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"ወደ የአንተ ማህበራዊ የውይይት ክፍሎች ጻፍ"</string>
@@ -499,11 +473,11 @@
<string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"መተግበሪያው የጓደኞችህን እና የስራ ባልደረቦችህን ጨምሮ በጡባዊ ተኮህ ላይ ልታስተካክላቸው የምትችላቸውን ክስተቶች እንዲያክል፣ እንዲያስወግድ፣ እንዲለውጥ ይፈቅድለታል። ይህ መተግበሪያው ከቀን መቁጠሪያ ባለቤቶች የመጡ የሚመስሉ መልእክቶችን እንዲልክ ወይም ያለባለቤቱ እውቀት ክስተቶችን እንዲያስተካክል ሊፈቅድለት ይችላል።"</string>
<string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"መተግበሪያው የጓደኞችዎን እና የስራ ባልደረቦችዎን ጨምሮ በስልክዎ ላይ ሊያስተካክሏቸው የሚችሏቸውን ክስተቶች እንዲያክል፣ እንዲያስወግድ፣ እንዲለውጥ ይፈቅድለታል። ይህ መተግበሪያው ከቀን መቁጠሪያ ባለቤቶች የመጡ የሚመስሉ መልዕክቶችን እንዲልክ ወይም ያለባለቤቱ እውቀት ክስተቶችን እንዲያስተካክል ሊፈቅድለት ይችላል።"</string>
<string name="permlab_accessMockLocation" msgid="8688334974036823330">"ለሙከራ ጊዜያዊ ሥፍራ ፍጠር።"</string>
- <string name="permdesc_accessMockLocation" msgid="5808711039482051824">"ለሙከራ የጊዜያዊ የመነሻ ምንጮችን ይፍጠሩ ወይም አዲስ የአካባቢ አቅራቢ ይጫኑ። ይህ መተግበሪያው አካባቢውን እና/ወይም እንደ GPS ወይም የአካባቢ አቅራቢዎች ባሉ ሌላ የመነሻ ምንጮች የተመለሱ ሁኔታዎችን ችላ እንዲል ይፈቅድለታል።"</string>
+ <string name="permdesc_accessMockLocation" msgid="5808711039482051824">"ለሙከራ የማስመሰል የመነሻ ምንጮችን ፍጠር ወይም አዲስ የአካባቢ አቅራቢ ጫን። ይህ መተግበሪያው አካባቢውን እና/ወይም እንደ GPS ወይም የአካባቢ አቅራቢዎች ባሉ ሌላ የመነሻ ምንጮች የተመለሱ ሁኔታዎችን ችላ እንዲል ይፈቅድለታል።"</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ተጨማሪ ሥፍራ አቅራቢ ትዕዛዞችን ድረስ።"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="5945166642335800763">"መተግበሪያው ተጨማሪ የአካባቢ አቅራቢ ትእዛዞችን እንዲደርስ ይፈቅድለታል። ይህ መተግበሪያው በGPS ወይም ሌላ የመነሻ ምንጮች ክወና ላይ ጣልቃ እንዲገባ ሊፈቅድለት ይችላል።"</string>
<string name="permlab_installLocationProvider" msgid="6578101199825193873">"የሥፍራ አቅራቢ ለመጫን ፍቀድ"</string>
- <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"ለሙከራ የጊዜያዊ የመነሻ ምንጮችን ይፍጠሩ ወይም አዲስ የአካባቢ አቅራቢ ይጫኑ። ይህ መተግበሪያው አካባቢውን እና/ወይም እንደ ጂፒኤስ ወይም የአካባቢ አቅራቢዎች ባሉ ሌላ የመነሻ ምንጮች የተመለሱ ሁኔታዎችን ችላ እንዲል ይፈቅድለታል።"</string>
+ <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"ለሙከራ የማስመሰል የመነሻ ምንጮችን ፍጠር ወይም አዲስ የአካባቢ አቅራቢ ጫን። ይህ መተግበሪያው አካባቢውን እና/ወይም እንደ GPS ወይም የአካባቢ አቅራቢዎች ባሉ ሌላ የመነሻ ምንጮች የተመለሱ ሁኔታዎችን ችላ እንዲል ይፈቅድለታል።"</string>
<string name="permlab_accessFineLocation" msgid="1191898061965273372">"ትክክለኛ አካባቢ (በጂ ፒ ኤስ እና አውታረ መረብ ላይ የተመሠረተ)"</string>
<string name="permdesc_accessFineLocation" msgid="5295047563564981250">"መተግበሪያው የእርስዎን አለምአቀፍ የመሬት አቀማመጥ ስርዓትን (ጂ ፒ ኤስ) ወይም እንደ የተንቀሳቃሽ ስልክ ማማዎች እና Wi-Fi ያሉ የአውታረ መረብ አካባቢ ምንጮችን ተጠቅሞ ትክክለኛ አካባቢዎትን እንዲያውቅ ያስችለዋል። መተግበሪያው እነዚህ የአካባቢ አገልግሎቶችን እንዲጠቀምባቸው እነሱ ሊበሩ እና ለመሣሪያዎ የሚገኙ መሆን አለባቸው። መተግበሪያዎች እርስዎ የት እንዳሉ ለማወቅ ይህንን ሊጠቀሙበት ይችላሉ፣ እና ተጨማሪ ባትሪ ሊፈጁ ይችላሉ።"</string>
<string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"ግምታዊ አካባቢ (በአውታረ መረብ ላይ የተመሰረተ)"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"የመገልገያ መሳሪያውን የስልክ ባህሪያት ለመቆጣጠር ለመተግበሪያው ይፈቅዳል፡፡ ከዚህ ፍቃድ ጋር መተግበሪያ አውታረ መረቦችን ሊለውጥ ይችላል፤አንተን ምንም ሳያሳውቅ የስልኩን ሬድዮ አብራ እና አጥፋ እና የመሳሰሉትን ሊያበራ ይችላል፡፡"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"የስልክ ሁኔታና ማንነት አንብብ"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"መተግበሪያው የመሳሪያውን የስልክ ባህሪያት ላይ እንዲደርስ ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው የስልክ ቁጥሩን እና የመሳሪያውን መታወቂያዎች፣ ጥሪ የነቃ እንደሆነ፣ እና በጥሪ የተገናኘውን የሩቅ ቁጥር እንዲወስን ይፈቅድለታል።"</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ትክክለኛዎቹን የስልክ ሁኔታዎች ያነብባል"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"መተግበሪያው ትክክለኛዎቹ የስልክ ሁኔታዎችን እንዲደርስባቸው ያስችለዋል። ይህ ፍቃድ መተግበሪያው የእውነተኛ ጥሪው ሁኔታ፣ አንድ ጥሪ ገባሪ ወይም ጀርባ ላይ ይሁን፣ ያልተሳኩ ጥሪዎች፣ ትክክለኛው የውሂብ ግንኙነት ሁኔታ እና የውሂብ ግንኙነት አለመሳካቶችን እንዲያውቅ ያስችለዋል።"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ጡባዊ ከማንቀላፋት ተከላከል"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ስልክ ከማንቀላፋት ተከላከል"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ጡባዊውን ከመተኛት መከልከል ለመተግበሪያው ይፈቅዳሉ።"</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"የWiMAX ሁኔታ ለውጥ"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"መተግበሪያው ጡባዊ ተኮውን ከWiMAX አውታረ መረብ ጋር እንዲያገናኝና እንዲያለያይ ይፈቅድለታል።"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"መተግበሪያው ስልኩን ከWiMAX አውታረ መረብ ጋር እንዲያገናኝና እንዲያለያይ ይፈቅድለታል።"</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ለአውታረ መረቦች ነጥብ ይሰጣል"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"መተግበሪያው ለአውታረ መረቦች ደረጃ እንዲሰጥ እና ጡባዊው የትኛዎቹን አውታረ መረቦች እንደሚመርጥ ላይ ተጽዕኖ እንዲያሳርፍ ያስችለዋል።"</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"መተግበሪያው ለአውታረ መረቦች ደረጃ እንዲሰጥ እና ስልኩ የትኛዎቹን አውታረ መረቦች እንደሚመርጥ እና ላይ ተጽዕኖ እንዲያሳርፍ ያስችለዋል።"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"ከብሉቱዝ መሣሪያዎች ጋር ተጣመር"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"መተግበሪያው በጡባዊ ተኮው ላይ ያለውን የብሉቱዝ ውቅር እንዲያይ እና ከተጣመሩ መሳሪያዎች ጋር ግንኙነቶችን እንዲያደርግና እንዲቀበል ይፈቅድለታል።"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"መተግበሪያው በስልኩ ላይ ያለውን የብሉቱዝ ውቅር እንዲያይ እና ከተጣመሩ መሳሪያዎች ጋር ግንኙነቶችን እንዲያደርግና እንዲቀበል ይፈቅድለታል።"</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"መተግበሪያው ማሳወቂያዎችን እንዲያስመጣ፣ እንዲመረምር እና እንዲያጸዳ ያስችለዋል፣ በሌሎች መተግበሪያዎች የተለጠፉትንም ጨምሮ።"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ከአንድ የማሳወቂያ አዳማጭ አገልግሎት ጋር ይሰሩ"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ያዢው የማሳወቂያ አዳማጭ አገልግሎቱን ከከፍተኛ-ደረጃ በይነገጹ ጋር እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ከአንድ የሁኔታ አቅራቢ አገልግሎት ጋር ይሰሩ"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ያዢው የአንድ የሁኔታ አቅራቢ አገልግሎት የከፍተኛ ደረጃ በይነገጽ እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን መጥራት"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ያዢው በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን እንዲጠራው ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"በአውታረ መረብ ሁኔታዎች ላይ የተስተዋሉ ነገሮችን ያዳምጣል"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"አንድ መተግበሪያ በአውታረ መረብ ሁኔታዎች ላይ የተስተዋሉ ነገሮችን እንዲያዳምጥ ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አስፈላጊ ሊሆን አይገባም።"</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"የግቤት መሣሪያ ማስተካከያ ቀይር"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"መተግበሪያው የማያ ንካ የማስተካከያ ልኬቶቹን እንዲቀይር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ ሊያስፈልግ አይገባም።"</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"የDRM የምስክር ወረቀቶች ላይ ይድረሱ"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"አንድ መተግበሪያ የDRM የምስክር ወረቀቶችን እንዲሰጥና እንዲጠቀም ያስችላል። ለመደበኛ መተግበሪያዎች በፍጹም አስፈላጊ አይሆንም።"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ደንቦች አዘጋጅ"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"በማያ-መክፈት የተፈቀዱ የይለፍ ቃል ርዝመት እና ቁምፊዎች ተቆጣጠር።"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"የማሳያ-ክፈት ሙከራዎችን አሳይ"</string>
@@ -867,7 +830,7 @@
<string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"የይለፍ ቃል ለመተየብ ንካ"</font></string>
<string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"ለመክፈት የይለፍ ቃል ተይብ"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"ለመክፈት ፒን ተይብ"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ትክክል ያልሆነ ፒን ኮድ።"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ትክክል ያልሆነ PIN ኮድ።"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"ለመክፈት፣ምናሌ ተጫን ከዛ 0"</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"የአደጋ ጊዜቁጥር"</string>
<string name="lockscreen_carrier_default" msgid="8963839242565653192">"ከአገልግሎት መስጫ ክልል ውጪ"</string>
@@ -1025,12 +988,12 @@
<string name="search_go" msgid="8298016669822141719">"ፍለጋ"</string>
<string name="searchview_description_search" msgid="6749826639098512120">"ፍለጋ"</string>
<string name="searchview_description_query" msgid="5911778593125355124">"ጥያቄ ፍለጋ"</string>
- <string name="searchview_description_clear" msgid="1330281990951833033">"ጥያቄ አጽዳ"</string>
+ <string name="searchview_description_clear" msgid="1330281990951833033">"ጥያቄ አጥራ"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"ጥያቄ አስረክብ"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"የድምፅ ፍለጋ"</string>
<string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"በመንካት አስስ ይንቃ?"</string>
- <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ማሰስን በንኪ ማንቃት ይፈልጋል። አስስ በንኪ በሚበራበት ጊዜ፣ ከጡባዊ ተኮው ጋር ለመግባባት ምን በጣትዎ ስር ወይም ምልክቶችን ማከናወን እንዳለብዎ ማብራሪያ ሊመለከቱ ወይም ሊሰሙ ይችላሉ።"</string>
- <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ማሰስን በንኪ ማንቃት ይፈልጋል። አስስ በንኪ በሚበራበት ጊዜ፣ ከስልኩ ጋር ለመግባባት ምን በጣትዎ ስር ወይም ምልክቶችን ማከናወን እንዳለብዎ ማብራሪያ ሊመለከቱ ወይም ሊሰሙ ይችላሉ።"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ማሰስን በንኪ ማንቃት ይፈልጋል። አስስ በንኪ በሚበራበት ጊዜ፣ ከጡባዊ ተኮው ጋር ለመግባባት ምን በጣትህ ስር ወይም ምልክቶችን ማከናወን እንዳለብህ ማብራሪያ ልታይ ወይም ልትሰማ ትችላለህ።"</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ማሰስን በንኪ ማንቃት ይፈልጋል። አስስ በንኪ በሚበራበት ጊዜ፣ ከስልኩ ጋር ለመግባባት ምን በጣትህ ስር ወይም ምልክቶችን ማከናወን እንዳለብህ ማብራሪያ ልታይ ወይም ልትሰማ ትችላለህ።"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"ከ1 ወር በፊት"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ከ1 ወር በፊት"</string>
<plurals name="num_seconds_ago">
@@ -1068,7 +1031,7 @@
</plurals>
<plurals name="in_num_days">
<item quantity="one" msgid="5413088743009839518">"ነገ"</item>
- <item quantity="other" msgid="5109449375100953247">"በ<xliff:g id="COUNT">%d</xliff:g> ቀኖች"</item>
+ <item quantity="other" msgid="5109449375100953247">"በ<xliff:g id="COUNT">%d</xliff:g> ቀናት"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
<item quantity="one" msgid="1849036840200069118">"1 ሴኮንድ በፊት"</item>
@@ -1100,7 +1063,7 @@
</plurals>
<plurals name="abbrev_in_num_days">
<item quantity="one" msgid="2178576254385739855">"ነገ"</item>
- <item quantity="other" msgid="2973062968038355991">"በ<xliff:g id="COUNT">%d</xliff:g> ቀኖች"</item>
+ <item quantity="other" msgid="2973062968038355991">"በ<xliff:g id="COUNT">%d</xliff:g> ቀናት"</item>
</plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"በ <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"በ <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -1158,9 +1121,9 @@
<string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> እያሄደ ነው"</string>
<string name="app_running_notification_text" msgid="4653586947747330058">"ተጨማሪ መረጃ ለማግኘት ወይም መተግበሪያውን ለማቆም ይንኩ።"</string>
<string name="ok" msgid="5970060430562524910">"እሺ"</string>
- <string name="cancel" msgid="6442560571259935130">"ይቅር"</string>
+ <string name="cancel" msgid="6442560571259935130">"ሰርዝ"</string>
<string name="yes" msgid="5362982303337969312">"እሺ"</string>
- <string name="no" msgid="5141531044935541497">"ይቅር"</string>
+ <string name="no" msgid="5141531044935541497">"ሰርዝ"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ትኩረት"</string>
<string name="loading" msgid="7933681260296021180">"በመጫን ላይ…"</string>
<string name="capital_on" msgid="1544682755514494298">"በ"</string>
@@ -1262,7 +1225,7 @@
<string name="sms_short_code_details" msgid="3492025719868078457">"ይሄ በተንቀሳቃሽ ስልክ መለያዎ ላይ "<font fgcolor="#ffffb060">"ክፍያዎችን ሊያስከትል ይችላል"</font>"።"</string>
<string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"ይሄ በተንቀሳቃሽ ስልክ መለያዎ ላይ ክፍያዎችን ያስከትላል።"</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"ላክ"</string>
- <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"ይቅር"</string>
+ <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"ሰርዝ"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"ምርጫዬን አስታውስ"</string>
<string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"ይሄንን በኋላ ላይ በቅንብሮች > መተግበሪያዎች ውስጥ ሊቀይሩት ይችላሉ"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"ሁልጊዜ ፍቀድ"</string>
@@ -1276,7 +1239,7 @@
<string name="time_picker_dialog_title" msgid="8349362623068819295">"ጊዜ አዘጋጅ"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"ውሂብ አዘጋጅ"</string>
<string name="date_time_set" msgid="5777075614321087758">"አዘጋጅ"</string>
- <string name="date_time_done" msgid="2507683751759308828">"ተከናውኗል"</string>
+ <string name="date_time_done" msgid="2507683751759308828">"ተጠናቋል"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"አዲስ፦ "</font></string>
<string name="perms_description_app" msgid="5139836143293299417">"በ<xliff:g id="APP_NAME">%1$s</xliff:g> የቀረበ።"</string>
<string name="no_permissions" msgid="7283357728219338112">"ምንም ፍቃዶች አይጠየቁም"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"አንድ መተግበሪያ ደህንነቱ በቁልፍ የተጠበቀ ማከማቻ እንዲደርስ ያስችለዋል።"</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"የቁልፍ መጠበቂያውን ማሳየት እና መደበቅ ይቆጣጠሩ"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"አንድ መተግበሪያ የቁልፍ መጠበቂያውን እንዲቆጣጠር ያስችለዋል።"</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"የተአማኒነት ሁኔታ ለውጦችን አዳምጥ።"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"መተግበሪያው በተአማኒነት ሁኔታ ውስጥ ለውጦችን እንዲያዳምጥ ይፈቅዳል።"</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ለተአማኒነት ወኪል አገልግሎት ተገዢ አድርግ"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"ለመተግበሪያን የተአማኒነት ወኪል አገልግሎትን እንዲያከብር ይፈቅዳል።"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"ከዝማኔዎች እና ከመልሶ ማግኛ ስርዓቶች ጋር ይገናኙ"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"መተግበሪያው ከመልሶ ማግኛ ስርዓት እና ከስርዓት ማዘመኛዎች ጋር እንዲገናኝ ይፈቅድለታል።"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"ለአጉላ መቆጣጠሪያ ሁለት ጊዜ ነካ አድርግ"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"ልጣፍ"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"ልጣፍ ለውጥ"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ማሳወቂያ አዳማጭ"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"የሁኔታ አቅራቢ"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN ነቅቷል።"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN በ<xliff:g id="APP">%s</xliff:g>ገብሯል"</string>
<string name="vpn_text" msgid="3011306607126450322">"አውታረመረብ ለማደራጀት ንካ።"</string>
@@ -1465,7 +1423,7 @@
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"ዓመት ጨምር"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ዓመት ቀንስ"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
- <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ይቅር"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ተወው"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ሰርዝ"</string>
<string name="keyboardview_keycode_done" msgid="1992571118466679775">"ተከናውኗል"</string>
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ሞድ ለውጥ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index a32c74c..f90b65d 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"تيرابايت"</string>
<string name="petabyteShort" msgid="5637816680144990219">"بيتابايت"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> يوم"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> يوم <xliff:g id="HOURS">%2$d</xliff:g> ساعة"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> يوم <xliff:g id="HOURS">%2$d</xliff:g> ساعة"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> ساعة"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> ساعة <xliff:g id="MINUTES">%2$d</xliff:g> دقيقة"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> ساعة <xliff:g id="MINUTES">%2$d</xliff:g> دقيقة"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> دقيقة"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> دقيقة <xliff:g id="SECONDS">%2$d</xliff:g> ثانية"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> دقيقة <xliff:g id="SECONDS">%2$d</xliff:g> ثانية"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> ثانية"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> ثانية"</string>
<string name="untitled" msgid="4638956954852782576">"<بلا عنوان>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"مزامنة"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"عمليات حذف <xliff:g id="CONTENT_TYPE">%s</xliff:g> كثيرة للغاية."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"سعة تخزين الجهاز اللوحي ممتلئة! احذف بعض الملفات لإخلاء مساحة."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"سعة تخزين المشاهدة ممتلئة! احذف بعض الملفات لتحرير مساحة."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"سعة تخزين الهاتف ممتلئة. احذف بعض الملفات لإخلاء مساحة."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"قد تكون الشبكة مراقبة"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"بواسطة جهة خارجية غير معلومة"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"تشغيل الرنين"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"جارٍ إيقاف التشغيل..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"سيتم إيقاف تشغيل الجهاز اللوحي."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"سيتم إيقاف المشاهدة."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"سيتم إيقاف تشغيل هاتفك."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"هل تريد إيقاف التشغيل؟"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"إعادة تشغيل في الوضع الآمن"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"وضع الطائرة"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"وضع الطائرة قيد التشغيل"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"وضع الطائرة متوقف"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"الإعدادات"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"الخدمات التي تكلفك المال"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"يمكنك تنفيذ إجراءات يمكن أن تكلفك مالاً."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"رسائلك"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"إزالة الاختصارات"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"للسماح للتطبيق بإزالة اختصارات من الشاشة الرئيسية بدون تدخل المستخدم."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"إعادة توجيه المكالمات الصادرة"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"للسماح للتطبيق بالاطلاع على الرقم الذي يتم الاتصال به عند إجراء مكالمة صادرة مع وجود الخيار لإعادة توجيه المكالمة إلى رقم آخر أو إنهاء المكالمة تمامًا."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"للسماح للتطبيق بمعالجة المكالمات الصادرة وتغيير الرقم المطلوب. يتيح هذا الإذن للتطبيق مراقبة المكالمات الصادرة أو إعادة توجيهها أو منعها."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"تلقي رسائل نصية (رسائل قصيرة SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"للسماح للتطبيق بتلقي ومعالجة الرسائل القصيرة SMS. وهذا يعني أنه يمكن للتطبيق مراقبة الرسائل التي يتم إرسالها إلى جهازك أو حذفها بدون عرضها لك."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"تلقي رسائل نصية (رسائل وسائط متعددة)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"للسماح للتطبيق باسترداد محتوى النافذة النشطة. يمكن للبرامج الضارة استرداد محتوى النافذة بالكامل وفحص جميع النصوص الموجودة بها باستثناء كلمات المرور."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"تمكين إمكانية الدخول مؤقتًا"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"يتيح لتطبيق تمكين إمكانية الدخول مؤقتًا بالجهاز. قد تتيح التطبيقات الضارة تمكين إمكانية الدخول بدون موافقة المستخدم."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"استرداد النافذة التي تم التقاطها"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"يتيح للتطبيق استعادة النافذة التي تم التقاطها. وقد تتمكن التطبيقات الضارة من تنفيذ تفاعل غير مصرح به مع نافذة التطبيق التي تنتحل صفة النظام."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"استرداد الإحصاءات الإطارية"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"يتيح للتطبيق جمع إحصاءات إطارية. وقد تتمكن التطبيقات الضارة من رصد الإحصاءات الإطارية للنوافذ من تطبيقات أخرى."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"استرداد معلومات النوافذ"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"للسماح لأحد التطبيقات باستعادة معلومات حول النوافذ من مدير النوافذ. يمكن أن تستعيد التطبيقات الضارة معلومات الغرض منها استخدام النظام الداخلي."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"تصفية الأحداث"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"للسماح لأحد التطبيقات بتسجيل فلتر إدخال يعمل على تصفية مجموعة البث من جميع أحداث المستخدمين قبل إرسالها. يمكن أن يتحكم برنامج ضار في واجهة المستخدم النظام دون تدخل المستخدم."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"تكبير الشاشة"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"للسماح للتطبيق بتكبير محتوى شاشة. قد تؤدي التطبيقات الضارة إلى نقل محتوى الشاشة بطريقة تعرض الجهاز في وضع غير قابل للاستخدام."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"إيقاف تشغيل جزئي"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"لوضع مدير الأنشطة في حالة إيقاف التشغيل. لا يتم تنفيذ إيقاف تشغيل كامل."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"منع التبديل بين التطبيقات"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"للسماح للتطبيق ببث إشعار باستلام رسالة قصيرة SMS. قد تستخدم التطبيقات الضارة هذا لتزييف الرسائل القصيرة SMS الواردة."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"إرسال بث WAP-PUSH المستلم"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"للسماح للتطبيق ببث إشعار باستلام رسالة WAP PUSH. يمكن أن تستخدم التطبيقات الضارة هذا لتزيف استلام رسالة وسائط متعددة أو لاستبدال محتوى أي صفحة ويب بمتغيرات ضارة بشكل غير ملحوظ."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"إرسال بث الشبكات التي تم تقييمها"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"السماح للتطبيق لكي يبث إشعارًا يفيد بأنه يلزم تقييم الشبكات. لا يلزم ذلك مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"تحديد عدد العمليات قيد التشغيل"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"للسماح للتطبيق بالتحكم في الحد الأقصى لعدد العمليات التي سيتم تشغيلها. غير مطلوب على الإطلاق للتطبيقات العادية."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"فرض إغلاق تطبيقات الخلفية"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الشبكة الظاهرية الخاصة (VPN). لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"الالتزام بخلفية ما"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"للسماح للمالك بالالتزام بواجهة المستوى العلوي للخلفية. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"الربط بخدمة التفاعل الصوتي"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"للسماح للمالك بالربط بواجهة المستوى العلوي لخدمة التفاعل الصوتي. لن تكون هناك حاجة إلى هذا الإعداد مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"الربط بالشاشة عن بُعد"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"للسماح للمالك بالالتزام بواجهة المستوى العلوي للعرض عن بُعد. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"الالتزام بخدمة أداة"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الأداة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"الربط مع خدمة مزود طريق"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"للسماح لحامل البطاقة الربط مع أي مزود طريق مسجل. لا يجب استخدامه على الإطلاق مع التطبيقات العادية."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"التفاعل مع مشرف الجهاز"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"للسماح للمالك بإرسال الأهداف إلى أحد مشرفي الجهاز. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"الالتزام بإدخال التلفزيون"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"السماح للتطبيق باستخدام أي برنامج فك تشفير وسائط مثبت لفك التشفير من أجل التشغيل."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"إدارة بيانات الاعتماد الموثوقة"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"السماح للتطبيق بتثبيت شهادات CA وإلغاء تثبيتها باعتبارها بيانات اعتماد محل ثقة."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"تشغيل التطبيق أثناء وقت الخمول"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"يتيح هذا الإذن لنظام Android تشغيل التطبيق في الخلفية في حين أن الجهاز ليس قيد الاستخدام."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"الالتزام بالخدمات الخاملة"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"يتيح هذا الإذن لنظام Android الارتباط بخدمات وضع الخمول لأحد التطبيقات."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"قراءة/كتابة إلى الموارد المملوكة بواسطة التشخيص"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"للسماح للتطبيق بالقراءة والكتابة إلى أي مورد مملوك بواسطة مجموعة التشخيصات؛ على سبيل المثال، الملفات في /dev. من المحتمل أن يؤثر ذلك في استقرار النظام وأمانه. يجب ألا يستخدم ذلك سوى للتشخيصات الخاصة بالنظام من قِبل المصنِّع أو المشغِّل."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"تمكين مكونات التطبيق أو تعطيلها"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"للسماح للتطبيق بقراءة المعلومات الشخصية في الملف الشخصي المخزنة على الجهاز، مثل اسمك ومعلومات جهات الاتصال. ويعني ذلك أنه يمكن للتطبيق التعرف عليك كما يمكنه إرسال معلومات ملفك الشخصي إلى الآخرين."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"تعديل بطاقة جهة الاتصال الخاصة"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"للسماح للتطبيق بتغيير المعلومات الشخصية في الملف الشخصي المخزنة على الجهاز أو الإضافة إليها، مثل اسمك ومعلومات جهات الاتصال. ويعني ذلك أنه يمكن للتطبيق التعرف عليك كما يمكنه إرسال معلومات ملفك الشخصي إلى الآخرين."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"أجهزة استشعار الجسم (مثل شاشات معدل ضربات القلب)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"للسماح للتطبيق بالدخول إلى البيانات من أجهزة الاستشعار التي تستخدمها لقياس ما يجري داخل جسمك، مثل معدل ضربات القلب."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"قراءة المشاركات الاجتماعية"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"للسماح للتطبيق بالدخول إلى التحديثات الاجتماعية منك ومن أصدقائك ومزامنتها. توخ الحذر عند مشاركة المعلومات، حيث يتيح هذا للتطبيق قراءة عمليات التواصل بينك وبين أصدقائك على الشبكات الاجتماعية، بغض النظر عن مدى السرية. ملاحظة: لا يجوز فرض هذا الإذن على جميع الشبكات الاجتماعية."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"كتابة إلى المشاركات الاجتماعية"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"للسماح للتطبيق بالتحكم في ميزات الهاتف بالجهاز. يمكن لأحد التطبيقات بهذا الإذن تبديل الشبكات وتشغيل لاسلكي الهاتف وإيقاف تشغيله وما إلى ذلك بدون إعلامك على الإطلاق."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"قراءة حالة الهاتف والهوية"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"للسماح للتطبيق بالدخول إلى ميزات الهاتف في الجهاز. ويتيح هذا الإذن للتطبيق تحديد رقم الهاتف ومعرّفات الجهاز، وما إذا كانت هناك مكالمة نشطة والرقم البعيد الذي تم الاتصال به في المكالمة."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"قراءة حالات الهاتف الدقيقة"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"للسماح للتطبيق بالوصول إلى حالات الهاتف الدقيقة. يتيح هذا الإذن للتطبيق تحديد حالة المكالمة الفعلية، سواء أكانت مكالمة نشطة أم في الخلفية، وإخفاق الاتصال، وحالة اتصال البيانات الدقيقة، وإخفاق اتصال البيانات."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"منع الجهاز اللوحي من الدخول في وضع السكون"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"منع الهاتف من الدخول في وضع السكون"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"للسماح للتطبيق بمنع الجهاز اللوحي من الانتقال إلى وضع السكون."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"تغيير حالة WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"للسماح للتطبيق بتوصيل الجهاز اللوحي بشبكات WiMAX وقطع اتصاله بها."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"للسماح للتطبيق بتوصيل الهاتف بشبكات WiMAX وقطع اتصاله بها."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"تقييم الشبكات"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"للسماح للتطبيق بترتيب الشبكات وتحديد تلك الشبكات التي من المفضل أن يستخدمها الجهاز اللوحي."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"للسماح للتطبيق بترتيب الشبكات وتحديد تلك الشبكات التي من المفضل أن يستخدمها الهاتف."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"الاتصال بأجهزة بلوتوث"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"للسماح للتطبيق بعرض تهيئة البلوتوث على الجهاز اللوحي وإجراء اتصالات وقبولها مع الأجهزة المقترنة."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"للسماح للتطبيق بعرض تهيئة البلوتوث على الهاتف وإجراء اتصالات وقبولها مع الأجهزة المقترنة."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"يتيح للتطبيق استرجاع الإشعارات وفحصها ومسحها، بما في ذلك تلك التي نشرتها تطبيقات أخرى."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"الربط بخدمة تلقّي الإشعارات الصوتية"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"يتيح للمالك الربط بواجهة المستوى العلوي لخدمة تلقّي الإشعارات الصوتية. ولن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"الربط بخدمة موفر الحالة"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"للسماح للمالك بالربط بواجهة المستوى العلوي لخدمة موفر الحالة. لن تكون هناك حاجة إلى هذا الإعداد مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"استدعاء تطبيق التهيئة الذي يوفره مشغل شبكة الجوال"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"للسماح للمالك باستدعاء تطبيق التهيئة الذي يوفره مشغل شبكة الجوال. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"الاستماع إلى ملاحظات حول أحوال الشبكة"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"للسماح للتطبيق بالاستماع إلى ملاحظات حول أحوال الشبكة. لا حاجة إلى هذا مع التطبيقات العادية."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"تغيير معايرة أجهزة الإدخال"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"يتيح للتطبيق إمكانية تعديل معلمات المعايرة في شاشة اللمس. يجب عدم اللجوء إليه مع التطبيقات العادية."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"الدخول إلى شهادات DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"للسماح لأحد التطبيقات بتقديم شهادات DRM واستخدامها. لا يجب أن يكون ذلك لازمًا مطلقًا مع التطبيقات العادية."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"تعيين قواعد كلمة المرور"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"يمكنك التحكم في الطول والأحرف المسموح بها في كلمات مرور إلغاء تأمين الشاشة."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"مراقبة محاولات إلغاء قفل الشاشة"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"السماح لأحد التطبيقات بالدخول إلى التخزين المحمي بقفل المفاتيح."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"التحكم في عرض وإخفاء قفل المفاتيح"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"للسماح لأحد التطبيقات بالتحكم في قفل المفاتيح."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"معرفة تغييرات حالة الاعتماد."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"للسماح للتطبيق بالتعرف على التغييرات في حالة الاعتماد."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"الالتزام بخدمة الوكيل المعتمد"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"للسماح لأحد التطبيقات بالالتزام بخدمة الوكيل المعتمد."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"التفاعل مع نظام التحديث والاسترداد"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"للسماح للتطبيق بالتفاعل مع نظام الاسترداد وتحديثات النظام."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"المس مرتين للتحكم في التكبير/التصغير"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"الخلفية"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"تغيير الخلفية"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"برنامج تلقّي الإشعارات الصوتية"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"موفر الحالة"</string>
<string name="vpn_title" msgid="19615213552042827">"تم تنشيط الشبكة الظاهرية الخاصة (VPN)"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"تم تنشيط VPN بواسطة <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"المس لإدارة الشبكة."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 3ebe798..218d54a 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"ТБ"</string>
<string name="petabyteShort" msgid="5637816680144990219">"ПБ"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> дни"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> ден <xliff:g id="HOURS">%2$d</xliff:g> ч"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> ден <xliff:g id="HOURS">%2$d</xliff:g> ч"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> ч"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> ч <xliff:g id="MINUTES">%2$d</xliff:g> мин"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> ч <xliff:g id="MINUTES">%2$d</xliff:g> мин"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> мин"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> мин <xliff:g id="SECONDS">%2$d</xliff:g> сек"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> мин <xliff:g id="SECONDS">%2$d</xliff:g> сек"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> сек"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> сек"</string>
<string name="untitled" msgid="4638956954852782576">"<Без заглавие>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синхронизиране"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Изтриванията за <xliff:g id="CONTENT_TYPE">%s</xliff:g> са твърде много."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Хранилището на таблета е пълно. Изтрийте файлове, за да освободите място."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Хранилището на часовника е пълно. Изтрийте файлове, за да освободите място."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Хранилището на телефона е пълно. Изтрийте файлове, за да освободите място."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мрежата може да се наблюдава"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"От неизвестна трета страна"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Звъненето е включено"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Изключва се..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Таблетът ви ще се изключи."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Часовникът ви ще се изключи."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Телефонът ви ще се изключи."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Искате ли да изключите?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Рестартиране в безопасен режим"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Самолетен режим"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Самолетният режим е ВКЛЮЧЕН"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Самолетният режим е ИЗКЛЮЧЕН"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Настройки"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Услуги, които ви струват пари"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Извършват неща, които могат да ви струват пари."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Вашите съобщения"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"деинсталиране на преки пътища"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Разрешава на приложението да премахва преки пътища от началния екран без намеса на потребителя."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"пренасочване на изходящите обаждания"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Разрешава на приложението да вижда набирания номер по време на изходящо обаждане и му дава възможност да пренасочи обаждането към друг номер или да го прекрати изцяло."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Разрешава на приложението да обработва изходящите обаждания и да променя номера, който да се набере. Това разрешение му позволява да наблюдава, пренасочва или не допуска изходящи обаждания."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"получаване на текстови съобщения (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Разрешава на приложението да получава и обработва SMS съобщения. Това означава, че то може да наблюдава или изтрива изпратените до устройството ви, без да ви ги покаже."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"получаване на текстови съобщения (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Разрешава на приложението да извлича съдържанието от активния прозорец. Злонамерените приложения могат да извлекат цялото му съдържание и да проследят целия текст в него освен паролите."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"временно активиране на достъпността"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Разрешава на приложението временно да активира достъпността на устройството. Злонамерените приложения може да я активират без съгласието на потребителя."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"извличане на означението за прозорци"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Разрешава на приложението да извлича означението за прозорци. Представяйки се за системата, злонамерените приложения може да извършат неупълномощено взаимодействие с прозореца на приложението."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"извличане на статистически данни за кадрите"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Разрешава на приложението да събира статистически данни за кадрите. Злонамерените приложения може да наблюдават тези данни за прозорците на други приложения."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"извличане на информация за прозорците"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Разрешава на приложението да извлича информация за прозорците от съответния мениджър. Злонамерените приложения може да извличат данни, които са предназначени за вътрешно използване от системата."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"филтриране на събитията"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Разрешава на приложението да регистрира входящ филтър, който филтрира потока на всички потребителски събития преди изпращането им. Злонамерено приложение може да контролира системния потребителски интерфейс без намесата на потребителя."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"промяна на мащаба на дисплея"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Разрешава на приложението да променя мащаба на съдържанието на дисплей. Злонамерените приложения може да преобразят съдържанието на дисплея по начин, който изобразява устройството като неизползваемо."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"частично изключване"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Изключва диспечера на дейностите. Не извършва пълно изключване."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"предотвратяване на превключването между приложения"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Разрешава на приложението да излъчва известие, че е получен SMS. Злонамерените приложения могат да използват това, за да фалшифицират входящите SMS съобщения."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"изпращане на излъчване при получено WAP PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Разрешава на приложението да излъчва известие, че е получено WAP PUSH съобщение. Злонамерените приложения могат да използват това, за да фалшифицират получаването на MMS или скрито да заменят съдържанието на произволна уеб страница със злонамерен вариант."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"изпращане на излъчване за оценяване на мрежите"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Разрешава на приложението да излъчи известие, че мрежите трябва да бъдат оценени. Не е необходимо за нормалните приложения."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"ограничаване на броя изпълнявани процеси"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Разрешава на приложението да контролира максималния брой изпълнявани процеси. Нормалните приложения никога не се нуждаят от това."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"принудително затваряне на приложенията на заден план"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за VPN. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"обвързване с тапет"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на тапет. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"свързване с услуга за гласово взаимодействие"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Разрешава на притежателя да се свърже с интерфейса от най-високото ниво на услуга за гласово взаимодействие. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"свързване с отдалечен екран"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Разрешава на притежателя да се свърже с интерфейса от първо ниво на отдалечен екран. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"обвързване с услуга за приспособления"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за приспособления. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"свързване с услуга за предоставяне на маршрути"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Разрешава на собственика да се свързва с всички регистрирани доставчици на маршрути. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаимодействие с администратор на устройството"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Разрешава на притежателя да изпраща намерения до администратор на устройството. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"свързване към вход на телевизор"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Разрешава на притежателя да се свърже към интерфейса от най-високото ниво за вход на телевизор. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"добавяне или премахване на администратор на устройства"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Разрешава на притежателя да добавя или премахва администратори на активни устройства. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"промяна на ориентацията на екрана"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Разрешава на приложението да използва всеки инсталиран медиен декодер с цел декодиране за възпроизвеждане."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"управление на надеждните идентификационни данни"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Разрешава на приложението да инсталира и деинсталира сертификати от сертифициращи органи като надеждни идентификационни данни."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"изпълняване на приложението по време на неактивност"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Това разрешение позволява на системата Android да изпълнява приложението на заден план, докато устройството не се използва."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"обвързване с услуги при неактивност"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Това разрешение позволява на системата Android да се свързва с неактивните услуги на приложението."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"четене/запис в ресурси, притежавани от diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Разрешава на приложението да чете и записва във всеки ресурс, притежаван от групата diag, например файловете в /dev. Това потенциално може да засегне стабилността и сигурността на системата. То трябва да се използва САМО за диагностика, конкретно за хардуера, от страна на производителя или оператора."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"активиране или деактивиране на компоненти на приложенията"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Разрешава на приложението да чете информацията от личния потребителски профил, съхранена на устройството ви, например вашето име и данни за връзка. Това означава, че приложението може да ви идентифицира и да изпраща информацията за потребителския ви профил на други хора."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"промяна на собств. ви карт. с данни за контакт"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Разрешава на приложението да променя или добавя към личния потребителски профил информация, съхранена на устройството ви, като например вашето име и данни за връзка. Това означава, че приложението може да ви идентифицира и да изпраща данните за потребителския ви профил на други хора."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"телесни сензори (като монитори за сърдечния ритъм)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Разрешава на приложението да осъществява достъп до данни от използваните от вас сензори, за да измери какво се случва в тялото ви, като например сърдечен ритъм."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"четене на социалния ви поток"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Разрешава на приложението да осъществява достъп и да синхронизира социални актуализации от вас и приятелите ви. Бъдете внимателни при споделянето на информация – това позволява на приложението да чете съобщения помежду ви в социалните мрежи независимо от поверителността. Забележка: Възможно е ограниченията на това разрешение да не могат да бъдат наложени във всички социални мрежи."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"писане в социалния ви поток"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Разрешава на приложението да контролира телефонните функции на устройството. Приложение с такова разрешение може да превключва между мрежи, да включва и изключва радиомодула на телефона и други подобни, без изобщо да ви известява."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"четене на състоянието и идентификационните данни на телефона"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Разрешава на приложението достъп до телефонните функции на устройството. Това разрешение позволява на приложението да определя телефонния номер и идентификационния номер на устройството, дали се води разговор и отдалечения номер, до който е установена връзка с обаждането."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"четене на точните състояния на телефона"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Позволява на приложението да осъществява достъп до точните състояния на телефона. С това разрешение то може да определи действителното състояние на обаждането – дали е активно, или е на заден план, дали е неуспешно, точното състояние на връзката за пренос на данни и неуспешната връзка за пренос."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"предотвратяване на спящия режим на таблета"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"предотвратява спящ режим на телефона"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Разрешава на приложението да предотвратява преминаването на таблета в спящ режим."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Промяна на състоянието на WiMAX мрежата"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Разрешава на приложението да свързва таблета към WiMAX мрежа и да прекратява връзката му с нея."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Разрешава на приложението да свързва телефона към WiMAX мрежа и да прекратява връзката му с нея."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"оценяване на мрежите"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Разрешава на приложението да класира мрежите и да повлияе върху това, кои да са предпочитаните за таблета."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Разрешава на приложението да класира мрежите и да повлияе върху това, кои да са предпочитаните за телефона."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"сдвояване с устройства с Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Разрешава на приложението да вижда конфигурацията на Bluetooth на таблета и да изгражда и приема връзки със сдвоени устройства."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Разрешава на приложението да вижда конфигурацията на Bluetooth на телефона и да изгражда и приема връзки със сдвоени устройства."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Разрешава на приложението да извлича, преглежда и изчиства известия, включително публикуваните от други приложения."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"обвързване с услуга за слушател на известия"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Разрешава на притежателя да се обвърже с интерфейса от първо ниво на услуга за слушател на известия. Нормалните приложения не би трябвало никога да се нуждаят от това."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"свързване с услуга за предоставяне на условия"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Разрешава на притежателя да се свърже с интерфейса от най-високото ниво на услуга за предоставяне на условия. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"извикване на предоставеното от оператора приложение за конфигуриране"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Разрешава на притежателя да извиква предоставеното от оператора приложение за конфигуриране. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"слушане за наблюдения на мрежовите условия"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Разрешава на приложението да слуша за наблюдения на мрежовите условия. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"промяна на калибрирането на устройството за въвеждане"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Разрешава на приложението да променя параметрите на калибриране на сензорния екран. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"достъп до сертификатите за управление на цифровите права (DRM)"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Разрешава на приложението да обезпечава и използва сертификатите за управление на цифровите права (DRM). Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Задаване на правила за паролата"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролирайте дължината и разрешените знаци за паролите за отключване на екрана."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Наблюдаване на опитите за отключване на екрана"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Позволява на приложението да осъществява достъп до надеждното хранилище, свързано с функцията за защита на клавишите."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Контролиране на показването и скриването на функцията за защита на клавишите"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Разрешава на приложението да контролира функцията за защита на клавишите."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Следене за промени в състоянието на надеждност"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Разрешава на приложението да следи за промени в състоянието на надеждност."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Обвързване с услуга за trust agents"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Разрешава на приложението да се обвърже с услуга за trust agents."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Взаимодействие със системата за актуализации и възстановяване"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Разрешава на приложението да взаимодейства със системата за възстановяване и системните актуализации."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Докоснете двукратно за управление на промяната на мащаба"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Тапет"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Промяна на тапета"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Слушател на известия"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Доставчик на условия"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN е активирана"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN е активирана от <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Докоснете за управление на мрежата."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index a767e7f..44757fd 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> dies"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> dia <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> dia <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> hores"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> minuts"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
<string name="untitled" msgid="4638956954852782576">"<Sense títol>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,9 +135,8 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronització"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Massa supressions de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"L\'emmagatzematge de la tauleta és ple. Suprimeix uns quants fitxers per alliberar espai."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"L\'emmagatzematge del rellotge està ple. Suprimeix uns quants fitxers per alliberar espai."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"L\'emmagatzematge del telèfon és ple. Suprimeix uns quants fitxers per alliberar espai."</string>
- <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"És possible que la xarxa estigui supervisada"</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Pot ser que la xarxa se supervisi."</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Per un tercer desconegut"</string>
<string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Per <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Mi"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Timbre activat"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"S\'està apagant..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"La tauleta s\'apagarà."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"El rellotge s\'apagarà."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"El telèfon s\'apagarà."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Vols apagar-lo?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reinicia en mode segur"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode d\'avió"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mode d\'avió activat"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mode d\'avió desactivat"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Configuració"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"+999"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Serveis de pagament"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Dur a terme activitats de pagament."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Missatges"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"desinstal·la dreceres"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permet que l\'aplicació suprimeixi les dreceres de la pantalla d\'inici sense la intervenció de l\'usuari."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"desviació de les trucades sortints"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permet que l\'aplicació vegi el número que s\'està marcant durant una trucada sortint, amb l\'opció de redirigir la trucada a un altre número o bé de cancel·lar-la completament."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Permet que l\'aplicació processi les trucades sortints i que canviï el número que es marcarà. Aquest permís permet que l\'aplicació supervisi, redirigeixi o bloquegi les trucades sortints."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"recepció de missatges de text (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Permet que l\'aplicació rebi i processi missatges SMS. Això vol dir que l\'aplicació pot controlar o suprimir missatges que s\'han enviat al teu dispositiu sense mostrar-te\'ls."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"recepció de missatges de text (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permet que l\'aplicació recuperi el contingut de la finestra activa. Les aplicacions malicioses poden recuperar el contingut de tota la finestra i examinar-ne tot el text, excepte les contrasenyes."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"activació temporal de l\'accessibilitat"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permet que una aplicació activi temporalment l\'accessibilitat al dispositiu. És possible que les aplicacions malicioses activin l\'accessibilitat sense el consentiment de l\'usuari."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"recuperació del testimoni de la finestra"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Permet que una aplicació recuperi el testimoni de la finestra. Les aplicacions malicioses poden suplantar la identitat del sistema per dur a terme una interacció no autoritzada amb la finestra de l\'aplicació."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"recuperació d\'estadístiques de fotogrames"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Permet que una aplicació recopili estadístiques de fotogrames. Les aplicacions malicioses poden veure les estadístiques de fotogrames de finestres d\'altres aplicacions."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"recupera informació de les finestres"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permet que una aplicació recuperi informació sobre les finestres del gestor de finestres. Aplicacions malicioses podrien recuperar informació dirigida a la utilització per part del sistema intern."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtra els esdeveniments"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Permet que una aplicació registri un filtre d\'entrada per a l\'emissió de tots els esdeveniments d\'usuari abans no s\'enviïn. Aplicacions malicioses podrien controlar la IU del sistema sense la intervenció de l\'usuari."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"augment de la pantalla"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Permet a una aplicació augmentar el contingut d\'una pantalla. Les aplicacions malicioses poden transformar el contingut de la pantalla de manera que el dispositiu no es pugui fer servir."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"apagar parcialment"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Posa el gestor d\'activitats en estat d\'apagada. No fa una apagada completa."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedir els canvis d\'aplicació"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permet que l\'aplicació difongui una notificació en què s\'indiqui que s\'ha rebut un missatge SMS. Les aplicacions malicioses poden fer servir aquesta funció per falsificar els missatges SMS entrants."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar una difusió de tipus WAP-PUSH-received"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permet que l\'aplicació difongui una notificació que indica que s\'ha rebut un missatge d\'inserció WAP. Les aplicacions malicioses poden utilitzar-ho per falsificar la recepció dels missatges MMS o per substituir silenciosament el contingut d\'una pàgina web per variants malicioses."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"enviar l\'emissió de la puntuació de les xarxes"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permet que l\'aplicació emeti una notificació necessària perquè les xarxes rebin una puntuació. No es necessita mai per a les aplicacions normals."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar el nombre de processos en execució"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permet que l\'aplicació controli el nombre màxim de processos que s\'executaran. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"com fer que es tanquin les aplicacions en segon pla"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de VPN. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"enllaça amb un fons de pantalla"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet que el titular vinculi a la interfície de nivell superior d\'un fons de pantalla. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"enllaçar amb una eina d\'interacció de veu"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permet enllaçar amb la interfície de nivell superior d\'un servei d\'interacció de veu. No ha de ser mai necessari per a aplicacions normals."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vincula a una pantalla remota"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permet que el titular es vinculi a la interfície de nivell superior d\'una pantalla remota. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincula a un servei de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de widget. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"establir vincles amb un servei d\'aprovisionament de rutes"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permet que el titular estableixi vincles amb els proveïdors de rutes registrats. No hauria de ser mai necessari per a les aplicacions normals."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar amb un administrador del dispositiu"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet que el titular enviï intents a un administrador del sistema. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"Vinculació a una entrada de televisor"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet que l\'aplicació utilitzi qualsevol descodificador de mitjans instal·lat per descodificar per a la reproducció."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestiona les credencials de confiança"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet que l\'aplicació instal·li i desinstal·li certificats de CA com a credencials de confiança."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"executar l\'aplicació durant el temps d\'inactivitat"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Aquest permís permet que el sistema Android executi l\'aplicació en segon pla mentre el dispositiu no està en ús."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"vincula als serveis inactius"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Amb aquest permís, el sistema Android podrà vincular-se amb els serveis inactius d\'una aplicació."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"llegir/escriure recursos propietat de diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet que l\'aplicació llegeixi i escrigui a qualsevol recurs propietat del grup diag; per exemple, els fitxers de /dev. Això podria afectar l\'estabilitat i la seguretat del sistema. NOMÉS l\'hauria d\'utilitzar el fabricant o l\'operador per a diagnòstics específics de maquinari."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"activa o desactiva els components de l\'aplicació"</string>
@@ -458,19 +436,19 @@
<string name="permdesc_grantRevokePermissions" msgid="4088642654085850662">"Permet que una aplicació concedeixi o denegui permisos específics per a aquesta o per a altres aplicacions. És possible que les aplicacions malicioses ho facin servir per accedir a funcions a les quals no has concedit accés."</string>
<string name="permlab_setPreferredApplications" msgid="8463181628695396391">"defineix les aplicacions preferides"</string>
<string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"Permet que l\'aplicació modifiqui les aplicacions preferides. Les aplicacions malicioses poden canviar silenciosament les aplicacions que s\'executen, falsejar les aplicacions existents o recollir dades privades de l\'usuari."</string>
- <string name="permlab_writeSettings" msgid="2226195290955224730">"modificar la configuració del sistema"</string>
+ <string name="permlab_writeSettings" msgid="2226195290955224730">"modificació de la configuració del sistema"</string>
<string name="permdesc_writeSettings" msgid="7775723441558907181">"Permet que l\'aplicació modifiqui les dades de configuració del sistema. Les aplicacions malicioses poden malmetre la configuració del sistema."</string>
<string name="permlab_writeSecureSettings" msgid="204676251876718288">"modificar la configuració de seguretat del sistema"</string>
<string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"Permet que l\'aplicació modifiqui les dades de la configuració de seguretat del sistema. No indicat per a les aplicacions normals."</string>
<string name="permlab_writeGservices" msgid="2149426664226152185">"modificar el mapa de serveis de Google"</string>
<string name="permdesc_writeGservices" msgid="1287309437638380229">"Permet que l\'aplicació modifiqui el mapa dels serveis de Google. No la poden fer servir les aplicacions normals."</string>
- <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"executar-se a l\'inici"</string>
+ <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"execució en iniciar"</string>
<string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Permet que l\'aplicació s\'iniciï tan bon punt el sistema hagi acabat d\'arrencar. Això pot fer que es trigui més a iniciar el telèfon i permetre a l\'aplicació alentir-ne el funcionament general en executar-se sempre."</string>
<string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Permet que l\'aplicació s\'iniciï tan bon punt el sistema hagi acabat d\'arrencar. Això pot fer que es trigui més a iniciar el telèfon i permetre a l\'aplicació alentir-ne el funcionament general si s\'executa sempre."</string>
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"enviar difusió permanent"</string>
<string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Permet que l\'aplicació enviï emissions permanents, que es conserven després de finalitzar l\'emissió. L\'ús excessiu pot alentir o desestabilitzar la tauleta si li fan utilitzar massa memòria."</string>
<string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Permet que l\'aplicació enviï emissions permanents, que es conserven després de finalitzar l\'emissió. L\'ús excessiu pot alentir o desestabilitzar el telèfon si li fan utilitzar massa memòria."</string>
- <string name="permlab_readContacts" msgid="8348481131899886131">"consultar els contactes"</string>
+ <string name="permlab_readContacts" msgid="8348481131899886131">"lectura dels contactes"</string>
<string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Permet que l\'aplicació llegeixi dades sobre els contactes que tinguis emmagatzemats a la tauleta, inclosa la freqüència amb què has trucat, has enviat correus electrònics o t\'has comunicat d\'altres maneres amb persones concretes. Aquest permís permet que les aplicacions desin les dades dels teus contactes, i és possible que les aplicacions malicioses comparteixin dades dels contactes sense el teu coneixement."</string>
<string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Permet que l\'aplicació llegeixi dades sobre els contactes que tinguis emmagatzemats al telèfon, inclosa la freqüència amb què has trucat, has enviat correus electrònics o t\'has comunicat d\'altres maneres amb persones concretes. Aquest permís permet que les aplicacions desin les dades dels teus contactes, i és possible que les aplicacions malicioses comparteixin dades dels contactes sense el teu coneixement."</string>
<string name="permlab_writeContacts" msgid="5107492086416793544">"modificar els teus contactes"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Permet que l\'aplicació pugui llegir informació del perfil personal emmagatzemada al dispositiu, com ara el teu nom i la teva informació de contacte. Això significa que l\'aplicació et pot identificar i enviar la informació del teu perfil a altres persones."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"modificació targeta contacte"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Permet que l\'aplicació pugui canviar o afegir informació del perfil personal emmagatzemada al dispositiu, com ara el teu nom i la teva informació de contacte. Això significa que l\'aplicació et pot identificar i enviar la informació del teu perfil a altres persones."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"sensors corp. (monitors freq. cardíaca)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Permet que l\'aplicació accedeixi a les dades dels sensors que utilitzes per mesurar els signes vitals del teu cos, com ara la freqüència cardíaca."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"llegeix el teu tauler d\'activitat social"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Permet que l\'aplicació accedeixi i sincronitzi actualitzacions socials teves i dels teus amics. Vés amb compte en compartir informació: això permet que l\'aplicació llegeixi comunicacions entre tu i els teus amics a les xarxes socials, independentment de la confidencialitat. Nota: És possible que aquest permís no s\'apliqui a totes les xarxes socials."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"escriu al tauler d\'activitat social"</string>
@@ -534,7 +510,7 @@
<string name="permdesc_recordAudio" msgid="4906839301087980680">"Permet que l\'aplicació enregistri àudio amb el micròfon. Aquest permís permet que l\'aplicació enregistri àudio en qualsevol moment sense la teva confirmació."</string>
<string name="permlab_sim_communication" msgid="1180265879464893029">"comunicació SIM"</string>
<string name="permdesc_sim_communication" msgid="5725159654279639498">"Permet que l\'aplicació enviï ordres a la SIM. Això és molt perillós."</string>
- <string name="permlab_camera" msgid="3616391919559751192">"fer fotos i vídeos"</string>
+ <string name="permlab_camera" msgid="3616391919559751192">"fes fotos i vídeos"</string>
<string name="permdesc_camera" msgid="8497216524735535009">"Permet que l\'aplicació faci fotos i vídeos amb la càmera. Aquest permís permet que l\'aplicació utilitzi la càmera en qualsevol moment sense la teva confirmació."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"desactiva la transmissió del LED indicador en fer servir la càmera"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permet que una aplicació dels sistema preinstal·lada desactivi el LED indicador d\'ús de la càmera."</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permet que l\'aplicació controli les funcions de telèfon del dispositiu. Una aplicació amb aquest permís pot canviar de xarxa, activar i desactivar el senyal mòbil i dur a terme accions semblants sense notificar-t\'ho."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"veure l\'estat i la identitat del telèfon"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet que l\'aplicació accedeixi a les funcions de telèfon del dispositiu. Aquest permís permet que l\'aplicació determini el número de telèfon i els identificadors del dispositiu, si hi ha una trucada activa i el número remot connectat amb una trucada."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"llegeix els estats exactes del telèfon"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permet que l\'aplicació accedeixi als estats exactes del telèfon. Amb aquest permís, l\'aplicació pot determinar l\'estat real de la trucada, si la trucada està activa o en segon pla, si s\'ha produït algun error, l\'estat exacte de la connexió de dades i els errors de la connexió de dades."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evita que la tauleta entri en mode d\'inactivitat"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir que el telèfon entri en mode de repòs"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permet que l\'aplicació impedeixi que la tauleta entri en repòs."</string>
@@ -624,7 +598,7 @@
<string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Permet que l\'aplicació obtingui la llista de comptes coneguts pel telèfon. Això pot incloure tots els comptes que hagin creat les aplicacions que tens instal·lades."</string>
<string name="permlab_authenticateAccounts" msgid="5265908481172736933">"creació de comptes i definició de contrasenyes"</string>
<string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"Permet que l\'aplicació utilitzi les funcions d\'autenticador de comptes del gestor de comptes, incloses la creació de comptes i l\'obtenció i la definició de les seves contrasenyes."</string>
- <string name="permlab_manageAccounts" msgid="4983126304757177305">"afegir o eliminar comptes"</string>
+ <string name="permlab_manageAccounts" msgid="4983126304757177305">"addició o eliminació de comptes"</string>
<string name="permdesc_manageAccounts" msgid="8698295625488292506">"Permet que l\'aplicació dugui a terme operacions com ara afegir i eliminar comptes i suprimir-ne la contrasenya."</string>
<string name="permlab_useCredentials" msgid="235481396163877642">"fer servir comptes del dispositiu"</string>
<string name="permdesc_useCredentials" msgid="7984227147403346422">"Permet que l\'aplicació sol·liciti testimonis d\'autenticació."</string>
@@ -658,19 +632,16 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Canvia l\'estat de WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permet que l\'aplicació connecti i desconnecti la tauleta de les xarxes WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permet que l\'aplicació connecti i desconnecti el telèfon de les xarxes WiMAX."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"puntuar les xarxes"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permet que l\'aplicació classifiqui les xarxes i indiqui quines han de ser les xarxes preferides de la tauleta."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permet que l\'aplicació classifiqui les xarxes i indiqui quines han de ser les xarxes preferides del telèfon."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"emparella amb dispositius Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permet que l\'aplicació visualitzi la configuració de Bluetooth de la tauleta i que estableixi i accepti connexions amb dispositius sincronitzats."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permet que una aplicació visualitzi la configuració de Bluetooth del telèfon i que estableixi i accepti connexions amb els dispositius sincronitzats."</string>
- <string name="permlab_nfc" msgid="4423351274757876953">"controlar Comunicació de camp proper (NFC)"</string>
+ <string name="permlab_nfc" msgid="4423351274757876953">"controla Near Field Communication (NFC)"</string>
<string name="permdesc_nfc" msgid="7120611819401789907">"Permet que l\'aplicació es comuniqui amb les etiquetes, les targetes i els lectors de Near Field Communication (NFC)."</string>
<string name="permlab_disableKeyguard" msgid="3598496301486439258">"desactivació del bloqueig de pantalla"</string>
<string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Permet que l\'aplicació desactivi el bloqueig del teclat i qualsevol element de seguretat de contrasenyes associat. Per exemple, el telèfon desactiva el bloqueig del teclat en rebre una trucada telefònica entrant i, a continuació, reactiva el bloqueig del teclat quan finalitza la trucada."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"llegir la configuració de sincronització"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Permet que l\'aplicació llegeixi la configuració de sincronització d\'un compte. Per exemple, això pot determinar que l\'aplicació Persones estigui sincronitzada amb un compte."</string>
- <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activar o desactivar la sincronització"</string>
+ <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"activació o desactivació de la sincronització"</string>
<string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Permet que una aplicació modifiqui la configuració de sincronització d\'un compte. Per exemple, aquesta acció es pot fer servir per activar la sincronització de l\'aplicació Persones amb un compte."</string>
<string name="permlab_readSyncStats" msgid="7396577451360202448">"llegir les estadístiques de sincronització"</string>
<string name="permdesc_readSyncStats" msgid="1510143761757606156">"Permet que una aplicació llegeixi les estadístiques de sincronització d\'un compte, inclòs l\'historial d\'esdeveniments sincronitzats i quantes dades se sincronitzen."</string>
@@ -682,7 +653,7 @@
<string name="permdesc_readDictionary" msgid="659614600338904243">"Permet que l\'aplicació llegeixi les paraules, els noms i les frases que l\'usuari pot haver emmagatzemat al seu diccionari."</string>
<string name="permlab_writeDictionary" msgid="2183110402314441106">"afegeix paraules al diccionari definit per l\'usuari"</string>
<string name="permdesc_writeDictionary" msgid="8185385716255065291">"Permet que l\'aplicació escrigui paraules noves al diccionari de l\'usuari."</string>
- <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"consultar contingut emmagatzematge USB"</string>
+ <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"lectura contingut emmagat. USB"</string>
<string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"lectura del contingut de la targeta SD"</string>
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Permet que l\'aplicació llegeixi el contingut de l\'emmagatzematge USB."</string>
<string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Permet que l\'aplicació llegeixi el contingut de la targeta SD."</string>
@@ -712,28 +683,22 @@
<string name="permdesc_markNetworkSocket" msgid="7655568433696356578">"Permet que l\'aplicació modifiqui les marques de sòcols per a l\'encaminament"</string>
<string name="permlab_accessNotifications" msgid="7673416487873432268">"accedeix a les notificacions"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet que l\'aplicació recuperi, examini i esborri les notificacions, incloses les que han publicat altres aplicacions."</string>
- <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincula a un servei oient de notificacions"</string>
- <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet que el titular vinculi la interfície de nivell superior d\'un servei oient de notificacions. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"enllaçar amb el servei de proveïdor de condicions"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permet enllaçar amb la interfície de nivell superior d\'un servei de proveïdor de condicions. No ha de ser mai necessari per a aplicacions normals."</string>
+ <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincula a un servei de processament de notificacions"</string>
+ <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet que el titular vinculi la interfície de nivell superior d\'un servei de processament de notificacions. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invoca l\'aplicació de configuració proporcionada per l\'operador"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet que el titular invoqui l\'aplicació de configuració proporcionada per l\'operador. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"conèixer les observacions sobre les condicions de la xarxa"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet que una aplicació conegui les observacions sobre les condicions de la xarxa. No s\'ha de necessitar mai per a aplicacions normals."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"canviar el calibratge del dispositiu d\'entrada"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permet que l\'aplicació modifiqui els paràmetres de calibratge de la pantalla tàctil. No ha de ser mai necessari per a aplicacions normals."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accedir als certificats de DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permet que una aplicació proporcioni i utilitzi certificats de gestió de drets digitals (DRM, Digital Rights Management). No ha de ser mai necessari per a aplicacions normals."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Definir les normes de contrasenya"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controla la longitud i els caràcters permesos a les contrasenyes de desbloqueig de pantalla."</string>
- <string name="policylab_watchLogin" msgid="914130646942199503">"Controlar els intents de desbloqueig de pantalla"</string>
+ <string name="policylab_watchLogin" msgid="914130646942199503">"Controlar intents de desbloqueig de pantalla"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Supervisa el nombre de contrasenyes incorrectes introduïdes per desbloquejar la pantalla i bloqueja la tauleta o n\'esborra totes les dades si s\'introdueixen massa contrasenyes incorrectes."</string>
<string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Supervisa el nombre de contrasenyes incorrectes introduïdes en desbloquejar la pantalla, i bloqueja el telèfon o esborra totes les dades del telèfon si s\'introdueixen massa contrasenyes incorrectes."</string>
<string name="policylab_resetPassword" msgid="2620077191242688955">"Canvia la contrasenya de desbloqueig de pantalla"</string>
<string name="policydesc_resetPassword" msgid="605963962301904458">"Canvia la contrasenya de desbloqueig de pantalla."</string>
<string name="policylab_forceLock" msgid="2274085384704248431">"Bloqueig de pantalla"</string>
<string name="policydesc_forceLock" msgid="1141797588403827138">"Controla com i quan es bloqueja la pantalla."</string>
- <string name="policylab_wipeData" msgid="3910545446758639713">"Esborrar totes les dades"</string>
+ <string name="policylab_wipeData" msgid="3910545446758639713">"Esborra totes les dades"</string>
<string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Esborra les dades de la tauleta sense advertiment mitjançant un restabliment de les dades de fàbrica."</string>
<string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Esborra les dades del telèfon sense avisar, restablint les dades de fàbrica."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Defineix el servidor intermediari global del dispositiu"</string>
@@ -743,7 +708,7 @@
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Encriptació d’emmagatzematge"</string>
<string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Requereix que les dades de l\'aplicació emmagatzemades estiguin encriptades."</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"Desactivar les càmeres"</string>
- <string name="policydesc_disableCamera" msgid="2306349042834754597">"Impedeix l\'ús de les càmeres del dispositiu."</string>
+ <string name="policydesc_disableCamera" msgid="2306349042834754597">"Impedeix l\'ús de totes les càmeres del dispositiu."</string>
<string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Des. funcions en bloq. tecles"</string>
<string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Impedeix l\'ús d\'algunes funcions en bloqueig de tecles."</string>
<string-array name="phoneTypes">
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permet que una aplicació accedeixi a l\'emmagatzematge protegit per contrasenya."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Controla si es mostra o s\'amaga el bloqueig de les tecles."</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permet que una aplicació controli el bloqueig de les tecles."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Escoltar els canvis de l\'estat de confiança"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permet que una aplicació escolti els canvis en l\'estat de confiança."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Enllaçar amb el servei d\'un agent de confiança"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permet que una aplicació es vinculi amb el servei d\'un agent de confiança."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interacciona amb el sistema de recuperació i amb les actualitzacions"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Permet que una aplicació interaccioni amb el sistema de recuperació i amb les actualitzacions del sistema."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toca dos cops per controlar el zoom"</string>
@@ -1385,8 +1346,7 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilitat"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fons de pantalla"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Canvia el fons de pantalla"</string>
- <string name="notification_listener_binding_label" msgid="2014162835481906429">"Oient de notificacions"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Proveïdor de condicions"</string>
+ <string name="notification_listener_binding_label" msgid="2014162835481906429">"Processador de notificacions"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ha activat VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toca per gestionar la xarxa."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 1c4e8b8..c338661 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> d"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> d <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> d <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> h"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
<string name="untitled" msgid="4638956954852782576">"<Bez názvu>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronizace"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Příliš mnoho smazaných položek služby <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Úložiště tabletu je plné. Uvolněte místo smazáním některých souborů."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Úložiště hodinek je plné. Uvolněte místo smazáním některých souborů."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Paměť telefonu je plná. Uvolněte místo smazáním některých souborů."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Síť může být monitorována"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Původce: neznámá třetí strana"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Vyzvánění zapnuto"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Vypínání..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablet se vypne."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Hodinky se vypnou."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Váš telefon bude vypnut."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Chcete zařízení vypnout?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Restart v nouzovém režimu"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Režim V letadle"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim V letadle je ZAPNUTÝ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim V letadle je VYPNUTÝ"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Nastavení"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Zpoplatněné služby"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Provádět činnosti, které vás mohou stát peníze."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vaše zprávy"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"odinstalace zástupců"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Umožňuje aplikaci odebrat zástupce z plochy bez zásahu uživatele."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"přesměrování odchozích hovorů"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Umožňuje aplikaci sledovat při odchozích hovorech volaná čísla a přesměrovat hovor na jiné číslo nebo jej zcela zrušit."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Umožňuje aplikaci zpracovávat odchozí hovory a měnit vytáčené číslo. Toto oprávnění umožňuje sledovat či přesměrovat odchozí hovory nebo jim zabránit."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"příjem textových zpráv (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Umožňuje aplikaci přijmout a zpracovat zprávy SMS. Znamená to, že aplikace může sledovat zprávy odeslané do vašeho zařízení nebo je smazat, aniž by se vám zobrazily."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"příjem textových zpráv (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Umožňuje aplikaci načíst obsah aktivního okna. Škodlivé aplikace mohou načíst obsah celého okna a prozkoumat všechen text kromě hesel."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"dočasná aktivace usnadnění přístupu"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Umožňuje aplikaci dočasně aktivovat usnadnění přístupu v zařízení. Škodlivé aplikace mohou usnadnění přístupu aktivovat bez souhlasu uživatele."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"načíst token okna"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Umožňuje aplikaci načíst token okna. Škodlivé aplikace se mohou vydávat za systém a provádět s oknem aplikace neoprávněné interakce."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"načíst statistiky rámců"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Umožňuje aplikaci shromažďovat statistiky rámců. Škodlivé aplikace mohou sledovat statistiky rámců oken ostatních aplikací."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"načítání informací o oknech"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Umožňuje aplikaci načíst informace o oknech ze správce oken. Škodlivé aplikace mnohou načíst informace, které slouží k internímu systémovému využití."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtrování událostí"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Umožní aplikaci registrovat vstupní filtr, který filtruje stream všech uživatelských přenosů před jejich odvysíláním. Škodlivé aplikace mohou používat uživatelské rozhraní systému bez zásahu uživatele."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"zvětšit zobrazení"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Povoluje aplikaci zvětšit obsah displeje. Škodlivé aplikace mohou změnit zobrazení obsahu způsobem, který učiní zařízení nepoužitelným."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"částečné vypnutí"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Uvede správce činností do vypnutého stavu. Nedojde však k úplnému vypnutí."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zabránění přepínání aplikací"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Umožňuje aplikaci vysílat oznámení o přijetí zprávy SMS. Škodlivé aplikace mohou toto oprávnění použít k vytváření falešných příchozích zpráv SMS."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"odeslání vysílání typu WAP-PUSH-received"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Umožňuje aplikaci vysílat oznámení o přijetí zprávy WAP PUSH. Škodlivé aplikace mohou toto oprávnění použít k vytváření falešných přijatých zpráv MMS nebo utajenému nahrazení obsahu libovolné webové stránky jejich škodlivými variantami."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"odeslání skóre vysílaných sítěmi"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Umožňuje aplikaci vysílat oznámení, že je třeba zadat skóre sítí. Běžné aplikace toto oprávnění nepotřebují."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"omezení počtu spuštěných procesů"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Umožňuje aplikaci řídit maximální počet spuštěných procesů. Běžné aplikace toto oprávnění nikdy nepotřebují."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"vynucení zavření aplikací na pozadí"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Umožňuje držiteli navázat se na nejvyšší úroveň služby VPN. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"vazba na tapetu"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní tapety. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"navázání na hlasovou interakci"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní služby hlasové interakce. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"připojit se ke vzdálenému displeji"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Umožňuje držiteli připojit se k vysokoúrovňovému rozhraní vzdáleného displeje. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"navázat se na službu widgetu"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteli navázat se na nejvyšší úroveň služby widgetu. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"navázání na službu poskytovatele tras"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Umožňuje držiteli navázat se na libovolného poskytovatele registrovaných tras. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovat se správcem zařízení"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Umožňuje držiteli oprávnění odesílat informace správci zařízení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"navázání na televizní vstup"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní televizního vstupu. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"přidat nebo odebrat správce zařízení"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Opravňuje držitele přidávat nebo odebírat aktivní správce zařízení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"změna orientace obrazovky"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Umožňuje aplikaci používat libovolný nainstalovaný dekodér médií k dekódování při přehrávání."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"správa důvěryhodných identifikačních údajů"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Umožňuje aplikaci instalovat a odinstalovat certifikáty CA jako důvěryhodné identifikační údaje."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"spustit aplikaci během nečinnosti"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Toto oprávnění umožňuje systému Android spustit aplikaci na pozadí, když zařízení není používáno."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"napojit se na nečinné služby"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Toto oprávnění umožní systému Android vázat se na nečinné služby aplikace."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"čtení nebo zápis do prostředků funkce diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Umožňuje aplikaci číst libovolné prostředky ve skupině diag, např. soubory ve složce /dev, a zapisovat do nich. Může dojít k ovlivnění stability a bezpečnosti systému. Toto nastavení by měl používat POUZE výrobce či operátor pro diagnostiku hardwaru."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivace či deaktivace komponent aplikací"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Umožňuje aplikaci číst údaje v osobním profilu uložené v zařízení, například jméno nebo kontaktní údaje. Znamená to, že vás aplikace může identifikovat a odeslat údaje z profilu dalším aplikacím."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"úprava vaší vlastní vizitky"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Umožňuje aplikaci změnit nebo přidat údaje osobního profilu uložené v zařízení, například jméno nebo kontaktní údaje. Znamená to, že vás aplikace může identifikovat a odeslat údaje z profilu dalším aplikacím."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"tělesné senzory (například snímače tepu)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Umožňuje aplikaci přistupovat k datům ze senzorů, pomocí kterých měříte činnost svého těla, například tep."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"čtení vašeho sociálního streamu"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Umožňuje aplikaci získat přístup k sociálním aktualizacím od vašich přátel a synchronizaci těchto aktualizací. Při sdílení informací buďte opatrní – toto oprávnění umožňuje aplikaci číst komunikaci mezi vámi a vašimi přáteli v sociálních sítích bez ohledu na její důvěrnost. Poznámka: Toto oprávnění nemusí platit pro všechny sociální sítě."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"zápis do sociálního streamu"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Umožňuje aplikaci ovládat telefonní funkce zařízení. Aplikace s tímto oprávněním smí bez upozornění přepínat sítě, zapínat a vypínat bezdrátový modul telefonu a podobně."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"čtení stavu a identity telefonu"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Umožňuje aplikaci získat přístup k telefonním funkcím zařízení. Toto oprávnění umožňuje aplikaci zjistit telefonní číslo telefonu, identifikační čísla zařízení, zda zrovna probíhá hovor, a vzdálené číslo, ke kterému je hovor připojen."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"čtení přesného stavu telefonování"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Umožňuje aplikaci zjišťovat přesný stav telefonování a mobilních dat. Toto oprávnění aplikaci umožňuje zjistit skutečný stav volání, zda je volání aktivní nebo na pozadí, zda volání selhalo, přesný stav datového připojení a zda datové připojení selhalo."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"bránění přechodu tabletu do režimu spánku"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"bránění přechodu telefonu do režimu spánku"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Umožňuje aplikaci zabránit přechodu tabletu do režimu spánku."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Změnit stav připojení WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Umožňuje aplikaci připojovat tablet k sítím WiMAX a odpojovat jej od nich."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Umožňuje aplikaci připojovat telefon k sítím WiMAX a odpojovat jej od nich."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"zadání skóre sítí"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Umožňuje aplikaci hodnotit sítě a ovlivňovat, které sítě by měl tablet preferovat."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Umožňuje aplikaci hodnotit sítě a ovlivňovat, které sítě by měl telefon preferovat."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"párování se zařízeními Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Umožňuje aplikaci zobrazit konfiguraci tabletu s rozhraním Bluetooth, vytvářet připojení ke spárovaným zařízením a přijímat tato připojení."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Umožňuje aplikaci zobrazit konfiguraci telefonu s rozhraním Bluetooth, vytvářet připojení ke spárovaným zařízením a přijímat tato připojení."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikacím načítat, zobrazovat a mazat oznámení včetně těch přidaných jinými aplikacemi."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"navázání na službu pro poslouchání oznámení"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Umožňuje držiteli navázat se na nejvyšší úroveň služby pro poslouchání oznámení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"navázání na službu poskytovatele podmínky"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní služby poskytovatele podmínky. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"vyvolat konfigurační aplikaci poskytnutou operátorem"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Umožňuje vyvolání konfigurační aplikace poskytnuté operátorem. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"naslouchat informacím o stavu sítě"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Umožňuje aplikaci naslouchat informacím o stavu sítě. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"měnit kalibraci vstupního zařízení"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Umožňuje aplikaci měnit parametry kalibrace dotykové obrazovky. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"přístup k certifikátům DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Umožňuje aplikaci vydávat a používat certifikáty DRM. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavit pravidla pro heslo"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Řídit délku hesel pro odemčení obrazovky a povolené znaky."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Sledovat pokusy o odemčení obrazovky"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Umožňuje aplikaci přístup k bezpečnému úložišti keyguard."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Ovládání zobrazování a skrývání zámku obrazovky"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Umožňuje aplikaci ovládat zámek obrazovky."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Naslouchat změnám stavu důvěryhodnosti"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Umožňuje aplikaci naslouchat změnám ve stavu důvěryhodnosti."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Vázat se na službu zástupce důvěryhodnosti"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Umožňuje aplikaci vázat se na službu zástupce důvěryhodnosti."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interakce se systémem aktualizací a obnovení"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Umožňuje aplikaci interakci se systémem obnovení a s aktualizacemi systému."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dvojitým dotykem můžete ovládat přiblížení"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Změnit tapetu"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Aplikace poslouchající oznámení"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Poskytovatel podmínky"</string>
<string name="vpn_title" msgid="19615213552042827">"Síť VPN je aktivována"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Aplikace <xliff:g id="APP">%s</xliff:g> aktivovala síť VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dotykem zobrazíte správu sítě."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 1724de1..d8babe9 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"Tb"</string>
<string name="petabyteShort" msgid="5637816680144990219">"Pb"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> dage"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> dag <xliff:g id="HOURS">%2$d</xliff:g> t."</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> dag <xliff:g id="HOURS">%2$d</xliff:g> t."</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> timer"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> t. <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> t. <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min."</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min. <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min. <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sek."</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sek."</string>
<string name="untitled" msgid="4638956954852782576">"<Uden titel>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
@@ -57,7 +46,7 @@
<string name="badPin" msgid="9015277645546710014">"Den gamle pinkode, som du har indtastet, er ikke korrekt."</string>
<string name="badPuk" msgid="5487257647081132201">"Den indtastede PUK-kode er forkert."</string>
<string name="mismatchPin" msgid="609379054496863419">"De indtastede pinkoder er ikke ens"</string>
- <string name="invalidPin" msgid="3850018445187475377">"Indtast en pinkode på mellem 4 og 8 tal."</string>
+ <string name="invalidPin" msgid="3850018445187475377">"Indtast en PIN-kode på mellem 4 og 8 tal."</string>
<string name="invalidPuk" msgid="8761456210898036513">"Angiv en PUK-kode på 8 eller flere cifre."</string>
<string name="needPuk" msgid="919668385956251611">"Dit SIM-kort er låst med PUK-koden. Indtast PUK-koden for at låse den op."</string>
<string name="needPuk2" msgid="4526033371987193070">"Indtast PUK2-koden for at låse op for SIM-kortet."</string>
@@ -74,12 +63,12 @@
<string name="CwMmi" msgid="9129678056795016867">"Ventende opkald"</string>
<string name="BaMmi" msgid="455193067926770581">"Opkaldsspærring"</string>
<string name="PwdMmi" msgid="7043715687905254199">"Ændring af adgangskode"</string>
- <string name="PinMmi" msgid="3113117780361190304">"ændring af pinkode"</string>
+ <string name="PinMmi" msgid="3113117780361190304">"ændring af PIN-kode"</string>
<string name="CnipMmi" msgid="3110534680557857162">"Opkaldsnummeret er til stede"</string>
<string name="CnirMmi" msgid="3062102121430548731">"Opkaldsnummeret er begrænset"</string>
<string name="ThreeWCMmi" msgid="9051047170321190368">"Trevejsopkald"</string>
<string name="RuacMmi" msgid="7827887459138308886">"Afvisning af uønskede, irriterende opkald"</string>
- <string name="CndMmi" msgid="3116446237081575808">"Levering af nummervisning"</string>
+ <string name="CndMmi" msgid="3116446237081575808">"Levering af opkaldsnummer"</string>
<string name="DndMmi" msgid="1265478932418334331">"Forstyr ikke"</string>
<string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"Standarder for opkalds-id til begrænset. Næste opkald: Begrænset"</string>
<string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"Standarder for opkalds-id til begrænset. Næste opkald: Ikke begrænset"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkroniser"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"For mange <xliff:g id="CONTENT_TYPE">%s</xliff:g> sletninger"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Din tablets lager er fuldt. Slet nogle filer for at frigøre plads."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Urets lager er fuldt. Slet nogle filer for at frigøre plads."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefonens lager er fuldt. Slet nogle filer for at frigøre plads."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netværket kan være overvåget"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Af en ukendt tredjepart"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Ringeren er aktiveret"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Lukker ned..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Din tablet slukkes nu."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Dit ur lukkes ned."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Din telefon slukkes nu."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Vil du slukke?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Genstart i sikker tilstand"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flytilstand"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flytilstand er TIL"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flytilstand er slået FRA"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Indstillinger"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Tjenester, der koster dig penge"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Gør ting, der kan koste dig penge."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Dine beskeder"</string>
@@ -257,7 +241,7 @@
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"undersøge indholdet i et vindue, du interagerer med."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"aktivere Udforsk ved berøring"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="5800552516779249356">"De emner, der trykkes på, læses højt, og skærmen kan udforskes ved hjælp af bevægelser."</string>
- <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"aktivere forbedrede webhjælpefunktioner"</string>
+ <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"aktivere forbedret webhjælpefunktioner"</string>
<string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Der installeres muligvis scripts for at gøre appindhold mere tilgængeligt."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"observere tekst, du skriver"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Dette omfatter personlige data såsom kreditkortnumre og adgangskoder."</string>
@@ -272,15 +256,15 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"afinstaller genveje"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Tillader, at applikationen fjerner genveje på startskærmen uden brugerindgriben."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"omdirigere udgående opkald"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Tillader, at appen kan se det nummer, der ringes op til under et udgående opkald, og giver mulighed for at omdirigere opkaldet til et andet nummer eller afbryde opkaldet helt."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Tillader, at appen kan behandle udgående opkald og ændre det nummer, der skal ringes til. Med denne tilladelse kan appen overvåge, omdirigere eller forhindre udgående opkald."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"modtage tekstbeskeder (sms)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Tillader, at appen kan modtage og behandle sms-beskeder. Det betyder, at appen kan overvåge eller slette de beskeder, der sendes til din enhed, uden at vise dem til dig."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"modtage tekstbeskeder (mms)"</string>
<string name="permdesc_receiveMms" msgid="533019437263212260">"Tillader, at appen kan modtage og behandle mms-beskeder. Det betyder, at appen kan overvåge eller slette de beskeder, der sendes til din enhed, uden at vise dem til dig."</string>
<string name="permlab_receiveEmergencyBroadcast" msgid="1803477660846288089">"modtage nødudsendelser"</string>
<string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"Tillader, at appen kan modtage og behandle nødtransmissioner. Denne tilladelse er kun tilgængelig for systemapps."</string>
- <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"læse Cell Broadcast-beskeder"</string>
- <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Tillader, at appen læser Cell Broadcast-beskeder, der modtages af din enhed. I nogle områder sendes der Cell Broadcast-beskeder for at advare om nødsituationer. Ondsindede apps kan forstyrre ydelsen eller driften af din enhed, når der modtages en Cell Broadcast-besked om en nødsituation."</string>
+ <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"læse mobiltransmissionsbeskeder"</string>
+ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Tillader, at appen læser mobiltransmissionsbeskeder, der modtages af din enhed. I nogle områder sendes mobiltransmissionsbeskeder for at advare om nødsituationer. Ondsindede apps kan forstyrre ydelsen eller driften af din enhed, når en mobiltransmission om en nødsituation modtages."</string>
<string name="permlab_sendSms" msgid="5600830612147671529">"send sms-beskeder"</string>
<string name="permdesc_sendSms" msgid="7094729298204937667">"Tillader, at appen kan sende sms-beskeder. Dette kan resultere i uventede opkrævninger. Skadelige apps kan koste dig penge ved at sende beskeder uden din bekræftelse."</string>
<string name="permlab_sendRespondViaMessageRequest" msgid="8713889105305943200">"send hændelser, hvor der skal svares pr. besked"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Tillader, at appen kan hente indholdet i det aktive vindue. Ondsindede apps kan hente al indholdet i vinduet og undersøge al dens tekst med undtagelse af adgangskoder."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"aktivere hjælpefunktioner midlertidigt"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Tillader, at en app midlertidigt kan aktivere hjælpefunktioner på enheden. Skadelige apps kan muligvis aktivere hjælpefunktioner uden brugerens samtykke."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"hente vinduestoken"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Tillader, at en applikation kan hente vinduestokenet. Skadelige apps udfører muligvis uautoriseret interaktion med applikationsvinduet ved at efterligne systemet."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"hente rammestatistik"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Tillader, at en applikation kan indsamle rammestatistik. Skadelige apps kan muligvis observere rammestatistikker for vinduer fra andre apps."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"hent oplysninger om vinduer"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Tillader, at en applikation henter oplysninger om vinduerne i vinduesadministratoren. Skadelige apps kan muligvis hente oplysninger, der er beregnet til intern systembrug."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtrer begivenheder"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Tillader, at en applikation registrerer et inputfilter, som filtrerer alle brugeres strøm, før disse afsendes. Skadelige apps kan muligvis kontrollere systemets grænseflade uden brugerens deltagelse."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"forstør skærmen"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Tillader, at applikationer kan forstørre indholdet på en skærm. Skadelige apps kan omdanne skærmindholdet, så enheden bliver ubrugelig."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"delvis lukning"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Sætter aktivitetsadministratoren i lukningstilstand. Lukker ikke helt ned."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"undgå programskift"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Tillader, at appen kan udsende en underretning om, at der er modtaget en sms-besked. Ondsindede apps kan bruge dette til at simulere indgående sms-beskeder."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"send WAP-PUSH-modtaget udsendelse"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Tillader, at appen kan udsende en underretning om, at der er modtaget en WAP PUSH-besked. Ondsindede apps kan bruge dette til at simulere modtagelse af mms-beskeder eller i det skjulte erstatte indholdet på en webside med ondsindede varianter."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"sende underretninger om bedømmelse af netværk"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Tillader, at appen kan udsende en underretning om, at netværket skal bedømmes. Dette er aldrig nødvendigt for almindelige apps."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"begræns antallet af kørende processer"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Tillader, at appen kan kontrollere det maksimale antal kørende processer. Dette er aldrig nødvendigt til normale apps."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"tvinge baggrundsapps til at lukke"</string>
@@ -398,16 +380,12 @@
<string name="permdesc_bindTextService" msgid="8151968910973998670">"Tillader, at ejeren kan binde en teksttjenestes grænseflade (f. eks. SpellCheckerService) på øverste niveau. Dette bør aldrig være nødvendigt til normale apps."</string>
<string name="permlab_bindVpnService" msgid="4708596021161473255">"bind til en VPN-tjeneste"</string>
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Tillader, at brugeren forpligter sig til en VPN-tjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt i almindelige apps."</string>
- <string name="permlab_bindWallpaper" msgid="8716400279937856462">"knyt til en baggrund"</string>
+ <string name="permlab_bindWallpaper" msgid="8716400279937856462">"forpligt til et tapet"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Tillader, at indehaveren kan binde en baggrunds grænseflade på øverste niveau. Dette bør aldrig være nødvendigt for almindelige apps."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"oprette binding til en tjeneste til stemmeinteraktion"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Tillader, at brugeren opretter en binding til det øverste niveau af grænsefladen i en tjeneste til stemmeinteraktion. Dette bør aldrig være nødvendigt for almindelige apps."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind til en ekstern skærm"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Tillader, at brugeren kan foretage en binding til grænsefladens øverste niveau på en ekstern skærm. Bør aldrig være nødvendigt til almindelige apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"forpligt til en widgettjeneste"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Tillader, at brugeren kan forpligte sig til en grænseflade for en widgettjeneste på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"oprette tilknytning til en ruteudbydertjeneste"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Tillader, at indehaveren opretter tilknytninger til registrerede ruteudbydere. Dette bør aldrig være nødvendigt for normale apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikere med en enhedsadministrator"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Tillader, at brugeren kan sende hensigter til en enhedsadministrator. Dette bør aldrig være nødvendigt for almindelige apps."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"knyt til en tv-indgang"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Tillader, at appen bruger enhver installeret medieafkoder til at afkode til afspilning."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrer pålidelige logonoplysninger"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Tillader, at appen installerer og afinstallerer CA-certifikater som pålidelige loginoplysninger."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"kør applikation, mens enheden er i dvale"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Med denne tilladelse kan Android-systemet køre applikationen i baggrunden, mens enheden ikke er i brug."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"knyt til tjenester i dvale"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Med denne tilladelse kan Android-systemet bindes til en applikations dvaletjenester."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"læs/skriv til ressourcer ejet af diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Tillader, at appen kan læse og skrive til alle ressourcer, der ejes af diag-gruppen, f.eks. filer i /dev. Dette kan muligvis påvirke systemets stabilitet og sikkerhed. Dette bør KUN bruges til hardwarespecifik diagnosticering, som foretages af producenten eller udbyderen."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivere eller deaktivere appkomponenter"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Tillader, at appen kan læse de personlige profiloplysninger, der er gemt på din enhed, f.eks. dit navn og dine kontaktoplysninger. Det betyder, at appen kan identificere dig og sende dine profiloplysninger til andre."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"ændre dit eget kontaktkort"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Tillader, at appen kan ændre eller tilføje oplysninger i din personlige profil, der er gemt på din enhed, f.eks. dit navn eller dine kontaktoplysninger. Dette betyder, at andre apps kan identificere dig og sende profiloplysninger til andre."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"kropssensorer (f.eks. pulsmålere)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Tillader, at appen får adgang til data fra sensorer, du bruger til at måle, hvad der sker inde i din krop, f.eks. din puls."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"læs din sociale strøm"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Tillader, at appen kan få adgang til og synkronisere sociale opdateringer fra dig og dine venner. Vær forsigtig, når du deler oplysninger – med denne tilladelse kan appen læse kommunikation mellem dig og dine venner på sociale netværk, uanset fortrolighed. Bemærk! Denne tilladelse håndhæves muligvis ikke på alle sociale netværk."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"skriv i din sociale strøm"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Tillader, at appen kan styre enhedens telefonfunktioner. En app med denne tilladelse kan skifte netværk, slå telefonsenderen til og fra og lignende uden at underrette dig."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"læse telefonens status og identitet"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Tillader, at appen kan få adgang til telefonfunktionerne på enheden. Med denne tilladelse kan appen fastslå telefonnummeret og enheds-id\'erne, hvorvidt et opkald er aktivt samt det eksterne nummer, der oprettes forbindelse til via et opkald."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"læse nøjagtig status for telefonen"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Tillader, at appen får adgang til den nøjagtige status for telefonen. Denne tilladelse giver appen mulighed for at fastlægge den rigtige opkaldsstatus – om et opkald er aktivt eller kører i baggrunden, om opkaldet mislykkes, hvad den nøjagtige status for dataforbindelsen er, og om dataforbindelsen mislykkes."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"afholde tabletcomputeren fra at gå i dvale"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"afholde telefonen fra at gå i dvale"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Tillader, at appen kan forhindre tabletten i at gå i dvale."</string>
@@ -605,7 +579,7 @@
<string name="permlab_factoryTest" msgid="3715225492696416187">"kør i fabriksindstillet testtilstand"</string>
<string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Kør som en producenttest på lavt niveau, der giver fuld adgang til tabletens hardware. Kun tilgængeligt når en tablet kører i producenttesttilstand."</string>
<string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Kør som en producenttest på lavt niveau. Giver fuld adgang til telefonens hardware. Kun tilgængeligt når en telefon kører i producenttesttilstand."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"angive baggrund"</string>
+ <string name="permlab_setWallpaper" msgid="6627192333373465143">"angiv tapet"</string>
<string name="permdesc_setWallpaper" msgid="7373447920977624745">"Tillader, at appen kan konfigurere systembaggrunden."</string>
<string name="permlab_setWallpaperHints" msgid="3278608165977736538">"ændre størrelsen på din baggrund"</string>
<string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Tillader, at appen giver tips til systembaggrundens størrelse."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Skift WiMAX-tilstand"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Tillader, at appen kan oprette forbindelse fra tabletten og afbryde forbindelsen til tabletten på WiMAX-netværk."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Tillader, at appen kan oprette forbindelse fra telefonen og afbryde forbindelsen til telefonen på WiMAX-netværk."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"bedømme netværk"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Tillader, at appen rangerer netværk og påvirker, hvilke netværk tabletten bør foretrække."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Tillader, at appen rangerer netværk og påvirker, hvilke netværk telefonen bør foretrække."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"parre med Bluetooth-enheder"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Tillader, at appen kan læse konfigurationen af Bluetooth på tabletten samt kan oprette og acceptere forbindelser med parrede enheder."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Tillader, at appen kan læse konfigurationen af Bluetooth på telefonen samt kan oprette og acceptere forbindelser med parrede enheder."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillader, at appen kan hente, undersøge og rydde underretninger, f.eks. dem, der er sendt af andre apps."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"forpligte sig til en underretningslyttertjeneste"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Tillader brugeren at forpligte sig til en underretningslyttertjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"oprette binding til en tjeneste til formidling af betingelser"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Tillader, at brugeren opretter en binding til det øverste niveau af grænsefladen i en tjeneste til formidling af betingelser. Dette bør aldrig være nødvendigt for almindelige apps."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"aktivere konfigurationsappen, der leveres af mobilselskabet"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Tillader, at brugeren aktiverer konfigurationsappen, der er forsynet af mobilselskabet. Dette bør aldrig være nødvendigt for almindelige apps."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"observer netværksforhold"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Tillader, at en applikation observerer netværksforhold. Bør aldrig være nødvendigt for almindelige apps."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"skift kalibrering for inputenheden"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Tillader, at appen ændrer kalibreringsparametrene for berøringsskærmen. Dette bør aldrig være nødvendigt for almindelige apps."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"få adgang til DRM-certifikater"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Tillader, at en applikation leverer og anvender DRM-certfikater. Dette bør aldrig være nødvendigt for almindelige apps."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Indstil regler for adgangskode"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller længden samt tilladte tegn i adgangskoder til oplåsning af skærmen."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Overvåg forsøg på oplåsning af skærm"</string>
@@ -1194,7 +1159,7 @@
<string name="smv_process" msgid="5120397012047462446">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> har overtrådt sin egen StrictMode-politik."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android opgraderes..."</string>
<string name="android_upgrading_apk" msgid="7904042682111526169">"Optimerer app <xliff:g id="NUMBER_0">%1$d</xliff:g> ud af <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
- <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Åbner dine apps."</string>
+ <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Sådan åbner du dine apps."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Gennemfører start."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> er i gang"</string>
<string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Tryk for at skifte til appen"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Tillader, at en applikation får adgang til et nøglebeskyttet lager."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Administrer, om nøglebeskyttelse skal vises eller skjules"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Tillader, at en applikation styrer nøglebeskyttelsen."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Registrere ændringer i trust-tilstand."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Tillader, at en applikation registrerer ændringer i trust-tilstand."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Knytte sig til en trust agent-tjeneste"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Tillader, at en applikation knytter sig til en trust agent-tjeneste."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interager med opdaterings- og gendannelsessystemet"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Giver en applikation tilladelse til at interagere med gendannelsessystemet og systemopdateringerne."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Tryk to gange for zoomstyring"</string>
@@ -1383,10 +1344,9 @@
<string name="input_method_binding_label" msgid="1283557179944992649">"Inputmetode"</string>
<string name="sync_binding_label" msgid="3687969138375092423">"Synkroniser"</string>
<string name="accessibility_binding_label" msgid="4148120742096474641">"Hjælpefunktioner"</string>
- <string name="wallpaper_binding_label" msgid="1240087844304687662">"Baggrund"</string>
- <string name="chooser_wallpaper" msgid="7873476199295190279">"Skift baggrund"</string>
+ <string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapet"</string>
+ <string name="chooser_wallpaper" msgid="7873476199295190279">"Skift tapet"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Underretningslytter"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Tjeneste til formidling af betingelser"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN er aktiveret."</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveres af <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Tryk for at administrere netværket."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index e527521..4da2043 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> Tage"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> Tag <xliff:g id="HOURS">%2$d</xliff:g> Std."</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> Tag <xliff:g id="HOURS">%2$d</xliff:g> Std."</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> Std."</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> Std. <xliff:g id="MINUTES">%2$d</xliff:g> Min."</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> Std. <xliff:g id="MINUTES">%2$d</xliff:g> Min."</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> Min."</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> Min. <xliff:g id="SECONDS">%2$d</xliff:g> Sek."</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> Min. <xliff:g id="SECONDS">%2$d</xliff:g> Sek."</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> Sek."</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> Sek."</string>
<string name="untitled" msgid="4638956954852782576">"<Unbenannt>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronisierung"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Zu viele <xliff:g id="CONTENT_TYPE">%s</xliff:g> gelöscht."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Der Tablet-Speicher ist voll. Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Der Speicher Ihrer Uhr ist voll. Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Der Handyspeicher ist voll! Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Das Netzwerk wird möglicherweise überwacht."</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Von einem unbekannten Dritten"</string>
@@ -157,14 +145,13 @@
<string name="silent_mode" msgid="7167703389802618663">"Lautlos-Modus"</string>
<string name="turn_on_radio" msgid="3912793092339962371">"Funk einschalten"</string>
<string name="turn_off_radio" msgid="8198784949987062346">"Funk ausschalten"</string>
- <string name="screen_lock" msgid="799094655496098153">"Displaysperre"</string>
+ <string name="screen_lock" msgid="799094655496098153">"Display-Sperre"</string>
<string name="power_off" msgid="4266614107412865048">"Ausschalten"</string>
<string name="silent_mode_silent" msgid="319298163018473078">"Klingelton aus"</string>
<string name="silent_mode_vibrate" msgid="7072043388581551395">"Klingeltonmodus \"Vibration\""</string>
<string name="silent_mode_ring" msgid="8592241816194074353">"Klingelton ein"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Wird heruntergefahren..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Ihr Tablet wird heruntergefahren."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ihre Uhr wird heruntergefahren."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefon wird heruntergefahren."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Möchten Sie das Gerät herunterfahren?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Im abgesicherten Modus starten"</string>
@@ -173,7 +160,7 @@
<string name="no_recent_tasks" msgid="8794906658732193473">"Keine kürzlich geöffneten Apps"</string>
<string name="global_actions" product="tablet" msgid="408477140088053665">"Tablet-Optionen"</string>
<string name="global_actions" product="default" msgid="2406416831541615258">"Telefonoptionen"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Displaysperre"</string>
+ <string name="global_action_lock" msgid="2844945191792119712">"Display-Sperre"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Ausschalten"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Fehlerbericht"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Fehlerbericht abrufen"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flugmodus"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flugmodus ist AN."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flugmodus ist AUS."</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Einstellungen"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Kostenpflichtige Dienste"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Kostenpflichtige Aktionen"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Ihre Nachrichten"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"Verknüpfungen deinstallieren"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Ermöglicht einer App das Entfernen von Verknüpfungen vom Startbildschirm ohne Eingriff des Nutzers"</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"Ausgehende Anrufe umleiten"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Ermöglicht der App die Erkennung der während eines ausgehenden Anrufs gewählten Nummer und gibt ihr die Möglichkeit, den Anruf an eine andere Nummer umzuleiten oder den Anruf ganz abzubrechen"</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Ermöglicht der App, ausgehende Anrufe zu verarbeiten und die zu wählende Nummer zu ändern. Die Berechtigung erlaubt der App, ausgehende Anrufe zu überwachen, umzuleiten und zu unterbinden."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"SMS empfangen"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Ermöglicht der App, SMS zu empfangen und zu verarbeiten. Das bedeutet, dass die App an Ihr Gerät gesendete Nachrichten überwachen und löschen kann, ohne sie Ihnen anzuzeigen."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"MMS empfangen"</string>
@@ -330,13 +314,13 @@
<string name="permlab_retrieve_window_content" msgid="8022588608994589938">"Bildschirminhalt abrufen"</string>
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Ermöglicht der App, den Inhalt des aktiven Fensters abzurufen. Schädliche Apps können so den gesamten Fensterinhalt abrufen und mit Ausnahme von Passwörtern den gesamten Text auswerten."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"Bedienungshilfen vorübergehend aktivieren"</string>
- <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Ermöglicht der App, die Bedienungshilfen auf dem Gerät vorübergehend zu aktivieren. Schädliche Apps können Bedienungshilfen ohne die Zustimmung des Nutzers aktivieren."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"Fenstertoken abrufen"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Berechtigt eine App zum Abruf des Fenstertokens. Bösartige Apps können sich als System ausgeben und unautorisiert mit dem App-Fenster interagieren."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"Framestatistiken abrufen"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Berechtigt eine App zur Erfassung von Framestatistiken. Bösartige Apps können möglicherweise die Framestatistiken für Fenster von anderen Apps beobachten."</string>
+ <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Ermöglicht einer App, die Bedienungshilfen auf dem Gerät vorübergehend zu aktivieren. Schädliche Apps können Bedienungshilfen ohne die Zustimmung des Nutzers aktivieren."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"Fensterinformationen abrufen"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Ermöglicht einer App, Informationen über die Fenster vom Fenster-Manager abzurufen. Schädliche Apps können Informationen abrufen, die für die systeminterne Nutzung gedacht sind."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"Ereignisse filtern"</string>
- <string name="permdesc_filter_events" msgid="8006236315888347680">"Ermöglicht der App, einen Eingabefilter zu registrieren, der den Stream aller Nutzerereignisse vor ihrem Versand filtert. Eine schädliche App kann die System-UI ohne Eingriff des Nutzers kontrollieren."</string>
+ <string name="permdesc_filter_events" msgid="8006236315888347680">"Ermöglicht einer App, einen Eingabefilter zu registrieren, der den Stream aller Nutzerereignisse vor ihrem Versand filtert. Eine schädliche App kann die System-UI ohne Eingriff des Nutzers kontrollieren."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"Anzeige vergrößern"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Erlaubt der App, den Inhalt einer Anzeige zu vergrößern. Schädliche Apps verändern eventuell die Ansicht, sodass Inhalte nicht richtig angezeigt werden."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"Partielles Herunterfahren"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Versetzt den Aktivitätsmanager in einen heruntergefahrenen Zustand. Führt kein vollständiges Herunterfahren aus."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"App-Wechsel verhindern"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Ermöglicht der App, eine Benachrichtigung zu senden, dass eine SMS empfangen wurde. Schädliche Apps können so eingehende SMS fälschen."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"Von WAP-PUSH empfangenen Broadcast senden"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Ermöglicht der App, eine Benachrichtigung zu senden, dass eine WAP PUSH-Nachricht empfangen wurde. Schädliche Apps können so den Empfang von MMS vortäuschen oder unbemerkt den Inhalt einer beliebigen Webseite durch schädliche Inhalte ersetzen."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"Netzwerkbewertungen senden"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Ermöglicht der App, Benachrichtigungen zu senden, dass Netzwerke bewertet werden müssen. Für normale Apps ist dies nie erforderlich."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"Anzahl der laufenden Prozesse beschränken"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Ermöglicht der App, die maximale Anzahl an aktiven Prozessen zu steuern. Wird nie für normale Apps benötigt."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"Apps im Hintergrund schließen"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Ermöglicht dem Halter, sich an die Oberfläche eines VPN-Dienstes auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"An einen Hintergrund binden"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ermöglicht dem Halter, sich an die Oberfläche eines Hintergrunds auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"An einen Sprachinteraktionsdienst binden"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Sprachinteraktionsdienstes auf oberster Ebene zu binden. Für normale Apps sollte dies nie erforderlich sein."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"An Remote-Display binden"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ermöglicht dem Halter, sich an die Oberfläche eines Remote-Displays auf oberster Ebene zu binden. Sollte für normale Apps nie benötigt werden."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"An einen Widget-Dienst binden"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ermöglicht dem Halter, sich an die Oberfläche eines Widget-Dienstes auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"An Routenanbieterdienst binden"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Ermöglicht dem Inhaber die Bindung an registrierte Routenanbieter. Sollte für normale Apps nicht erforderlich sein"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Interaktion mit einem Geräteadministrator"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ermöglicht dem Halter, Intents an einen Geräteadministrator zu senden. Sollte nie für normale Apps benötigt werden."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"An eine TV-Eingabe binden"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Ermöglicht dem Inhaber, sich an die Oberfläche einer TV-Eingabe auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"Geräteadministrator hinzufügen oder entfernen"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Ermöglicht dem Inhaber, aktive Geräteadministratoren hinzuzufügen oder zu entfernen. Sollte für normale Apps nie benötigt werden."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"Bildschirmausrichtung ändern"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ermöglicht der App, alle installierten Mediendecodierer zur Wiedergabe zu verwenden."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Vertrauenswürdige Anmeldedaten verwalten"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ermöglicht der App, CA-Zertifikate als vertrauenswürdige Anmeldedaten zu installieren und zu deinstallieren."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"App bei Inaktivität ausführen"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Diese Berechtigung ermöglicht es dem Android-System, die App im Hintergrund auszuführen, wenn das Gerät nicht verwendet wird."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"An inaktive Dienste binden"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Mit dieser Berechtigung kann sich das Android-System an die inaktiven Dienste einer App binden."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"Lese-/Schreibberechtigung für zu Diagnosegruppe gehörige Elemente"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Ermöglicht der App, alle Elemente in der Diagnosegruppe zu lesen und zu bearbeiten, etwa Dateien in \"/dev\". Dies könnte eine potenzielle Gefährdung für die Stabilität und Sicherheit des Systems darstellen und sollte NUR für hardwarespezifische Diagnosen des Herstellers oder Mobilfunkanbieters verwendet werden."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"App-Komponenten aktivieren oder deaktivieren"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Ermöglicht der App, auf Ihrem Gerät gespeicherte personenbezogene Profildaten zu lesen, einschließlich Ihres Namens und Ihrer Kontaktdaten. Die App kann Sie somit identifizieren und Ihre Profildaten an andere senden."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"Ihre Kontaktkarten ändern"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Ermöglicht der App, auf Ihrem Gerät gespeicherte personenbezogene Profildaten zu ändern, einschließlich Ihres Namens und Ihrer Kontaktdaten, sowie Daten hinzuzufügen. Die App kann Sie so identifizieren und Ihre Profildaten an andere senden."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"Körpersensoren (wie Herzfrequenzmesser)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Ermöglicht der App den Zugriff auf Daten von Sensoren, mit denen Ihre Vitalfunktionen, etwa die Herzfrequenz, gemessen werden."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"In sozialem Stream lesen"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Ermöglicht der App, auf Updates aus sozialen Netzwerken von Ihnen und Ihren Freunden zuzugreifen und diese zu synchronisieren. Seien Sie vorsichtig, wenn Sie Informationen teilen: Der App wird erlaubt, die Kommunikation zwischen Ihnen und Ihren Freunden in sozialen Netzwerken zu lesen, unabhängig von der Vertraulichkeit der kommunizierten Informationen. Hinweis: Diese Berechtigung kann möglicherweise nicht in allen sozialen Netzwerken erzwungen werden."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"In sozialem Stream schreiben"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Ermöglicht der App, die Telefonfunktionen des Geräts zu steuern. Eine App mit dieser Berechtigung kann das Netzwerk wechseln oder das Radio des Telefons ein- und ausschalten, ohne Sie darüber zu informieren."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"Telefonstatus und Identität abrufen"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ermöglicht der App, auf die Telefonfunktionen des Geräts zuzugreifen. Die Berechtigung erlaubt der App, die Telefonnummer und Geräte-IDs zu erfassen, festzustellen, ob gerade ein Gespräch geführt wird, und die Rufnummer verbundener Anrufer zu lesen."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"Genaue Telefonstatusangaben abrufen"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Ermöglicht der App, auf die genauen Telefonstatusangaben zuzugreifen. Diese Erlaubnis ermöglicht der App, den tatsächlichen Rufstatus zu ermitteln, das bedeutet, ob ein Anruf aktiv ist oder im Hintergrund abläuft, ob bei einem Anruf ein Fehler aufgetreten ist, wie der genaue Datenverbindungsstatus lautet oder ob bei der Datenverbindung ein Fehler aufgetreten ist."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Ruhezustand des Tablets deaktivieren"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Ruhezustand deaktivieren"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ermöglicht der App, den Ruhezustand des Tablets zu deaktivieren"</string>
@@ -658,15 +630,12 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX-Status ändern"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Ermöglicht der App, eine Verbindung zwischen dem Tablet und WiMAX-Netzwerken herzustellen und solche zu trennen."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Ermöglicht der App, eine Verbindung zwischen dem Telefon und WiMAX-Netzwerken herzustellen und solche zu trennen."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"Netzwerke bewerten"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Ermöglicht der App, Netzwerke zu bewerten und die Auswahl des jeweiligen Netzwerks für das Tablet zu beeinflussen"</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Ermöglicht der App, Netzwerke zu bewerten und die Auswahl des jeweiligen Netzwerks für das Telefon zu beeinflussen"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Pairing mit Bluetooth-Geräten durchführen"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Ermöglicht der App, die Bluetooth-Konfiguration eines Tablets einzusehen und Verbindungen zu gekoppelten Geräten herzustellen und zu akzeptieren."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Ermöglicht der App, die Bluetooth-Konfiguration des Telefons einzusehen und Verbindungen mit gekoppelten Geräten herzustellen und zu akzeptieren."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"Nahfeldkommunikation steuern"</string>
<string name="permdesc_nfc" msgid="7120611819401789907">"Ermöglicht der App die Kommunikation mit Tags für die Nahfeldkommunikation, Karten und Readern"</string>
- <string name="permlab_disableKeyguard" msgid="3598496301486439258">"Displaysperre deaktivieren"</string>
+ <string name="permlab_disableKeyguard" msgid="3598496301486439258">"Display-Sperre deaktivieren"</string>
<string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Ermöglicht der App, die Tastensperre sowie den damit verbundenen Passwortschutz zu deaktivieren. Das Telefon deaktiviert die Tastensperre beispielsweise, wenn ein Anruf eingeht, und aktiviert sie wieder, nachdem das Gespräch beendet wurde."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"Synchronisierungseinstellungen lesen"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Ermöglicht der App, die Synchronisierungseinstellungen eines Kontos zu lesen. Beispielsweise kann damit festgestellt werden, ob Kontakte mit einem Konto synchronisiert werden."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Ermöglicht der App das Abrufen, Überprüfen und Löschen von Benachrichtigungen, einschließlich Benachrichtigungen, die von anderen Apps gepostet wurden"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"An Benachrichtigungs-Listener-Dienst binden"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ermöglicht dem Inhaber, sich an die Oberfläche der obersten Ebene eines Benachrichtigungs-Listener-Dienstes zu binden. Sollte nie für normale Apps benötigt werden."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"An einen Bedingungsproviderdienst binden"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Bedingungsproviderdienstes auf oberster Ebene zu binden. Für normale Apps sollte dies nie erforderlich sein."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufrufen"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ermöglicht dem Inhaber, die vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufzurufen. Sollte für normale Apps nie benötigt werden."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Informationen zu den Netzwerkbedingungen erfassen"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Ermöglicht der App, Informationen zu den Netzwerkbedingungen zu erfassen. Sollte für normale Apps nie benötigt werden."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"Kalibrierung für Eingabegerät ändern"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Ermöglicht der App, die Kalibrierungsparameter des Touchscreens zu ändern. Für normale Apps sollte dies nie erforderlich sein."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"Auf DRM-Zertifikate zugreifen"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Ermöglicht einer App die Bereitstellung und Nutzung von DRM-Zertifikaten. Sollte für normale Apps nie benötigt werden."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Zulässige Länge und Zeichen für Passwörter zum Entsperren des Bildschirms festlegen"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string>
@@ -731,11 +694,11 @@
<string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Anzahl der falsch eingegebenen Passwörter beim Entsperren des Bildschirms überwachen und Telefon sperren oder alle Daten auf dem Telefon löschen, wenn zu häufig ein falsches Passwort eingegeben wird."</string>
<string name="policylab_resetPassword" msgid="2620077191242688955">"Passwort zum Entsperren des Bildschirms ändern"</string>
<string name="policydesc_resetPassword" msgid="605963962301904458">"Ändern Sie das Passwort zum Entsperren des Bildschirms."</string>
- <string name="policylab_forceLock" msgid="2274085384704248431">"Bildschirm sperren"</string>
+ <string name="policylab_forceLock" msgid="2274085384704248431">"Display sperren"</string>
<string name="policydesc_forceLock" msgid="1141797588403827138">"Legen Sie fest, wie und wann der Bildschirm gesperrt wird."</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"Alle Daten löschen"</string>
<string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Tablet ohne Warnung löschen"</string>
- <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Setzen Sie das Telefon auf die Werkseinstellungen zurück. Dabei werden alle Daten ohne Warnung gelöscht."</string>
+ <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Setzen Sie das Telefon auf Werkseinstellungen zurück. Dabei werden alle Daten ohne Warnung gelöscht."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Den globalen Proxy des Geräts festlegen"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Den bei aktivierter Richtlinie zu verwendenden globalen Proxy des Geräts festlegen. Nur der erste Geräteadministrator kann den gültigen globalen Proxy festlegen."</string>
<string name="policylab_expirePassword" msgid="885279151847254056">"Ablauf von Sperr-Passwort festlegen"</string>
@@ -1351,15 +1314,11 @@
<string name="permlab_copyProtectedData" msgid="4341036311211406692">"Inhalte kopieren"</string>
<string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Ermöglicht der App das Aufrufen des Standard-Containerdienstes zum Kopieren von Inhalten. Nicht für normale Apps vorgesehen."</string>
<string name="permlab_route_media_output" msgid="1642024455750414694">"Medienausgabe umleiten"</string>
- <string name="permdesc_route_media_output" msgid="4932818749547244346">"Ermöglicht der App, die Medienausgabe auf andere externe Geräte umzuleiten."</string>
+ <string name="permdesc_route_media_output" msgid="4932818749547244346">"Ermöglicht einer App, die Medienausgabe auf andere externe Geräte umzuleiten."</string>
<string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Zugriff auf mit Keyguard geschützten Speicher"</string>
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Ermöglicht einer App den Zugriff auf mit Keyguard geschützten Speicher"</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Anzeige und Ausblenden des Keyguard steuern"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Apps können den Keyguard steuern."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Überwachung von Änderungen des Trust-Status"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Ermöglicht einer App die Überwachungen von Änderungen des Trust-Status"</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"An Trust Agent-Service anbinden"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ermöglicht einer App die Anbindung an einen Trust Agent-Service"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Mit Update- und Wiederherstellungssystem interagieren"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Ermöglicht einer App die Interaktion mit dem Wiederherstellungssystem und den Systemupdates"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Für Zoomeinstellung zweimal berühren"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Hintergrund"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Hintergrund ändern"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Benachrichtigungs-Listener"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Bedingungsprovider"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN aktiviert"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN wurde von <xliff:g id="APP">%s</xliff:g> aktiviert."</string>
<string name="vpn_text" msgid="3011306607126450322">"Zum Verwalten des Netzwerks berühren"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 296fd71..64d330d 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> ημέρες"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> ημ. <xliff:g id="HOURS">%2$d</xliff:g> ώρες"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> ημ. <xliff:g id="HOURS">%2$d</xliff:g> ώρα"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> ώρες"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> ώρα <xliff:g id="MINUTES">%2$d</xliff:g> λ"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> ώρα <xliff:g id="MINUTES">%2$d</xliff:g> λ"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> λεπτά"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> λ. <xliff:g id="SECONDS">%2$d</xliff:g> δευτ."</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> λ <xliff:g id="SECONDS">%2$d</xliff:g> δευτ."</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> δευτ."</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> δευτ."</string>
<string name="untitled" msgid="4638956954852782576">"<Χωρίς τίτλο>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Συγχρονισμός"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Πάρα πολλές <xliff:g id="CONTENT_TYPE">%s</xliff:g> διαγραφές."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Ο αποθηκευτικός χώρος του tablet είναι πλήρης. Διαγράψτε μερικά αρχεία για να δημιουργήσετε ελεύθερο χώρο."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Ο αποθηκευτικός χώρος παρακολούθησης είναι πλήρης! Διαγράψτε μερικά αρχεία για να απελευθερώσετε χώρο."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Ο αποθηκευτικός χώρος του τηλεφώνου είναι πλήρης. Διαγράψτε μερικά αρχεία για να δημιουργήσετε ελεύθερο χώρο."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Το δίκτυο ενδέχεται να παρακολουθείται"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Από ένα άγνωστο τρίτο μέρος"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Ειδοποίηση ήχου ενεργή"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Απενεργοποίηση..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Το tablet σας θα απενεργοποιηθεί."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Η παρακολούθησή σας θα τερματιστεί."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Το τηλέφωνό σας θα απενεργοποιηθεί."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Θέλετε να γίνει τερματισμός λειτουργίας;"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Επανεκκίνηση στην ασφαλή λειτουργία"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Λειτουργία πτήσης"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Η λειτουργία πτήσης είναι ενεργοποιημένη."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Λειτ. πτήσης είναι ανενεργή"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Ρυθμίσεις"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Υπηρεσίες επί πληρωμή"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Πραγματοποίηση ενεργειών για τις οποίες ενδέχεται να χρεωθείτε."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Τα μηνύματά σας"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"κατάργηση εγκατάστασης συντομεύσεων"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Επιτρέπει στην εφαρμογή την κατάργηση συντομεύσεων από την Αρχική οθόνη χωρίς την παρέμβαση του χρήστη."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"αναδρομολόγηση εξερχόμενων κλήσεων"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Επιτρέπει στην εφαρμογή να βλέπει τον αριθμό που καλέσατε κατά τη διάρκεια μιας εξερχόμενης κλήσης με επιλογή ανακατεύθυνσης της κλήσης σε έναν διαφορετικό αριθμό ή διακοπής της κλήσης."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Επιτρέπει στην εφαρμογή την επεξεργασία εξερχόμενων κλήσεων και την αλλαγή του αριθμού που πρόκειται να κληθεί. Αυτό δίνει τη δυνατότητα στην εφαρμογή να παρακολουθεί, να ανακατευθύνει ή να παρεμποδίζει εξερχόμενες κλήσεις:"</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"λήψη μηνυμάτων κειμένου (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Επιτρέπει στην εφαρμογή τη λήψη και την επεξεργασία μηνυμάτων SMS. Αυτό σημαίνει ότι η εφαρμογή θα μπορούσε να παρακολουθήσει ή να διαγράψει τα μηνύματα που αποστέλλονται στη συσκευή σας χωρίς αυτά να εμφανιστούν σε εσάς."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"λήψη μηνυμάτων κειμένου (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Επιτρέπει στην εφαρμογή την ανάκτηση του περιεχομένου του ενεργού παραθύρου. Τυχόν κακόβουλες εφαρμογές ενδέχεται να ανακτήσουν ολόκληρο το περιεχόμενο του παραθύρου και να εξετάσουν ολόκληρο το κείμενό του εκτός από τους κωδικούς πρόσβασης."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"προσωρινή ενεργοποίηση προσβασιμότητας"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Επιτρέπει σε μια εφαρμογή να ενεργοποιήσει την προσβασιμότητα στη συσκευή. Οι κακόβουλες εφαρμογές ενδέχεται να ενεργοποιήσουν την προσβασιμότητα χωρίς τη συγκατάθεση των χρηστών."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"ανάκτηση διακριτικού παραθύρου"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Επιτρέπει σε μια εφαρμογή να ανακτήσει το διακριτικό παραθύρου. Οι κακόβουλες εφαρμογές μπορούν να εκτελούν μη εξουσιοδοτημένη αλληλεπίδραση με το παράθυρο της εφαρμογής, σε απομίμηση του συστήματος."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"ανάκτηση στατιστικών πλαισίου"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Επιτρέπει σε μια εφαρμογή να συλλέγει στατιστικά στοιχεία πλαισίου. Οι κακόβουλες εφαρμογές μπορούν να παρατηρούν τα στατιστικά στοιχεία πλαισίου των παραθύρων από άλλες εφαρμογές."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"ανάκτηση πληροφοριών παραθύρων"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Επιτρέπει σε μια εφαρμογή να ανακτήσει πληροφορίες σχετικά με τα παράθυρα από το διαχειριστή παραθύρων. Οι κακόβουλες εφαρμογές ενδέχεται να ανακτήσουν πληροφορίες που προορίζονται για την εσωτερική χρήση του συστήματος."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"φιλτράρισμα συμβάντων"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Επιτρέπει σε μια εφαρμογή να καταγράφει ένα φίλτρο εισαγωγής, το οποίο φιλτράρει τη ροή όλων των συμβάντων χρήστη πριν την αποστολή τους. Μια κακόβουλη εφαρμογή μπορεί να ελέγξει τη διεπαφή του συστήματος χωρίς την παρέμβαση του χρήστη."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"μεγέθυνση οθόνης"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Επιτρέπει στην εφαρμογή να μεγεθύνει το περιεχόμενο της οθόνης. Οι κακόβουλες εφαρμογές ενδέχεται να τροποποιούν το περιεχόμενο της οθόνης με τέτοιο τρόπο ώστε η εφαρμογή να μην μπορεί να χρησιμοποιηθεί."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"μερικός τερματισμός λειτουργίας"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Θέτει το πρόγραμμα διαχείρισης δραστηριοτήτων σε κατάσταση τερματισμού λειτουργιών. Δεν εκτελεί πλήρη τερματισμό λειτουργιών."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"αποτροπή εναλλαγών εφαρμογών"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Επιτρέπει στην εφαρμογή την εκπομπή ειδοποίησης σχετικά με τη λήψη μηνύματος SMS. Τυχόν κακόβουλες εφαρμογές ενδέχεται να χρησιμοποιήσουν αυτήν τη δυνατότητα για τη δημιουργία πλαστών εισερχόμενων μηνυμάτων SMS."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"αποστολή εκπομπής που έχει ληφθεί με WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Επιτρέπει στην εφαρμογή τη μετάδοση μιας ειδοποίησης ότι έχει ληφθεί κάποιο μήνυμα WAP PUSH. Τυχόν κακόβουλες εφαρμογές ενδέχεται να χρησιμοποιήσουν αυτήν τη δυνατότητα για τη λήψη πλαστών μηνυμάτων MMS ή την εν αγνοία του χρήστη αντικατάσταση του περιεχομένου οποιασδήποτε ιστοσελίδας με κακόβουλες παραλλαγές."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"αποστολή μετάδοσης κατάταξης δικτύων"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Επιτρέπει στην εφαρμογή να μεταδίδει μια ειδοποίηση ότι απαιτείται κατάταξη των δικτύων. Δεν απαιτείται ποτέ για τις συνήθεις εφαρμογές."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"περιορισμός αριθμού εκτελούμενων διαδικασιών"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Επιτρέπει στην εφαρμογή τον έλεγχο του μέγιστου αριθμού διαδικασιών που θα εκτελούνται. Δεν είναι απαραίτητο για συνήθεις εφαρμογές."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"αναγκαστικός τερματισμός εφαρμογών στο παρασκήνιο"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας Vpn. Δεν απαιτείται για κανονικές εφαρμογές."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"δέσμευση σε ταπετσαρία"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας ταπετσαρίας. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"σύνδεση σε παράγοντα φωνητικής αλληλεπίδρασης"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Επιτρέπει στον κάτοχο τη σύνδεση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας φωνητικής αλληλεπίδρασης. Δεν απαιτείται για κανονικές εφαρμογές."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"μεταφορά σε μια απομακρυσμένη οθόνη"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας απομακρυσμένης οθόνης. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"δέσμευση σε υπηρεσία γραφικών στοιχείων"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας γραφικών στοιχείων. Δεν απαιτείται για κανονικές εφαρμογές."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"σύνδεση σε μια υπηρεσία παρόχου δρομολογητή"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Δίνει στον κάτοχο τη δυνατότητα σύνδεσης με οποιονδήποτε εγγεγραμμένο πάροχο δρομολογητή. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"επικοινωνία με έναν διαχειριστή συσκευής"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Επιτρέπει στον κάτοχο την αποστολή στόχων σε έναν διαχειριστή συσκευής. Δεν είναι απαραίτητο για συνήθεις εφαρμογές."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"σύνδεση σε μία είσοδο τηλεόρασης"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Επιτρέπει στην εφαρμογή τη χρήση οποιουδήποτε εγκατεστημένου αποκωδικοποιητή μέσων για αναπαραγωγή."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"διαχείριση αξιόπιστων διαπιστευτηρίων"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Επιτρέπει στην εφαρμογή την εγκατάσταση και την απεγκατάσταση πιστοποιητικών CA ως αξιόπιστων διαπιστευτηρίων."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"εκτέλεση εφαρμογής κατά τη λειτουργία αδράνειας"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Αυτή η άδεια επιτρέπει στο σύστημα Android να εκτελεί την εφαρμογή στο παρασκήνιο όταν δεν χρησιμοποιείται η συσκευή."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"σύνδεση σε υπηρεσίες αδράνειας"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Αυτή η άδεια επιτρέπει στο σύστημα Android να συνδέεται στις υπηρεσίες αδράνειας μιας εφαρμογής."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"ανάγνωση/εγγραφή σε πόρους που ανήκουν στο διαγνωστικό"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Επιτρέπει στην εφαρμογή την ανάγνωση και την εγγραφή σε οποιονδήποτε πόρο που ανήκει στην ομάδα διαγνωστικού (π.χ. αρχεία στον κατάλογο /dev). Αυτό ενδέχεται να επηρεάσει την σταθερότητα και την ασφάλεια του συστήματος. Θα πρέπει να χρησιμοποιείται ΜΟΝΟ για διαγνωστικά υλικού από τον κατασκευαστή ή τον χειριστή."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"ενεργοποίηση ή απενεργοποίηση στοιχείων εφαρμογής"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Επιτρέπει στην εφαρμογή την ανάγνωση προσωπικών πληροφοριών προφίλ οι οποίες είναι αποθηκευμένες στη συσκευή σας, όπως το όνομα και τα στοιχεία επικοινωνίας σας. Αυτό σημαίνει ότι η εφαρμογή μπορεί να σας αναγνωρίσει και να στείλει τις πληροφορίες του προφίλ σας σε άλλους."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"τροποποίηση κάρτας επαφής"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Επιτρέπει στην εφαρμογή την αλλαγή ή την προσθήκη προσωπικών πληροφοριών προφίλ οι οποίες είναι αποθηκευμένες στη συσκευή σας, όπως το όνομα και τα στοιχεία επικοινωνίας σας. Αυτό σημαίνει ότι η εφαρμογή μπορεί να σας αναγνωρίσει και να στείλει τις πληροφορίες του προφίλ σας σε άλλα άτομα."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"αισθητήρες λειτουργιών (π.χ. καρδιακό ρυθμό)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Επιτρέπει στην εφαρμογή την πρόσβαση στα δεδομένα από τους αισθητήρες που χρησιμοποιείτε για να παρακολουθείτε τις εσωτερικές λειτουργίες σας, όπως τον καρδιακό ρυθμό."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"διαβάστε τη ροή σας κοινωνικών δικτύων"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Επιτρέπει στην εφαρμογή την πρόσβαση και το συγχρονισμό κοινωνικών ενημερώσεων από εσάς και τους φίλους σας. Θα πρέπει να είστε προσεκτικοί όταν μοιράζεστε πληροφορίες -- αυτό δίνει τη δυνατότητα στην εφαρμογή να διαβάζει τις επικοινωνίες ανάμεσα σε εσάς και τους φίλους σας σε κοινωνικά δίκτυα, ανεξάρτητα από το επίπεδο εμπιστευτικότητας. Σημείωση: αυτή η άδεια ίσως να μην μπορεί να εφαρμοστεί σε όλα τα κοινωνικά δίκτυα."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"γράψτε στη ροή σας κοινωνικών δικτύων"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Επιτρέπει στην εφαρμογή να ελέγχει τις λειτουργίες τηλεφώνου της συσκευής. Μια εφαρμογή η οποία διαθέτει αυτήν την άδεια μπορεί να κάνει εναλλαγή μεταξύ δικτύων, να ενεργοποιεί και να απενεργοποιεί το ραδιόφωνο του τηλεφώνου και άλλα, χωρίς να ειδοποιείστε."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ανάγνωση κατάστασης και ταυτότητας τηλεφώνου"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Επιτρέπει στην εφαρμογή την πρόσβαση στις λειτουργίες τηλεφώνου της συσκευής. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να καθορίζει τον αριθμό τηλεφώνου και τα αναγνωριστικά συσκευών, εάν μια κλήση είναι ενεργή, καθώς και τον απομακρυσμένο αριθμό που συνδέεται από μια κλήση."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ανάγνωση ακριβούς κατάστασης τηλεφώνου"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Επιτρέπει στην εφαρμογή να αποκτήσει πρόσβαση στην ακριβή κατάσταση του τηλεφώνου. Αυτή η άδεια επιτρέπει στην εφαρμογή να καθορίσει την πραγματική κατάσταση της κλήσης, εάν η κλήση είναι ενεργή ή πραγματοποιείται στο παρασκήνιο, αποτυχίες κλήσεων, ακριβή δεδομένα κατάστασης σύνδεσης και αποτυχίες σύνδεσης δεδομένων."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"παρεμπόδιση μετάβασης του tablet σε κατάσταση αδράνειας"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"παρεμπόδιση μετάβασης του τηλεφώνου σε κατάσταση αδράνειας"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Επιτρέπει στην εφαρμογή την παρεμπόδιση της μετάβασης του tablet σε κατάσταση αδράνειας."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Αλλαγή κατάστασης WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Επιτρέπει στην εφαρμογή τη σύνδεση στο tablet και την αποσύνδεση από αυτό, από δίκτυα WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Επιτρέπει στην εφαρμογή τη σύνδεση στο τηλέφωνο και την αποσύνδεση από αυτό, από δίκτυα WiMAX."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"κατάταξη δικτύων"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Επιτρέπει στην εφαρμογή να κατατάσσει τα δίκτυα και να επιλέγει τα προτιμώμενα δίκτυα του tablet."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Επιτρέπει στην εφαρμογή να κατατάσσει τα δίκτυα και να επιλέγει τα προτιμώμενα δίκτυα του τηλεφώνου."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"σύζευξη με συσκευές Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Επιτρέπει στην εφαρμογή να προβάλλει τη διαμόρφωση του Bluetooth στο tablet, καθώς και να πραγματοποιεί και να αποδέχεται συνδέσεις με συζευγμένες συσκευές."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Επιτρέπει στην εφαρμογή να προβάλλει τη διαμόρφωση του Bluetooth στο τηλέφωνο, καθώς και να πραγματοποιεί και να αποδέχεται συνδέσεις με συζευγμένες συσκευές."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"δέσμευση σε υπηρεσία ακρόασης ειδοποίησης"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ακρόασης ειδοποιήσεων. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"σύνδεση σε μια υπηρεσία παρόχου συνθηκών"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Επιτρέπει στον κάτοχο τη σύνδεση στη διεπαφή ανωτάτου επιπέδου ενός παρόχου συνθηκών. Δεν απαιτείται για κανονικές εφαρμογές."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Επιτρέπει στον κάτοχο την κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας. Δεν απαιτείται για κανονικές εφαρμογές."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"λήψη παρατηρήσεων σχετικά με την κατάσταση δικτύου"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Επιτρέπει σε μια εφαρμογή να λαμβάνει παρατηρήσεις σχετικά με την κατάσταση δικτύου. Δεν θα πρέπει να απαιτείται ποτέ για κανονικές εφαρμογές."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"αλλαγή βαθμονόμησης της συσκευής εισόδου"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Επιτρέπει στην εφαρμογή να τροποποιεί τις παραμέτρους βαθμονόμησης της οθόνης αφής. Δεν απαιτείται για τις κανονικές εφαρμογές."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"πρόσβαση σε πιστοποιητικά DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Επιτρέπει σε μια εφαρμογή να παρέχει και να χρησιμοποιεί πιστοποιητικά DRM. Δεν θα χρειαστεί ποτέ για κανονικές εφαρμογές."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Έλεγχος του μεγέθους και των χαρακτήρων που επιτρέπονται στους κωδικούς πρόσβασης ξεκλειδώματος οθόνης."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Παρακολούθηση προσπαθειών ξεκλειδώματος οθόνης"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Επιτρέπει σε μια εφαρμογή να αποκτήσει πρόσβαση στον ασφαλή αποθηκευτικό χώρο με κλείδωμα."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Έλεγχος εμφάνισης και απόκρυψης κλειδώματος πληκτρολογίου"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Επιτρέπει σε μια εφαρμογή τον έλεγχο του κλειδώματος πληκτρολογίου."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Αντίληψη αλλαγών καταστάσεων εμπιστοσύνης."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Επιτρέπει σε μια εφαρμογή να αντιλαμβάνεται τις αλλαγές στην κατάσταση εμπιστοσύνης."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Σύνδεση σε υπηρεσία trust agent"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Επιτρέπει σε μια εφαρμογή να συνδεθεί σε μια υπηρεσία trust agents."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Αλληλεπίδραση με το σύστημα ενημέρωσης και ανάκτησης"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Επιτρέπει σε μια εφαρμογή να αλληλεπιδρά με το σύστημα ανάκτησης και ενημερώσεων συστήματος."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Αγγίξτε δύο φορές για έλεγχο εστίασης"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Ταπετσαρία"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Αλλαγή ταπετσαρίας"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Υπηρεσία ακρόασης ειδοποίησης"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Πάροχος συνθηκών"</string>
<string name="vpn_title" msgid="19615213552042827">"Το VPN ενεργοποιήθηκε"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Το VPN ενεργοποιήθηκε από την εφαρμογή <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Αγγίξτε για τη διαχείριση του δικτύου."</string>
@@ -1396,7 +1356,7 @@
<string name="vpn_lockdown_error" msgid="6009249814034708175">"Σφάλμα πάντα ενεργοποιημένου VPN"</string>
<string name="vpn_lockdown_config" msgid="6415899150671537970">"Αγγίξτε για διαμόρφωση"</string>
<string name="upload_file" msgid="2897957172366730416">"Επιλογή αρχείου"</string>
- <string name="no_file_chosen" msgid="6363648562170759465">"Δεν επιλέχθηκε κανένα αρχείο."</string>
+ <string name="no_file_chosen" msgid="6363648562170759465">"Δεν έχει επιλεγεί αρχείο"</string>
<string name="reset" msgid="2448168080964209908">"Επαναφορά"</string>
<string name="submit" msgid="1602335572089911941">"Υποβολή"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Η λειτουργία αυτοκινήτου είναι ενεργοποιημένη"</string>
@@ -1473,8 +1433,8 @@
<string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
<string name="activitychooserview_choose_application" msgid="2125168057199941199">"Επιλέξτε κάποια εφαρμογή"</string>
<string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Δεν ήταν δυνατή η εκκίνηση του <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
- <string name="shareactionprovider_share_with" msgid="806688056141131819">"Κοινοποίηση με"</string>
- <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Κοινοποίηση με <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="shareactionprovider_share_with" msgid="806688056141131819">"Κοινή χρήση με"</string>
+ <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Κοινή χρήση με <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Στοιχείο χειρισμού με δυνατότητα ολίσθησης. Αγγίξτε και πατήστε παρατεταμένα."</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Σύρετε για ξεκλείδωμα."</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Συνδέστε ακουστικά για να ακούσετε τα πλήκτρα του κωδικού πρόσβασης να εκφωνούνται."</string>
@@ -1518,7 +1478,7 @@
<string name="sha1_fingerprint" msgid="7930330235269404581">"Αποτύπωμα SHA-1"</string>
<string name="activity_chooser_view_see_all" msgid="4292569383976636200">"Εμφάνιση όλων"</string>
<string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"Επιλογή δραστηριότητας"</string>
- <string name="share_action_provider_share_with" msgid="5247684435979149216">"Κοινοποίηση με"</string>
+ <string name="share_action_provider_share_with" msgid="5247684435979149216">"Κοινή χρήση με"</string>
<string name="list_delimeter" msgid="3975117572185494152">", "</string>
<string name="sending" msgid="3245653681008218030">"Γίνεται αποστολή…"</string>
<string name="launchBrowserDefault" msgid="2057951947297614725">"Εκκίνηση προγράμματος περιήγησης;"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index c4b7aa0..549c6d5 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> days"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> day <xliff:g id="HOURS">%2$d</xliff:g> hrs"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> day <xliff:g id="HOURS">%2$d</xliff:g> hr"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> hrs"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> hr <xliff:g id="MINUTES">%2$d</xliff:g> mins"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> hr <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> mins"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> secs"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> sec"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> secs"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sec"</string>
<string name="untitled" msgid="4638956954852782576">"<Untitled>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sync"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Too many <xliff:g id="CONTENT_TYPE">%s</xliff:g> deletions."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet storage is full. Delete some files to free space."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Watch storage is full. Delete some files to free up space."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Phone storage is full. Delete some files to free space."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Network may be monitored"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"By an unknown third party"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Ringer on"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Shutting down…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Your tablet will shut down."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Your watch will shut down."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Your phone will shut down."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Do you want to shut down?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reboot to safe mode"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Aeroplane mode"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Aeroplane mode is ON"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Aeroplane mode is OFF"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Settings"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Services that cost you money"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Do things that can cost you money."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Your messages"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"uninstall shortcuts"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Allows the application to remove Home screen shortcuts without user intervention."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"reroute outgoing calls"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Allows the app to see the number being dialled during an outgoing call with the option to redirect the call to a different number or abort the call altogether."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Allows the app to process outgoing calls and change the number to be dialled. This permission allows the app to monitor, redirect or prevent outgoing calls."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"receive text messages (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Allows the app to receive and process SMS messages. This means that the app could monitor or delete messages sent to your device without showing them to you."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"receive text messages (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Allows the app to retrieve the content of the active window. Malicious apps may retrieve the entire window content and examine all its text except passwords."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"temporary enable accessibility"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Allows an application to temporarily enable accessibility on the device. Malicious apps may enable accessibility without user consent."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"retrieve window token"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Allows an application to retrieve the window token. Malicious apps may perform unauthorised interaction with the application window impersonating the system."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"retrieve frame statistics"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Allows an application to collect frame statistics. Malicious apps may observe the frame statistics of windows from other apps."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"retrieve window info"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Allows an application to retrieve information about the windows from the window manager. Malicious apps may retrieve information that is intended for internal system usage."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filter events"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Allows an application to register an input filter which filters the stream of all user events before they are dispatched. Malicious app may control the system UI without user intervention."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"magnify display"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Allows an application to magnify the content of a display. Malicious apps may transform the display content in a way that renders the device unusable."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"partial shutdown"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Puts the activity manager into a shut-down state. Does not perform a complete shut down."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"prevent app switches"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Allows the app to broadcast a notification that an SMS message has been received. Malicious apps may use this to forge incoming SMS messages."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"send WAP-PUSH-received broadcast"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Allows the app to broadcast a notification that a WAP PUSH message has been received. Malicious apps may use this to forge MMS message receipt or to silently replace the content of any web page with malicious variants."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"send score networks broadcast"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Allows the app to broadcast a notification that networks need to be scored. Never needed for normal apps."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limit number of running processes"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Allows the app to control the maximum number of processes that will run. Never needed for normal apps."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"force background apps to close"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Allows the holder to bind to the top-level interface of a Vpn service. Should never be needed for normal apps."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"bind to wallpaper"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Allows the holder to bind to the top-level interface of wallpaper. Should never be needed for normal applications."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"bind to a voice interactor"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Allows the holder to bind to the top-level interface of a voice interaction service. Should never be needed for normal apps."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind to a remote display"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Allows the holder to bind to the top-level interface of a remote display. Should never be needed for normal apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind to a widget service"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bind to a route provider service"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Allows the holder to bind to any registered route providers. Should never be needed for normal apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Allows the holder to send intents to a device administrator. Should never be needed for normal apps."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"bind to a TV input"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Allows the app to use any installed media decoder to decode for playback."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"manage trusted credentials"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Allows the app to install and uninstall CA certificates as trusted credentials."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"run application during idle time"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"This permission allows the Android system to run the application in the background while the device is not in use."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"bind to idle services"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"This permission allows the Android system to bind to an application\'s idle services."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"read/write to resources owned by diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Allows the app to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"enable or disable app components"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Allows the app to read personal profile information stored on your device, such as your name and contact information. This means that the app can identify you and may send your profile information to others."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"modify your own contact card"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Allows the app to change or add to personal profile information stored on your device, such as your name and contact information. This means that the app can identify you and may send your profile information to others."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"body sensors (like heart rate monitors)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Allows the app to access data from sensors that you use to measure what’s happening inside your body, such as heart rate."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"read your social stream"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Allows the app to access and sync social updates from you and your friends. Be careful when sharing information - this allows the app to read communications between you and your friends on social networks, regardless of confidentiality. Note: this permission may not be enforced on all social networks."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"write to your social stream"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Allows the app to control the phone features of the device. An app with this permission can switch networks, turn the phone radio on and off and the like without ever notifying you."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"read phone status and identity"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Allows the app to access the phone features of the device. This permission allows the app to determine the phone number and device IDs, whether a call is active and the remote number connected by a call."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"read precise phone states"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Allows the app to access the precise phone states. This permission allows the app to determine the real call status, whether a call is active or in the background, call fails, precise data connection status and data connection fails."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"prevent tablet from sleeping"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"prevent phone from sleeping"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Allows the app to prevent the tablet from going to sleep."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"change WiMAX state"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Allows the app to connect the tablet to and disconnect the tablet from WiMAX networks."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Allows the app to connect the phone to and disconnect the phone from WiMAX networks."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"score networks"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Allows the app to rank networks and influence which networks the tablet should prefer."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Allows the app to rank networks and influence which networks the phone should prefer."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"pair with Bluetooth devices"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Allows the app to view the configuration of Bluetooth on the tablet and to make and accept connections with paired devices."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Allows the app to view the configuration of the Bluetooth on the phone and to make and accept connections with paired devices."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Allows the app to retrieve, examine, and clear notifications, including those posted by other apps."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind to a notification listener service"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Allows the holder to bind to the top-level interface of a notification listener service. Should never be needed for normal apps."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bind to a condition provider service"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invoke the carrier-provided configuration app"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"listen for observations on network conditions"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"change input device calibration"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Allows the app to modify the calibration parameters of the touch screen. Should never be needed for normal apps."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"access DRM certificates"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Allows an application to provision and use DRM certficates. Should never be needed for normal apps."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Control the length and the characters allowed in screen-unlock passwords."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Allows an application to access keyguard secure storage."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Control displaying and hiding keyguard"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Allows an application to control keyguard."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Listen to trust state changes."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Allows an application to listen for changes in trust state."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bind to a trust agent service"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Allows an application to bind to a trust agent service."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interact with update and recovery system"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Allows an application to interact with the recovery system and system updates."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Touch twice for zoom control"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Change wallpaper"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification listener"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Condition provider"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activated"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN is activated by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Touch to manage the network."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index c4b7aa0..549c6d5 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> days"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> day <xliff:g id="HOURS">%2$d</xliff:g> hrs"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> day <xliff:g id="HOURS">%2$d</xliff:g> hr"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> hrs"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> hr <xliff:g id="MINUTES">%2$d</xliff:g> mins"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> hr <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> mins"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> secs"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> sec"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> secs"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sec"</string>
<string name="untitled" msgid="4638956954852782576">"<Untitled>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sync"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Too many <xliff:g id="CONTENT_TYPE">%s</xliff:g> deletions."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet storage is full. Delete some files to free space."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Watch storage is full. Delete some files to free up space."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Phone storage is full. Delete some files to free space."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Network may be monitored"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"By an unknown third party"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Ringer on"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Shutting down…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Your tablet will shut down."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Your watch will shut down."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Your phone will shut down."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Do you want to shut down?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reboot to safe mode"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Aeroplane mode"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Aeroplane mode is ON"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Aeroplane mode is OFF"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Settings"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Services that cost you money"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Do things that can cost you money."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Your messages"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"uninstall shortcuts"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Allows the application to remove Home screen shortcuts without user intervention."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"reroute outgoing calls"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Allows the app to see the number being dialled during an outgoing call with the option to redirect the call to a different number or abort the call altogether."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Allows the app to process outgoing calls and change the number to be dialled. This permission allows the app to monitor, redirect or prevent outgoing calls."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"receive text messages (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Allows the app to receive and process SMS messages. This means that the app could monitor or delete messages sent to your device without showing them to you."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"receive text messages (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Allows the app to retrieve the content of the active window. Malicious apps may retrieve the entire window content and examine all its text except passwords."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"temporary enable accessibility"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Allows an application to temporarily enable accessibility on the device. Malicious apps may enable accessibility without user consent."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"retrieve window token"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Allows an application to retrieve the window token. Malicious apps may perform unauthorised interaction with the application window impersonating the system."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"retrieve frame statistics"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Allows an application to collect frame statistics. Malicious apps may observe the frame statistics of windows from other apps."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"retrieve window info"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Allows an application to retrieve information about the windows from the window manager. Malicious apps may retrieve information that is intended for internal system usage."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filter events"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Allows an application to register an input filter which filters the stream of all user events before they are dispatched. Malicious app may control the system UI without user intervention."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"magnify display"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Allows an application to magnify the content of a display. Malicious apps may transform the display content in a way that renders the device unusable."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"partial shutdown"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Puts the activity manager into a shut-down state. Does not perform a complete shut down."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"prevent app switches"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Allows the app to broadcast a notification that an SMS message has been received. Malicious apps may use this to forge incoming SMS messages."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"send WAP-PUSH-received broadcast"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Allows the app to broadcast a notification that a WAP PUSH message has been received. Malicious apps may use this to forge MMS message receipt or to silently replace the content of any web page with malicious variants."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"send score networks broadcast"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Allows the app to broadcast a notification that networks need to be scored. Never needed for normal apps."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limit number of running processes"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Allows the app to control the maximum number of processes that will run. Never needed for normal apps."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"force background apps to close"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Allows the holder to bind to the top-level interface of a Vpn service. Should never be needed for normal apps."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"bind to wallpaper"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Allows the holder to bind to the top-level interface of wallpaper. Should never be needed for normal applications."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"bind to a voice interactor"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Allows the holder to bind to the top-level interface of a voice interaction service. Should never be needed for normal apps."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind to a remote display"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Allows the holder to bind to the top-level interface of a remote display. Should never be needed for normal apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind to a widget service"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bind to a route provider service"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Allows the holder to bind to any registered route providers. Should never be needed for normal apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Allows the holder to send intents to a device administrator. Should never be needed for normal apps."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"bind to a TV input"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Allows the app to use any installed media decoder to decode for playback."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"manage trusted credentials"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Allows the app to install and uninstall CA certificates as trusted credentials."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"run application during idle time"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"This permission allows the Android system to run the application in the background while the device is not in use."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"bind to idle services"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"This permission allows the Android system to bind to an application\'s idle services."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"read/write to resources owned by diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Allows the app to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"enable or disable app components"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Allows the app to read personal profile information stored on your device, such as your name and contact information. This means that the app can identify you and may send your profile information to others."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"modify your own contact card"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Allows the app to change or add to personal profile information stored on your device, such as your name and contact information. This means that the app can identify you and may send your profile information to others."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"body sensors (like heart rate monitors)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Allows the app to access data from sensors that you use to measure what’s happening inside your body, such as heart rate."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"read your social stream"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Allows the app to access and sync social updates from you and your friends. Be careful when sharing information - this allows the app to read communications between you and your friends on social networks, regardless of confidentiality. Note: this permission may not be enforced on all social networks."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"write to your social stream"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Allows the app to control the phone features of the device. An app with this permission can switch networks, turn the phone radio on and off and the like without ever notifying you."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"read phone status and identity"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Allows the app to access the phone features of the device. This permission allows the app to determine the phone number and device IDs, whether a call is active and the remote number connected by a call."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"read precise phone states"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Allows the app to access the precise phone states. This permission allows the app to determine the real call status, whether a call is active or in the background, call fails, precise data connection status and data connection fails."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"prevent tablet from sleeping"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"prevent phone from sleeping"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Allows the app to prevent the tablet from going to sleep."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"change WiMAX state"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Allows the app to connect the tablet to and disconnect the tablet from WiMAX networks."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Allows the app to connect the phone to and disconnect the phone from WiMAX networks."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"score networks"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Allows the app to rank networks and influence which networks the tablet should prefer."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Allows the app to rank networks and influence which networks the phone should prefer."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"pair with Bluetooth devices"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Allows the app to view the configuration of Bluetooth on the tablet and to make and accept connections with paired devices."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Allows the app to view the configuration of the Bluetooth on the phone and to make and accept connections with paired devices."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Allows the app to retrieve, examine, and clear notifications, including those posted by other apps."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bind to a notification listener service"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Allows the holder to bind to the top-level interface of a notification listener service. Should never be needed for normal apps."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bind to a condition provider service"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invoke the carrier-provided configuration app"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"listen for observations on network conditions"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"change input device calibration"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Allows the app to modify the calibration parameters of the touch screen. Should never be needed for normal apps."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"access DRM certificates"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Allows an application to provision and use DRM certficates. Should never be needed for normal apps."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Control the length and the characters allowed in screen-unlock passwords."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Allows an application to access keyguard secure storage."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Control displaying and hiding keyguard"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Allows an application to control keyguard."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Listen to trust state changes."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Allows an application to listen for changes in trust state."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bind to a trust agent service"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Allows an application to bind to a trust agent service."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interact with update and recovery system"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Allows an application to interact with the recovery system and system updates."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Touch twice for zoom control"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Change wallpaper"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification listener"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Condition provider"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activated"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN is activated by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Touch to manage the network."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 1225c81..f8e789c 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> días"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> día <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> día <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> h"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
<string name="untitled" msgid="4638956954852782576">"<Sin título>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronización"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Se ha agotado el espacio de almacenamiento de la tablet. Elimina algunos archivos para liberar espacio."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"El almacenamiento del reloj está completo. Elimina algunos archivos para liberar espacio."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Se ha agotado el espacio de almacenamiento del dispositivo. Elimina algunos archivos para liberar espacio."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Es posible que la red esté supervisada"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Por un tercero desconocido"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Timbre activado"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Apagando…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tu tablet se apagará."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Se apagará el reloj."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Tu dispositivo se apagará."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"¿Deseas apagarlo?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reiniciar en modo seguro"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avión"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"El modo avión está Activado"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"El modo avión está Desactivado"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Configuración"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Servicios que te cuestan dinero"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Permite que las aplicaciones realicen actividades con cargo."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Tus mensajes"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"desinstalar accesos directos"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permite que la aplicación elimine accesos directos de la pantalla principal sin que el usuario intervenga."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"redireccionar llamadas salientes"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permite que la aplicación vea el número marcado al realizar una llamada, con la opción de redirigir esta llamada a un número distinto o cancelarla completamente."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Permite que la aplicación procese las llamadas salientes y cambie el número que se va a marcar. La aplicación puede utilizar este permiso para controlar o desviar llamadas salientes o para impedir que se realicen."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"recibir mensajes de texto (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Permite que la aplicación reciba y procese mensajes SMS, lo que significa que podría controlar o eliminar mensajes enviados al dispositivo sin mostrártelos."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"recibir mensajes de texto (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permite que la aplicación recupere el contenido de la ventana activa. Las aplicaciones maliciosas pueden recuperar el contenido completo de la ventana y examinar todo el texto, excepto las contraseñas."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"Activación temporal de la accesibilidad"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permite a una aplicación activar temporalmente la accesibilidad en el dispositivo. Las aplicaciones maliciosas pueden activar la accesibilidad sin el consentimiento del usuario."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"recuperar token de ventana"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Permite que una aplicación recupere el token de ventana. Las aplicaciones maliciosas pueden interaccionar sin autorización con la ventana de la aplicación al hacerse pasar por el sistema."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"recuperar estadísticas de marcos"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Permite que una aplicación recopile estadísticas de marcos. Las aplicaciones maliciosas pueden observar estas estadísticas de ventanas desde otras aplicaciones."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"recuperar información de ventanas"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permite que una aplicación recupere la información del administrador de ventanas relacionada con estas. Las aplicaciones maliciosas pueden recuperar información destinada al uso interno del sistema."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtrar eventos"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Permite que una aplicación registre un filtro de entrada que filtre la transmisión de todos los eventos del usuario antes de ser enviados. Las aplicaciones maliciosas pueden controlar la IU del sistema sin la intervención del usuario."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"ampliar la pantalla"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Permite que una aplicación amplíe el contenido de una pantalla. Las aplicaciones malintencionadas pueden transformar el contenido de la pantalla de manera que el dispositivo quede inutilizable."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"cierre parcial"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Pone al administrador de la actividad en estado de cierre. No realiza un cierre completo."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedir conmutadores de aplicación"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permite que la aplicación transmita una notificación acerca de la recepción de un mensaje SMS. Las aplicaciones maliciosas pueden utilizar este permiso para falsificar mensajes SMS entrantes."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar emisiones WAP-PUSH-recibido"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permite que la aplicación transmita una notificación acerca de la recepción de un mensaje WAP PUSH. Las aplicaciones maliciosas pueden utilizar este permiso para falsificar la recepción de mensajes MMS o para reemplazar sin aviso el contenido de cualquier página web con variantes maliciosas."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"enviar transmisión de puntuación de redes"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permite que la aplicación transmita una notificación que las redes necesitan para recibir una puntuación. Las aplicaciones normales no necesitan nunca este permiso."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar la cantidad de procesos en ejecución"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permite que la aplicación controle la cantidad máxima de procesos que se ejecutarán. Las aplicaciones normales no deben utilizar este permiso."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forzar el cierre de aplicaciones de fondo"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite al titular vincularse a la interfaz de nivel superior de un servicio de VPN. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"vincular a un fondo de pantalla"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite al propietario vincularse a la interfaz de nivel superior de un fondo de pantalla. Las aplicaciones normales no deben utilizar este permiso."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"vincular con un servicio de interacción por voz"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite vincular con la interfaz de nivel superior de un servicio de interacción por voz. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vincular a una pantalla remota"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite al propietario vincularse a la interfaz de nivel superior de una pantalla remota. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincular a un servicio de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite al propietario vincularse a la interfaz de nivel superior del servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"vincular con un servicio de proveedor de rutas"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permite al propietario vincular con proveedores de rutas registrados. No debe ser necesario para las aplicaciones normales."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con un administrador de dispositivos"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite enviar intentos a un administrador de dispositivos. Las aplicaciones normales no deberían necesitar este permiso."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"vincular a una entrada de TV"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Permite al propietario vincularse a la interfaz de nivel superior de una entrada de TV. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"agregar o eliminar un administrador de dispositivos"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite al propietario agregar o eliminar administradores de dispositivos activos. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar la orientación de la pantalla"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que la aplicación use cualquier decodificador de archivos multimedia instalado para la reproducción."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrar credenciales de confianza"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que la aplicación instale y desinstale certificados de CA como credenciales de confianza."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"ejecutar la aplicación durante el tiempo de inactividad"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Con este permiso, el sistema Android puede ejecutar la aplicación en segundo plano mientras el dispositivo no está en uso."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"vincular con servicios inactivos"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Este permiso autoriza al sistema Android a vincularse con los servicios inactivos de una aplicación."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"leer y escribir a recursos dentro del grupo de diagnóstico"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que la aplicación lea y escriba en cualquier recurso propiedad del grupo de diagnóstico como, por ejemplo, archivos in/dev. Este permiso podría afectar la seguridad y estabilidad del sistema. SOLO se debe utilizar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"activar o desactivar componentes de la aplicación"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Permite que la aplicación consulte la información del perfil personal almacenada en el dispositivo, como el nombre o la información de contacto, lo que significa que la aplicación puede identificar al usuario y enviar la información de su perfil a otros usuarios."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"modif. tarjeta contacto propia"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Permite que la aplicación modifique la información del perfil personal almacenada en el dispositivo, como el nombre o la información de contacto, o que agregue contenido a esa información. Esto significa que puede identificarte y enviar la información de tu perfil a otros usuarios."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"sensores corporales (frec. card)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Permite que la aplicación acceda a datos de sensores que utilizas para medir lo que sucede en tu cuerpo, como la frecuencia cardíaca."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"Lectura de tu muro social"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Permite que la aplicación acceda a las actualizaciones de tus redes sociales y las de tus amigos, y que las sincronice. Ten cuidado al compartir información, ya que la aplicación puede utilizar este permiso para leer las conversaciones que tengas con tus amigos en las redes sociales sin tener en cuenta si son confidenciales. Nota: Este permiso no se puede utilizar en todas las redes sociales."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"Escritura en tu muro social"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite que la aplicación controle las funciones de teléfono del dispositivo. Una aplicación con este permiso puede cambiar redes, encender y apagar la radio del teléfono y tareas similares sin siquiera notificártelo."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"leer la identidad y el estado del dispositivo"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. La aplicación puede utilizar este permiso para descubrir identificadores de dispositivos y números de teléfono, para saber si una llamada está activa y para conocer el número remoto con el que se ha establecido conexión mediante una llamada."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"leer estados precisos del teléfono"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permite que la aplicación acceda a los estados precisos del teléfono y determine el estado real de la llamada, si hay una llamada activa o en segundo plano, si se produjeron fallos en la llamada, el estado preciso de la conexión de datos y si hubo fallos relacionados con la conexión de datos."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evitar que el tablet entre en estado de inactividad"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"evitar que el dispositivo entre en estado de inactividad"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que la aplicación evite que la tablet entre en estado de inactividad."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Cambiar el estado de WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite que la aplicación conecte la tablet a una red WiMAX y que la desconecte de ella."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite que la aplicación conecte el dispositivo a una red WiMAX y que lo desconecte de ella."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"puntuar redes"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permite que la aplicación clasifique redes e influya en las redes que la tablet debería preferir."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permite que la aplicación clasifique redes e influya en las redes que el teléfono debería preferir."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"vincular con dispositivos Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite que la aplicación vea la configuración de Bluetooth de la tablet y que cree y acepte conexiones con los dispositivos sincronizados."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite que la aplicación vea la configuración de Bluetooth del dispositivo y que cree y acepte conexiones con los dispositivos sincronizados."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y elimine notificaciones, incluidas aquellas publicadas por otras aplicaciones."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Vincular a un servicio de agente de escucha de notificaciones"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite al propietario vincularse a la interfaz de nivel superior de un servicio de agente de escucha de notificaciones. Las aplicaciones normales no deberían necesitar este permiso."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"vincular con un servicio de proveedor de condiciones"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite vincular con la interfaz de nivel superior de un servicio de proveedor de condiciones. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ejecutar la aplicación de configuración proporcionada por el proveedor"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite al propietario ejecutar la aplicación de configuración proporcionada por el proveedor. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Detectar cambios en el estado de la red"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que una aplicación detecte cambios en el estado de la red. Las aplicaciones normales no deberían necesitar este permiso."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"cambiar la calibración del dispositivo de entrada"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite que la aplicación modifique los parámetros de calibración de la pantalla táctil. Las aplicaciones normales no deberían necesitar este permiso."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"Acceder a certificados DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permite que una aplicación proporcione y utilice certificados DRM. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer reglas de contraseña"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas para desbloquear la pantalla"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Supervisa los intentos para desbloquear la pantalla"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permite que una aplicación acceda al almacenamiento seguro de bloqueos."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Controlar cuándo se muestra y se oculta el bloqueo"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite que una aplicación controle los bloqueos."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Detectar cambios en estado de confianza"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que una aplicación detecte cambios en el estado de confianza."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Vincular con un servicio de agente de confianza"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que una aplicación se vincule con un servicio de agente de confianza."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interaccionar con el sistema de recuperación y las actualizaciones"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Permite que una aplicación interaccione con el sistema de recuperación y las actualizaciones del sistema."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toca dos veces para acceder al control de zoom."</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Papel tapiz"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Agente de escucha de notificaciones"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Proveedor de condiciones"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN está activado por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 1c6aa8d..5010841 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> días"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> día <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> día <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> h"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
<string name="untitled" msgid="4638956954852782576">"<Sin título>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"..."</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronización"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Se ha agotado el espacio de almacenamiento del tablet. Elimina algunos archivos para liberar espacio."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"El almacenamiento del reloj está lleno. Elimina algunos archivos para liberar espacio."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Se ha agotado el espacio de almacenamiento del teléfono. Elimina algunos archivos para liberar espacio."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Es posible que la red esté supervisada"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Por un tercero desconocido"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Timbre activado"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Apagando..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"El tablet se apagará."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"El reloj se apagará."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"El teléfono se apagará."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"¿Seguro que quieres apagar el teléfono?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reiniciar en modo seguro"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avión"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avión activado. Desactivar"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avión desactivado. Activar"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Ajustes"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"> 999"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Servicios por los que tienes que pagar"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Hacer acciones por las que puede que tengas que pagar"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Tus mensajes"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"desinstalar accesos directos"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permite que la aplicación elimine accesos directos de la pantalla de inicio sin la intervención del usuario."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"redireccionar llamadas salientes"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permite que la aplicación vea el número que se marca al realizar una llamada con la opción de redirigir la llamada a otro número o cancelar la llamada."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Permite que la aplicación procese las llamadas salientes y cambie el número que se va a marcar. La aplicación puede utilizar este permiso para controlar, desviar o impedir que se realicen llamadas salientes."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"recibir mensajes de texto (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Permite que la aplicación reciba y procese mensajes MMS, lo que significa que podría utilizar este permiso para controlar o eliminar mensajes enviados al dispositivo sin mostrárselos al usuario."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"recibir mensajes de texto (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permite que la aplicación recupere el contenido de la ventana activa. Las aplicaciones malintencionadas pueden recuperar todo el contenido de la ventana y analizar todo el texto de la misma, excepto las contraseñas."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"habilitar la accesibilidad de forma temporal"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permite que una aplicación habilite la accesibilidad en el dispositivo de forma temporal. Las aplicaciones maliciosas pueden habilitar la accesibilidad sin el consentimiento del usuario."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"recuperar token de ventana"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Permite que una aplicación recupere el token de ventana. Las aplicaciones maliciosas pueden interactuar sin autorización con la ventana de la aplicación suplantando la identidad del sistema."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"recuperar estadísticas de enmarcación"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Permite que una aplicación recopile estadísticas de enmarcación. Las aplicaciones maliciosas pueden observar estas estadísticas de ventanas desde otras aplicaciones."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"recuperar información de ventanas"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permite que una aplicación recupere información sobre las ventanas del administrador de ventanas. Las aplicaciones malintencionadas pueden recuperar información destinada al uso interno del sistema."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtrar eventos"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Permite que una aplicación registre un filtro de entrada que filtre el flujo de los eventos del usuario antes de que se envíe. Las aplicaciones malintencionadas pueden controlar la interfaz del sistema sin la intervención del usuario."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"ampliar pantalla"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Permite que una aplicación amplíe el contenido de una pantalla. Las aplicaciones maliciosas pueden transformar el contenido de la pantalla para que el dispositivo no se pueda utilizar."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"cierre parcial"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Pone el administrador de actividades en estado de cierre. No realiza un cierre completo."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"evitar cambios de aplicación"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permite que la aplicación emita una notificación cuando se haya recibido un mensaje SMS. Las aplicaciones malintencionadas pueden usar este permiso para falsificar mensajes SMS entrantes."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar emisión recibida mediante mensaje WAP PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permite que la aplicación envíe una notificación cuando se haya recibido un mensaje WAP PUSH. Las aplicaciones malintencionadas pueden usar este permiso para falsificar la recepción de un mensaje MMS o para reemplazar sin aviso el contenido de cualquier página web con variantes malintencionadas."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"enviar notificaciones sobre la puntuación de las redes"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permite que la aplicación emita una notificación que la red necesita para recibir una puntuación. Las aplicaciones normales no necesitan nunca este permiso."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar el número de procesos en ejecución"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permite que la aplicación controle el número máximo de procesos que se ejecutarán. No es necesario nunca para las aplicaciones normales."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forzar el cierre de aplicaciones en segundo plano"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite enlazar con la interfaz de nivel superior de un servicio de VPN. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"enlazar con un fondo de pantalla"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite enlazar con la interfaz de nivel superior de un fondo de pantalla. Las aplicaciones normales no deberían necesitar este permiso."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"enlazar con un servicio de interacción de voz"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite enlazar con la interfaz de nivel superior de un servicio de interacción de voz. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"enlazar a una pantalla remota"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite enlazar con la interfaz de nivel superior de una pantalla remota. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"enlazar con un servicio de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite enlazar con la interfaz de nivel superior de un servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"enlazar con un servicio de proveedor de rutas"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permite enlazar con proveedores de rutas registrados. No debe ser necesario para las aplicaciones normales."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con el administrador de un dispositivo"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite que se envíen intentos a un administrador de dispositivos. Las aplicaciones normales nunca deberían necesitar este permiso."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"enlazar a una entrada de TV"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Permite enlazar con la interfaz de nivel superior de una entrada de TV. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"añadir o eliminar un administrador de dispositivos"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite añadir o eliminar administradores de dispositivos activos. No debe ser necesario para aplicaciones normales."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar orientación de la pantalla"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que la aplicación use cualquier decodificador de archivos multimedia instalado para la reproducción."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrar credenciales de confianza"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que la aplicación instale y desinstale certificados de CA como credenciales de confianza."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"ejecutar la aplicación durante el tiempo de inactividad"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Esto permite que el sistema Android ejecute la aplicación en segundo plano mientras el dispositivo no se utiliza."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"ocultar para servicios inactivos"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Esto permite que el sistema Android enlace con servicios inactivos de una aplicación."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"leer/escribir en los recursos propiedad del grupo de diagnóstico"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que la aplicación consulte y escriba en cualquier recurso del grupo de diagnóstico como, por ejemplo, archivos en /dev. Este permiso podría afectar a la seguridad y estabilidad del sistema. SOLO se debe usar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"habilitar o inhabilitar componentes de la aplicación"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Permite que la aplicación consulte la información del perfil personal almacenada en el dispositivo (como el nombre o la información de contacto), lo que significa que la aplicación puede identificar al usuario y enviar la información de su perfil a otros usuarios."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"modificar tu propia tarjeta de contacto"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Permite que la aplicación modifique la información del perfil personal almacenada en el dispositivo (como el nombre o la información de contacto) o que añada contenido a esa información, lo que significa que puede identificar al usuario y enviar la información de su perfil a otros usuarios."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"sens. corp. (mon. frec. card.)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Permite que la aplicación acceda a datos de sensores que utilizas para medir lo que sucede en tu cuerpo, como la frecuencia cardíaca."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"consulta tu actividad social"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Permite que la aplicación acceda a novedades de redes sociales tuyas y de tus amigos y las sincronice. Ten cuidado al compartir información, ya que la aplicación puede utilizar este permiso para leer conversaciones privadas con tus amigos en las redes sociales sin tener en cuenta si son confidenciales. Nota: este permiso no se puede utilizar en todas las redes sociales."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"escribir en tu actividad social"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite que la aplicación controle las funciones de teléfono del dispositivo. Las aplicaciones que tengan este permiso pueden cambiar de red, desactivar la señal móvil, etc., sin necesidad de informar al usuario."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"consultar la identidad y el estado del teléfono"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. La aplicación puede utilizar este permiso para descubrir identificadores de dispositivos y números de teléfono, para saber si una llamada está activa y para conocer el número remoto con el que se ha establecido conexión mediante una llamada."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"leer estados precisos del teléfono"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permite que la aplicación acceda a estados precisos del teléfono y que pueda determinar el estado real de la llamada, si una llamada está activa o en segundo plano, si se ha producido un error en la llamada, el estado de conexión de datos preciso y si se ha producido un error en la conexión de datos."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir que el tablet entre en modo de suspensión"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir que el teléfono entre en modo de suspensión"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que la aplicación impida que el tablet entre en modo de suspensión."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Cambiar estado de WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite que la aplicación conecte el tablet a redes WiMAX y lo desconecte de ellas."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite que la aplicación conecte el teléfono a redes WiMAX y lo desconecte de ellas."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"puntuar redes"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permite que la aplicación clasifique redes e influya en las redes que el tablet debe preferir."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permite que la aplicación clasifique una red e influya en las redes que el teléfono debe preferir."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"vincular con dispositivos Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite que la aplicación acceda a la configuración de Bluetooth del tablet y que establezca y acepte conexiones con los dispositivos sincronizados."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite que la aplicación acceda a la configuración de Bluetooth del teléfono y que establezca y acepte conexiones con los dispositivos sincronizados."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y borre notificaciones, incluidas las que han publicado otras aplicaciones."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"enlazar con un servicio de detector de notificaciones"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite enlazar con la interfaz de nivel superior de un servicio de detector de notificaciones. No debe ser necesario para las aplicaciones normales."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"enlazar con un servicio de proveedor de condiciones"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite enlazar con la interfaz de nivel superior de un servicio de proveedor de condiciones. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ejecutar la aplicación de configuración proporcionada por el operador"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite ejecutar la aplicación de configuración proporcionada por el operador. No debe ser necesario para aplicaciones normales."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"detectar cambios en el estado de la red"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que una aplicación detecte cambios en el estado de la red. No debe ser necesario para aplicaciones normales."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"cambiar la calibración del dispositivo de entrada"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite que la aplicación modifique los parámetros de calibración de la pantalla táctil. No debe ser necesario para las aplicaciones normales."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"acceder a certificados DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permite que una aplicación proporcione y utilice certificados DRM. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Establecimiento de reglas de contraseña"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas de bloqueo de pantalla"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Control de intentos de bloqueo de pantalla"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permite que una aplicación acceda al almacenamiento seguro de bloqueos."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Controlar cuándo se muestra y se oculta el bloqueo"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite que una aplicación controle los bloqueos."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Detectar cambios en el estado de confianza."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que una aplicación detecte cambios en el estado de confianza."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Enlazar con un servicio de agente de confianza"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite a una aplicación enlazar con un servicio de agente de confianza."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interactuar con el sistema de recuperación y las actualizaciones"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Permite que una aplicación interactúe con el sistema de recuperación y las actualizaciones del sistema."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toca dos veces para acceder al control de zoom."</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fondo de pantalla"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Detector de notificaciones"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Proveedor de condiciones"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN activada por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 1c3d94a..f16381c 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> päeva"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> päev <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> päev <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> h"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
<string name="untitled" msgid="4638956954852782576">"<Pealkirjata>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥."</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sünkroonimine"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Liiga palju üksuse <xliff:g id="CONTENT_TYPE">%s</xliff:g> kustutusi."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tahvelarvuti mäluruum on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Kella talletusruum on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefonimälu on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Võrku võidakse jälgida"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Tundmatu kolmas osapool:"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Helin on sees"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Väljalülitamine ..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Teie tahvelarvuti lülitub välja."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Teie kell lülitub välja."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Teie telefon lülitub välja."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Kas soovite välja lülitada?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Ohutus režiimis taaskäivitamine"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lennurežiim"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lennurežiim on SEES"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lennurežiim on VÄLJAS"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Seaded"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Tasulised teenused"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Tasuliste toimingute tegemine."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Teie sõnumid"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"otseteede desinstallimine"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Lubab rakendusel eemaldada avaekraani otseteid ilma kasutaja sekkumiseta."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"marsruutige väljuvad kõned uuesti"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Lubab rakendusel näha, mis number valitakse väljahelistamisel, ning laseb suunata kõne teisele numbrile või selle üldse katkestada."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Võimaldab rakendusel töödelda väljuvaid kõnesid ja muuta valitavat numbrit. Luba võimaldab rakendusel jälgida, ümber suunata või takistada väljuvaid kõnesid."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"võtke vastu tekstisõnumeid (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Võimaldab rakendusel vastu võtta ja töödelda SMS-sõnumeid. See tähendab, et rakendus võib jälgida või kustutada teie seadmele saadetud sõnumeid neid teile näitamata."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"võtke vastu tekstisõnumeid (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Võimaldab rakendusel kätte saada aktiivse akna sisu. Pahatahtlikud rakendused võivad hankida kogu akna sisu ja uurida kogu selle teksti, välja arvatud paroole."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"ajutine hõlbustuse lubamine"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Lubab rakendusel ajutiselt lubada seadmes hõlbustuse. Pahatahtlikud rakendused võivad lubada hõlbustuse kasutaja nõusolekuta."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"aknaloa toomine"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Lubab rakendusel tuua aknaloa. Pahatahtlikud rakendused võivad jäljendada süsteemi ja suhelda rakenduse aknaga ilma loata."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"raamistatistika toomine"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Lubab rakendusel koguda raamistatistikat. Pahatahtlikud rakendused võivad jälgida teiste rakenduste akende raamistatistikat."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"hangi akna teave"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Võimaldab rakendusel hankida teavet aknahalduri akende kohta. Pahatahtlikud rakendused võivad hankida teavet, mis on mõeldud süsteemisiseseks kasutamiseks."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtreeri sündmused"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Võimaldab rakendusel registreerida sisestusfiltri, mis filtreerib kõigi kasutaja sündmuste voo, enne kui need ära saadetakse. Pahatahtlik rakendus võib süsteemi kasutajaliidest juhtida ilma kasutaja sekkumiseta."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"kuva suurendamine"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Lubab rakendusel ekraani sisu suurendada. Pahatahtlikud rakendused võivad muundada kuva sisu nii, et seade muutub ebastabiilseks."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"osaline väljalülitamine"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Lülitab tegevushalduri väljalülitusolekusse. Ei lülita lõplikult välja."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"väldi rakenduste ümberlülitamist"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Võimaldab rakendusel edastada teatise SMS-sõnumi vastuvõtmise kohta. Pahatahtlikud rakendused võivad seda kasutada sissetulevate SMS-sõnumite võltsimiseks."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"saada WAP-PUSH-vastuvõetud saateid"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Võimaldab rakendusel edastada teatise WAP PUSH-sõnumi vastuvõtmise kohta. Pahatahtlikud rakendused võivad seda kasutada MMS-sõnumite vastuvõtmise võltsimiseks või mis tahes veebilehe sisu salaja asendamiseks pahatahtlikuga."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"võrkude levi hinnangu saatmine"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Lubab rakendusel levitada märguannet, et võrke tuleb hinnata. Seda ei ole kunagi vaja tavapäraste rakenduste puhul."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"piira töötavate protsesside arvu"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Võimaldab rakendusel juhtida töötavate protsesside maksimaalset arvu. Tavarakenduste puhul pole seda vaja."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"sundige taustarakendused sulguma"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Võimaldab omanikul siduda VPN-teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"taustapildiga sidumine"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lubab omanikul siduda taustapildi ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"seo häälinteraktsiooniga"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Lubab omanikul siduda häälinteraktsiooni teenuse ülataseme liidesega. Pole kunagi vajalik tavaliste rakenduste puhul."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"kaugekraaniga sidumine"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lubab omanikul siduda rakenduse kaugekraani ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vidinateenusega sidumine"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lubab omanikul siduda vidina teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"sidumine marsruudi pakkumisteenusega"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Lubab õiguste omajal luua seosed kõikide registreeritud marsruutide pakkujatega. Pole kunagi vajalik tavaliste rakenduste korral."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"seadme administraatoriga suhtlemine"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Võimaldab omanikul saata kavatsusi seadme administraatorile. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"sidumine TV-sisendiga"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Võimaldab rakendusel taasesituseks kasutada mis tahes installitud meediumidekooderit."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"usaldusväärsete mandaatide haldamine"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lubab rakendusel installida ja desinstallida usaldusväärsete mandaatidena CA-sertifikaate."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"rakenduse käitamine tegevusetul ajal"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"See luba võimaldab Android-süsteemil käitada rakendust taustal siis, kui seadet ei kasutata."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"sidumine tegevusetute teenustega"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"See luba võimaldab Androidi süsteemil siduda end rakenduse tegevusetute teenustega."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"loe/kirjuta valija allikaid"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Võimaldab rakendusel lugeda valimisrühma mis tahes ressurssi ja sellesse kirjutada (näiteks kaustas /dev olevad failid). See võib mõjutada süsteemi stabiilsust ja turvet. Seda tohiks kasutada tootja või operaator AINULT riistvaraspetsiifiliseks diagnostikaks."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"Rakenduse komponentide lubamine või keelamine"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Võimaldab rakendusel lugeda seadmesse salvestatud isiklikku profiiliteavet, näiteks teie nime ja kontaktteavet. See tähendab, et rakendus saab teid tuvastada ja saata teie profiiliteavet teistele."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"muutke oma kontaktikaarti"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Võimaldab rakendusel muuta või lisada seadmesse salvestatud isiklikku profiiliteavet, näiteks teie nime ja kontaktteavet. See tähendab, et rakendus saab teid tuvastada ja saata teie profiiliteavet teistele."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"kehaandurid (nt pulsilugeja)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Lubab rakendusel saada juurdepääsu selliste andurite andmetele, mida kasutate kehas toimuva (nt pulsi) mõõtmiseks."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"Sotsiaalvoo lugemine"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Annab rakendusele juurdepääsu ja võimaldab sünkroonida teie ja teie sõprade sotsiaalseid värskendusi. Olge teabe jagamisel ettevaatlik – see võimaldab rakendusel lugeda teie suhtlusi sõpradega suhtlusvõrgustikes konfidentsiaalsusest hoolimata. Märkus: see luba ei pruugi jõustuda kõigis suhtlusvõrgustikes."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"Sotsiaalvoogu kirjutamine"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Võimaldab rakendusel juhtida seadme telefonifunktsioone. Selle loaga rakendus saab vahetada võrke, lülitada telefoniraadiot sisse ja välja ning teha muudki ilma teid teavitamata."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lugege telefoni olekut ja identiteeti"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Annab rakendusele juurdepääsu seadme telefonifunktsioonidele. See luba võimaldab rakendusel määrata telefoninumbri ja seadme ID-d ning kontrollida, kas kõne on aktiivne ja kaugnumber on kõne kaudu telefoniga ühendatud."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"telefoni täpsete olekute lugemine"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Lubab rakendusel hankida juurdepääsu telefoni täpsetele olekutele. Selle loa korral saab rakendus tuvastada kõne tõelise oleku, kas kõne on aktiivne või taustal, kõnede ebaõnnestumised, täpse andmesideühenduse oleku ja andmesideühenduse ebaõnnestumised."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"tahvelarvuti uinumise vältimine"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"väldi telefoni uinumist"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Võimaldab rakendusel vältida tahvelarvuti uinumist."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX-i oleku muutmine"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Võimaldab rakendusel luua ja katkestada tahvelarvuti ühenduse WiMAX-i võrkudega."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Võimaldab rakendusel luua ja katkestada telefoni ühenduse WiMAX-i võrkudega."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"võrkude hindamine"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Lubab rakendusel võrke hinnata ja mõjutada seda, milliseid võrke peaks tahvelarvuti eelistama."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Lubab rakendusel võrke hinnata ja mõjutada seda, milliseid võrke peaks telefon eelistama."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"siduge Bluetoothi seadmetega"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Võimaldab rakendusel vaadata tahvelarvuti Bluetooth-konfiguratsiooni ning luua ja heaks kiita ühendusi seotud seadmetega."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Võimaldab rakendusel vaadata telefoni Bluetooth-konfiguratsiooni ning luua ja heaks kiita ühendusi seotud seadmetega."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Võimaldab rakendusel tuua, kontrollida ja kustutada märguandeid, sh neid, mille on postitanud teised rakendused."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"seo märguannete kuulamisteenusega"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Võimaldab omanikul siduda märguannete kuulamisteenuse ülemise taseme kasutajaliidese. Seda ei tohiks tavarakenduste puhul kunagi vaja olla."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"seo tingimuse pakkuja teenusega"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Lubab omanikul siduda tingimuse pakkuja teenuse ülataseme liidesega. Pole kunagi vajalik tavaliste rakenduste puhul."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"operaatoripoolse konfiguratsioonirakenduse aktiveerimine"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lubab omanikul aktiveerida operaatoripoolse konfiguratsioonirakenduse. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"võrgutingimuste teabe kuulamine"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Lubab rakendusel kuulata võrgutingimuste teavet. Ei ole kunagi vajalik tavaliste rakenduste puhul."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"sisendseadme kalibreerimise muutmine"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Lubab rakendusel muuta puuteekraani kalibreerimisparameetreid. Ei tohiks kunagi olla vajalik tavaliste rakenduste puhul."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"juurdepääs DRM-i sertifikaatidele"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Lubab rakendusel ette valmistada ja kasutada DRM-i sertifikaate. Tavarakenduste puhul ei tohiks see vajalik olla."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Parooli reeglite määramine"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrollige ekraaniluku avamise paroolide pikkust ja tähemärke."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Ekraani avamiskatsed"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Lubab rakendusel hankida juurdepääsu võtmekaitsega turvalisele talletusruumile."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Võtmekaitse kuvamise ja peitmise juhtimine"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Lubab rakendusel võtmekaitset juhtida."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Usaldusväärse oleku muudatuste tuvastamine."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Lubab rakendusel tuvastada muudatusi usaldusväärses olekus."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Usaldusväärse agendi teenusega sidumine"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Lubab rakendusel ennast siduda usaldusväärse agendi teenusega."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Suhtlemine värskenduse ja taastesüsteemiga"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Lubab rakendusel suhelda taastesüsteemi ja süsteemivärskendustega."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Suumi juhtimiseks puudutage kaks korda"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Taustapilt"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Muutke taustapilti"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Märguannete kuulamisteenus"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Tingimuse pakkuja"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN on aktiveeritud"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN-i aktiveeris <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Võrgu haldamiseks puudutage."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 66b4a90..34ee392 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"ترابایت"</string>
<string name="petabyteShort" msgid="5637816680144990219">"پتابایت"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> روز"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> روز و <xliff:g id="HOURS">%2$d</xliff:g> ساعت"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> روز و <xliff:g id="HOURS">%2$d</xliff:g> ساعت"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> ساعت"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> ساعت و <xliff:g id="MINUTES">%2$d</xliff:g> دقیقه"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> ساعت و <xliff:g id="MINUTES">%2$d</xliff:g> دقیقه"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> دقیقه"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> دقیقه و <xliff:g id="SECONDS">%2$d</xliff:g> ثانیه"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> دقیقه و <xliff:g id="SECONDS">%2$d</xliff:g> ثانیه"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> ثانیه"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> ثانیه"</string>
<string name="untitled" msgid="4638956954852782576">"<بدون عنوان>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"همگامسازی"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"تعداد موارد حذف شده <xliff:g id="CONTENT_TYPE">%s</xliff:g> بسیار زیاد است."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"حافظه رایانهٔ لوحی پر است! برخی از فایلها را حذف کنید تا فضا آزاد شود."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"حافظه ساعت پر است. برای آزادسازی فضا، چند فایل را حذف کنید."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"حافظه تلفن پر است. بعضی از فایلها را حذف کنید تا فضا آزاد شود."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ممکن است شبکه نظارت شده باشد"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"توسط یک شخص ثالث ناشناس"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"زنگ روشن"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"در حال خاموش شدن…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"رایانهٔ لوحی شما خاموش میشود."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"ساعت شما خاموش میشود."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"گوشی شما خاموش میشود."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"آیا میخواهید تلفن خاموش شود؟"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"راهاندازی مجدد در حالت امن"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"حالت هواپیما"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"حالت هواپیما روشن است"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"حالت هواپیما خاموش است"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"تنظیمات"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"بیشتر از 999"</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="permgrouplab_costMoney" msgid="5429808217861460401">"سرویسهای غیر رایگان"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"انجام کارهایی که برای شما هزینه دارد."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"پیامهای شما"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"حذف نصب میانبرها"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"به برنامه اجازه میدهد میانبرهای صفحه اصلی را بدون دخالت کاربر حذف کند."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"ترسیم مجدد مسیر تماسهای خروجی"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"به برنامه اجازه میدهد عددی را که در طی یک تماس خروجی شمارهگیری شده، ببیند و این اختیار را دارد که تماس را به شماره دیگری هدایت کند یا کلاً تماس را قطع کند."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"به برنامه اجازه میدهد تماسهای خروجی را پردازش کند و شمارههایی که باید گرفته شوند را تغییر دهد. این مجوز به برنامه امکان میدهد به کنترل، هدایت مجدد یا جلوگیری از تماسهای خروجی بپردازد."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"دریافت پیامهای نوشتاری (پیامک)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"به برنامه اجازه میدهد پیامکها را دریافت و پردازش کند. این یعنی برنامه میتواند پیامهای ارسالی به دستگاه شما را بدون نمایش آنها به شما حذف یا کنترل کند."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"دریافت پیامهای نوشتاری (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"به برنامه اجازه میدهد تا محتوای پنجره فعال را بازیابی کند. برنامههای مخرب میتوانند کل محتوای پنجره را بازیابی کنند و همه متن آنرا به غیر از گذرواژهها امتحان کنند."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"قابلیت دسترسی به طور موقت فعال شود"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"به یک برنامه اجازه میدهد به صورت موقت قابلیت دسترسی را در دستگاه فعال کند. برنامههای مخرب میتوانند قابلیت دسترسی را بدون رضایت کاربر فعال کنند."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"بازیابی کد پنجره"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"به یک برنامه کاربردی اجازه میدهد کد پنجره را بازیابی کند. برنامههای مخرب ممکن است با جعل کردن سیستم، تعامل غیرمجازی با پنجره برنامه انجام دهند."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"بازیابی آمار قابها"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"به یک برنامه کاربردی اجازه میدهد آمار قابها را جمعآوری کند. برنامههای مخرب ممکن است از برنامههای دیگر آمار قابهای مربوط به پنجرهها را مشاهده کنند."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"بازیابی اطلاعات پنجره"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"به یک برنامه کاربردی اجازه میدهد که اطلاعات مربوط به پنجرهها را از مدیریت پنجره بازیابی کند. برنامههای کاربردی مخرب ممکن است اطلاعاتی که برای استفاده سیستم داخلی درنظر گرفته شدهاند را بازیابی کنند."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"فیلتر کردن رویدادها"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"به یک برنامه کاربردی اجازه میدهد یک فیلتر ورودی را که جریان تمام رویدادهای کاربران را قبل از ارسال شدن فیلتر میکند، ثبت نماید. برنامه کاربردی مخرب ممکن است رابط کاربری سیستم را بدون مداخله کاربر، کنترل کند."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"بزرگ کردن صفحه نمایش"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"به یک برنامه کاربردی اجازه بزرگ کردن محتوای یک صفحه نمایش را میدهد. برنامههای کاربردی مضر میتوانند محتوای صفحه نمایش را به طریقی منتقل کنند که باعث غیرقابلاستفاده شدن دستگاه شود."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"خاموش شدن جزئی"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"مدیر فعالیت را در حالت خاموشی قرار میدهد. خاموشی را به صورت کامل انجام نمیدهد."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ممانعت از جابجایی برنامه"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"به برنامه اجازه میدهد تا اعلان دریافت پیام کوتاه را پخش کند. برنامههای مخرب میتوانند از این برای جعل پیامهای کوتاه ورودی استفاده کنند."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ارسال پخش دریافت شده توسط WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"به برنامه اجازه میدهد تا اعلانی را پخش کند که پیام WAP PUSH دریافت کرده است. برنامههای مخرب میتوانند از آن استفاده کنند تا دریافت پیام MMS را جعل کنند یا محتوای هر صفحهٔ وب را با انواع مخرب جایگزین کنند."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ارسال اعلان پخش برای امتیازبندی شبکهها"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"به برنامه اجازه میدهد تا اعلانی پخش کند که شبکهها باید امتیازبندی شوند. هرگز برای برنامههای عادی مورد نیاز نیست."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"محدود کردن تعداد فرآیندهای در حال اجرا"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"به برنامه اجازه میدهد تا حداکثر تعداد پردازشهایی را که اجرا خواهد شد کنترل کند. هرگز برای برنامههای عادی لازم نیست."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"بستن اجباری برنامههای پسزمینه"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"به دارنده اجازه میدهد که به رابط سطح بالای سرویس Vpn متصل شود. هرگز برای برنامههای معمولی مورد نیاز نیست."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"پیوند شده به تصویر زمینه"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"به دارنده اجازه میدهد تا به رابط سطح بالای تصویر زمینه متصل شود. برنامههای معمولی هرگز به این ویژگی نیاز ندارند."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"مقید بودن به سرویس تعامل صوتی"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"به دارنده امکان میدهد به واسط سطح بالای سرویس تعامل صوتی مقید باشد. برای برنامههای عادی هرگز نباید لازم باشد."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"اتصال به نمایشگر راه دور"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"به دارنده امکان میدهد تا به رابط سطح بالای نمایشگر راه دور وصل شود. نباید هرگز برای برنامههای عادی لازم باشد."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"اتصال به یک سرویس ابزارک"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"به دارنده اجازه میدهد که به رابط سطح بالای سرویس ابزارک متصل شود. هرگز برای برنامههای معمولی مورد نیاز نیست."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"اتصال به یک سرویس ارائهدهنده مسیر"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"به دارنده امکان میدهد به هر ارائهدهنده مسیر ثبت شدهای متصل شود. هرگز برای برنامههای عادی مورد نیاز نیست."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"تعامل با یک سرپرست دستگاه"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"به دارنده اجازه میدهد اهداف خود را به سرپرست دستگاه ارسال کند. برنامههای معمولی هیچگاه به این ویژگی نیازی ندارند."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"اتصال به ورودی تلویزیون"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"به برنامه امکان میدهد که به رابط سطح بالای ورودی تلویزیون متصل شود. هرگز برای برنامههای معمولی مورد نیاز نیست."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"اضافه یا حذف سرپرست دستگاه"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"به دارنده اجازه میدهد سرپرستان دستگاه فعال را اضافه یا حذف کند.هرگز نباید برای برنامههای عادی مورد نیاز باشد."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"تغییر جهت صفحه"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"اجازه میدهد برنامه از هر رمزگشای رسانه نصب شدهای استفاده کند تا برای پخش رمزگشایی شود."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"مدیریت اطلاعات کاربری مورد اعتماد"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"به برنامه امکان میدهد گواهینامههای CA را به عنوان اطلاعات کاربری مورد اعتماد نصب یا حذف نصب کند."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"اجرای برنامه در هنگام بدون فعالیت بودن دستگاه"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"این مجوز به سیستم Android امکان میدهد تا وقتی دستگاه استفاده نمیشود برنامه را در پسزمینه اجرا کند."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"اتصال با سرویسهای غیرفعال"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"این مجوز به سیستم Android امکان میدهد به سرویسهای غیرفعال یک برنامه متصل شود."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"خواندن/نوشتن منابع متعلق به تشخیص"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"به برنامه اجازه میدهد هر منبعی را که متعلق به گروه تشخیص است بخواند و در آن بنویسد؛ بهعنوان مثال، فایلهای /dev. این امر بهصورت بالقوه میتواند بر پایدار بودن و امنیت سیستم تأثیر بگذارد. این تنها باید برای تشخیصهای مختص سختافزار توسط تولیدکننده یا اپراتور استفاده شود."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"فعال یا غیر فعال کردن اجزای برنامه"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"به برنامه اجازه میدهد اطلاعات نمایه شخصی ذخیره شده در دستگاه شما، مانند نام و اطلاعات تماس شما را بخواند. یعنی برنامه میتواند شما را شناسایی کند و ممکن است اطلاعات نمایهٔ شما را به دیگران ارسال کند."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"اصلاح کارت تماس شما"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"به برنامه اجازه میدهد تا اطلاعات نمایه شخصی ذخیره شده در دستگاه شما، مانند نام و اطلاعات تماس شما را تغییر دهد یا اضافه کند. یعنی برنامه میتواند شما را شناسایی کند و ممکن است اطلاعات نمایهٔ شما را برای دیگران ارسال کند."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"حسگرهای بدن (مانند پایشگرهای ضربان قلب)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"به برنامه امکان میدهد به اطلاعات حسگرهایی که استفاده میکنید، دسترسی پیدا کند تا اندازهگیریهای مربوط به آنچه که درون بدنتان رخ میدهد، مانند ضربان قلب، را انجام دهد."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"خواندن جریان اجتماعی شما"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"به برنامه اجازه میدهد به بهروزرسانیهای اجتماعی از طرف شما و دوستان شما دسترسی پیدا کرده و آنها را همگامسازی کند. دقت کنید که هنگام اشتراکگذاری -- این ویژگی به برنامه اجازه میدهد ارتباطات بین شما و دوستان شما را در شبکههای اجتماعی، صرفنظر از محرمانه بودن آنها بخواند. توجه: این مجوز ممکن است در همه شبکههای اجتماعی اجرا نشود."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"نوشتن در جریان اجتماعی شما"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"به برنامه اجازه میدهد ویژگیهای دستگاه را کنترل کند. برنامهای که این مجوز را دارد میتواند بدون اطلاع شما تعویض شبکه داشته باشد، رادیوی تلفن را روشن یا خاموش کند و کارهایی از این قبیل را انجام دهد."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"خواندن وضعیت تلفن و شناسه"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"به برنامه اجازه میدهد به ویژگیهای تلفن دستگاه شما دسترسی پیدا کند. این مجوز به برنامه اجازه میدهد شماره تلفن و شناسههای دستگاه، فعال بودن یک تماس و شماره راه دوری که با یک تماس متصل شده است را مشخص کند."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"خواندن وضعیتهای دقیق تلفن"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"به برنامه امکان میدهد به وضعیتهای دقیق تلفن دسترسی داشته باشد. این مجوز به برنامه امکان میدهد وضعیت واقعی تماس، اینکه آیا تماس فعال است یا در پسزمینه قرار دارد، تماسهای ناموفق، وضعیت دقیق اتصال داده و اتصالهای ناموفق داده را تعیین کند."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ممانعت از به خواب رفتن رایانهٔ لوحی"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ممانعت از به خواب رفتن تلفن"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"به برنامه اجازه میدهد تا از غیرفعال شدن رایانهٔ لوحی جلوگیری کند."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"تغییر وضعیت WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"به برنامه امکان میدهد رایانهٔ لوحی را به شبکههای وایمکس متصل کرده یا اتصال آن را از این شبکهها قطع کند."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"به برنامه امکان میدهد تا تلفن را به شبکههای وایمکس متصل کرده یا اتصال آنرا از این شبکهها قطع کند."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"امتیازبندی شبکهها"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"به برنامه اجازه میدهد که شبکهها را درجهبندی کند و روی اینکه رایانه لوحی باید کدام شبکه را در اولویت قرار دهد تأثیر میگذارد."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"به برنامه اجازه میدهد که شبکهها را درجهبندی کند و روی اینکه تلفن باید کدام شبکه را در اولویت قرار دهد تأثیر میگذارد."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"جفت کردن با دستگاههای بلوتوث"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"به برنامه اجازه میدهد تا پیکربندی بلوتوث در رایانهٔ لوحی را مشاهده کند و اتصال با دستگاههای مرتبط را برقرار کرده و بپذیرد."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"به برنامه اجازه میدهد تا پیکربندی بلوتوث در تلفن را مشاهده کند، و اتصالات دستگاههای مرتبط را برقرار کرده و بپذیرد."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه میدهد به بازیابی، بررسی و پاک کردن اعلانها از جمله موارد پست شده توسط سایر برنامهها بپردازد."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"اتصال به یک سرویس شنونده اعلان"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"به دارنده اجازه میدهد به یک رابط سطح بالای سرویس شنونده اعلان متصل شود. هرگز نباید برای برنامههای عادی لازم شود."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"مقید بودن به سرویس ارائهدهنده وضعیت"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"به دارنده امکان میدهد تا به واسط سطح بالای سرویس ارائهدهنده وضعیت مقید باشد. برای برنامههای عادی هرگز نباید لازم باشد."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"لغو برنامه پیکربندی ارائه شده توسط شرکت مخابراتی"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"به دارنده اجازه میدهد که تنظیمات برنامه شرکت مخابراتی را لغو کند. هرگز برای برنامههای معمولی مورد نیاز نیست."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"گوش دادن برای بررسی شرایط شبکه"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"به برنامه امکان میدهد برای بررسی شرایط شبکه گوش دهد. این امکان هرگز نباید برای برنامههای معمولی مورد نیاز باشد."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"تغییر کالیبراسیون دستگاه ورودی"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"به برنامه امکان میدهد پارامترهای کالیبراسیون صفحه لمسی را تغییر دهد. هرگز نباید برای برنامههای عادی مورد نیاز باشد."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"دسترسی به گواهیهای DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"به یک برنامه کاربردی اجازه ارائه مجوز و استفاده از گواهیهای DRM را میدهد. هرگز برای برنامههای عادی مورد نیاز نیست."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین رمز ورود"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"طول و نویسههای مجاز در گذرواژههای بازکردن قفل صفحه را کنترل کنید."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"نمایش تلاشهای قفل گشایی صفحه"</string>
@@ -741,7 +704,7 @@
<string name="policylab_expirePassword" msgid="885279151847254056">"تنظیم زمان انقضای رمز ورود قفل صفحه"</string>
<string name="policydesc_expirePassword" msgid="1729725226314691591">"کنترل کنید چند وقت یک بار باید گذرواژه صفحه قفل عوض شود."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"تنظیم رمزگذاری حافظه"</string>
- <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"اطلاعات ذخیره شده برنامه باید رمزگذاری شود."</string>
+ <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"باید اطلاعات ذخیره شده برنامه رمزگذاری شود."</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"غیر فعال کردن دوربین ها"</string>
<string name="policydesc_disableCamera" msgid="2306349042834754597">"جلوگیری از استفاده از همه دوربینهای دستگاه."</string>
<string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"غیرفعال کردن ویژگیها در محافظ کلید"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"به یک برنامه کاربردی برای دسترسی به فضای ذخیرهسازی ایمن محافظ کلید اجازه میدهد."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"کنترل نمایش و پنهان کردن محافظ کلید"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"اجازه میدهد برنامهای محافظ کلید را کنترل کند."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"گوش دادن به تغییرات وضعیت trust."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"به یک برنامه کاربردی برای گوش دادن به تغییرات در trust اجازه میدهد."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"اتصال به یک سرویس trust agent"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"به یک برنامه کاربردی برای اتصال به یک سرویس trust agent اجازه میدهد."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"تعامل با سیستم بهروزرسانی و بازیابی"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"به یک برنامه کاربردی اجازه میدهد با سیستم بازیابی و بهروزرسانیهای سیستم تعامل داشته باشد."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"دوبار لمس کنید تا بزرگنمایی کنترل شود"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"تصویر زمینه"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"تغییر تصویر زمینه"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"شنونده اعلان"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ارائهدهنده وضعیت"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN فعال شد"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN توسط <xliff:g id="APP">%s</xliff:g> فعال شده است"</string>
<string name="vpn_text" msgid="3011306607126450322">"برای مدیریت شبکه لمس کنید."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index eb2540d..01f37d5 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"Tt"</string>
<string name="petabyteShort" msgid="5637816680144990219">"Pt"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> päivää"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> päivä <xliff:g id="HOURS">%2$d</xliff:g> t"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> päivä <xliff:g id="HOURS">%2$d</xliff:g> t"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> t"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> t <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> t <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
<string name="untitled" msgid="4638956954852782576">"<Nimetön>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkronointi"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Liikaa <xliff:g id="CONTENT_TYPE">%s</xliff:g>-poistoja."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet-laitteen tallennustila on täynnä. Vapauta tilaa poistamalla tiedostoja."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Kellon tallennustila on täynnä. Vapauta tilaa poistamalla tiedostoja."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Puhelimen tallennustila on täynnä. Vapauta tilaa poistamalla tiedostoja."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Verkkoa saatetaan valvoa"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Valvoja on tuntematon kolmas osapuoli."</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Soittoääni: normaali"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Suljetaan..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablet-laitteesi sammutetaan."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Kello sammutetaan."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Puhelin suljetaan."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Haluatko sammuttaa?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Käynnistä vikasietotilassa"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lentokonetila"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lentokonetila on KÄYTÖSSÄ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lentokonetila on POIS KÄYTÖSTÄ"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Asetukset"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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ökohtainen"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Työ"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Maksulliset palvelut"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Suorita mahdollisesti maksullisia toimintoja."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Omat viestit"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"poista pikakuvakkeita"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Antaa sovelluksen poistaa aloitusruudun pikakuvakkeita ilman käyttäjän toimia."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"ohjaa uudelleen lähtevät puhelut"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Sallii sovelluksen nähdä numeron, joka valitaan lähtevää puhelua soitettaessa, ja antaa mahdollisuuden ohjata puhelun eri numeroon tai keskeyttää puhelun kokonaan."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Antaa sovelluksen käsitellä lähteviä puheluita ja muuttaa kohdenumeroita. Sovellus voi valvoa, uudelleenohjata tai estää lähteviä puheluita."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"vastaanota tekstiviestejä (teksti)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Antaa sovelluksen vastaanottaa ja käsitellä tekstiviestejä. Sovellus voi valvoa tai poistaa laitteeseesi lähetettyjä viestejä näyttämättä niitä sinulle."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"vastaanota tekstiviestejä (multimedia)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Antaa sovelluksen noutaa aktiivisen ikkunan sisällön. Haitalliset sovellukset voivat noutaa koko ikkunan sisällön ja tarkastella sen kaikkea tekstiä lukuun ottamatta salasanoja."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"ota esteettömyystila käyttöön väliaikaisesti"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Antaa sovelluksen ottaa esteettömyystilan käyttöön laitteessa väliaikaisesti. Haitalliset sovellukset voivat ottaa esteettömyystilan käyttöön ilman käyttäjän lupaa."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"ikkunan tunnisteen noutaminen"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Antaa sovelluksen noutaa ikkunan tunnisteen. Haitalliset sovellukset saattavat käyttää sovelluksen ikkunaa luvattomasti esiintymällä järjestelmänä."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"kehystilastojen noutaminen"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Antaa sovelluksen kerätä kehystilastoja. Haitalliset sovellukset saattavat tarkkailla toisten sovellusten ikkunoiden kehystilastoja."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"nouda ikkunoiden tietoja"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Antaa sovelluksen noutaa ikkunoiden tietoja ikkunanhallinnasta. Haitalliset sovellukset voivat noutaa tietoja, jotka on tarkoitettu järjestelmän sisäiseen käyttöön."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"suodata tapahtumat"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Antaa sovelluksen rekisteröidä syöttösuodattimen, joka suodattaa kaikkien käyttäjätapahtumien streamin ennen tapahtumien näyttämistä. Haitalliset sovellukset voivat hallita järjestelmän käyttöliittymää ilman käyttäjän lupaa."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"suurenna ruutu"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Antaa sovelluksen suurentaa ruudun sisällön. Haitalliset sovellukset voivat muuttaa näytettävää sisältöä siten, ettei laitetta enää voi käyttää."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"sulje puhelin osittain"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Asettaa toimintojen hallinnan sulkeutumistilaan. Ei sulje puhelinta kokonaan."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"estä sovellusten vaihto"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Sallii sovelluksen lähettää ilmoituksen tekstiviestin vastaanotosta. Haitalliset sovellukset voivat käyttää tätä saapuvien tekstiviestien väärentämiseen."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"lähetä WAP-PUSH-vastaanotettu lähetys"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Antaa sovelluksen lähettää ilmoituksen WAP PUSH -viestin vastaanotosta. Haitalliset sovellukset voivat käyttää tätä MMS-viestien vastaanoton väärentämiseen tai sivujen sisällön korvaamiseen huomaamattomasti haitallisella sisällöllä."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"lähetä verkkojen pisteet"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Sallii sovelluksen lähettää ilmoituksen verkon pisteytystarpeesta. Ei tarvita tavallisissa sovelluksissa."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"rajoita käynnissä olevien prosessien määrää"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Antaa sovelluksen hallita suoritettavien sovellusten enimmäismäärää. Ei tavallisten sovellusten käyttöön."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"pakota taustasovelluksia sulkeutumaan"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Antaa sovelluksen sitoutua VPN-palvelun ylemmän tason käyttöliittymään. Ei tavallisten sovellusten käyttöön."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"sido taustakuvaan"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Antaa sovelluksen sitoutua taustakuvan ylätason käyttöliittymään. Ei tavallisten sovellusten käyttöön."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"puheohjauspalveluun sitominen"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Antaa sovelluksen luoda sidoksen puheohjauspalvelun ylätason rajapintaan. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"etänäyttöön sitoutuminen"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Antaa sovelluksen sitoutua etänäytön ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sitoudu widget-palveluun"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Antaa sovelluksen sitoutua widget-palvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"reitin tarjoajan palveluun sitominen"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Antaa sovelluksen luoda sidoksen mihin tahansa rekisteröityyn reitin tarjoajaan. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikoi laitteen järjestelmänvalvojan kanssa"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Antaa sovelluksen lähettää aikomuksia laitteen järjestelmänvalvojalle. Ei tavallisten sovellusten käyttöön."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"sido TV-tuloon"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Antaa sovelluksen sitoutua TV-tulon ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"lisää tai poista laitteen järjestelmänvalvoja"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Haltija voi lisätä tai poistaa aktiivisen laitteen järjestelmänvalvojia. Tätä ei pitäisi tarvita tavallisille sovelluksille."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"muuta näytön suuntaa"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Sallii sovelluksen käyttää mitä tahansa asennettua tietovälineen koodin purkajaa toistoa varten."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"hallinnoi luotettavia varmenteita"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Antaa sovellukselle luvan asentaa ja poistaa luotettavia CA-varmenteita."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"suorita sovellus laitteen ollessa käyttämättömänä"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Tämä oikeus sallii Android-järjestelmän siirtää sovelluksen suorituksen taustalle, kun laite ei ole käytössä."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"sido käyttämättömiin palveluihin"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Tämä käyttöoikeus antaa Android-järjestelmän sitoa sovelluksen käyttämättömiä palveluita."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lue diag:in omistamia resursseja / kirjoita resursseihin"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Antaa sovelluksen lukea ja kirjoittaa diag-ryhmän omistamiin resursseihin, esimerkiksi /dev-hakemistossa oleviin tiedostoihin. Tämä voi vaikuttaa järjestelmän vakauteen ja turvallisuuteen. Tämä lupa tulee myöntää VAIN valmistajan tai operaattorin laitteistotesteille."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"sovelluskomponenttien ottaminen käyttöön tai pois käytöstä"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Antaa sovelluksen lukea laitteelle tallennettuja henkilökohtaisia tietoja, kuten nimen ja yhteystietoja. Sovellus voi tunnistaa sinut ja lähettää profiilitietojasi muille."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"muokkaa omia yhteystietoja"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Antaa sovelluksen muuttaa laitteelle tallennettuja henkilökohtaisia tietoja, kuten nimeä ja yhteystietoja, tai lisätä niitä. Sovellus voi tunnistaa sinut ja lähettää profiilitietojasi muille."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"kehon anturit (kuten sykemittarit)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Antaa sovelluksen käyttää tietoja antureista, joita käytetään kehon toimintojen kuten sykkeen mittaamiseen."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"lue sosiaalista streamia"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Antaa sovelluksen käyttää ja synkronoida sinun tai kavereidesi päivityksiä sosiaalisista palveluista. Mieti tarkkaan ennen tietojen jakamista: tämän luvan saaneet sovellukset voivat lukea sinun ja kavereidesi välisiä viestejä sosiaalisissa verkkopalveluissa huolimatta viestien arkaluonteisuudesta. Huom: tätä lupaa ei saa ottaa käyttöön kaikissa sosiaalisissa verkkopalveluissa."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"kirjoita sosiaaliseen streamiin"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Antaa sovelluksen hallita laitteen puhelinominaisuuksia. Jos sovelluksella on tämä oikeus, se voi esimerkiksi vaihtaa verkkoa tai ottaa puhelinradion käyttöön tai poistaa sen käytöstä ilmoittamatta käyttäjälle."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lue puhelimen tila ja identiteetti"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Antaa sovelluksen käyttää laitteen puhelinominaisuuksia. Sovellus voi määrittää puhelinnumeron ja laitteen tunnuksen, puhelun tilan sekä soitetun numeron."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"lue puhelimen tarkat tilat"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Antaa sovelluksen käyttää puhelimen tarkkoja tiloja. Tämän oikeus antaa sovelluksen määrittää puhelun todellisen tilan, eli onko puhelu aktiivinen vai taustalla, puhelujen epäonnistumiset, tietoliikenneyhteyden tarkan tilan ja tietoliikenneyhteyden muodostuksen epäonnistumiset."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"estä tablet-laitetta menemästä virransäästötilaan"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"estä puhelinta menemästä virransäästötilaan"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Antaa sovelluksen estää tablet-laitetta siirtymästä virransäästötilaan."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Vaihda WiMAX-verkon tilaa"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Antaa sovelluksen muodostaa tablet-laitteella yhteyden WiMAX-verkkoon ja katkaista yhteyden."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Antaa sovelluksen muodostaa puhelimella yhteyden WiMAX-verkkoon ja katkaista yhteyden."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"pisteytä verkot"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Sallii sovelluksen asettaa verkkoja paremmuusjärjestykseen ja vaikuttaa siihen, mikä verkko tablet-laitteen kannattaa valita."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Sallii sovelluksen asettaa verkkoja paremmuusjärjestykseen ja vaikuttaa siihen, mikä verkko puhelimen kannattaa valita."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"muodosta laitepari Bluetooth-laitteiden kanssa"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Antaa sovelluksen tarkastella tablet-laitteen Bluetooth-asetuksia sekä muodostaa ja hyväksyä laitepariyhteyksiä."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Antaa sovelluksen tarkastella puhelimen Bluetooth-asetuksia sekä muodostaa ja hyväksyä laitepariyhteyksiä muihin laitteisiin."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Antaa sovelluksen noutaa, tutkia ja tyhjentää ilmoituksia (myös muiden sovelluksien lähettämiä)."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"sido ilmoituskuuntelijapalveluun"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Antaa sovelluksen sitoutua ilmoituskuuntelijan ylimmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ehtojen toimituspalveluun sitominen"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Antaa sovelluksen luoda sidoksen ehtojen toimituspalvelun ylätason rajapintaan. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Palveluntarjoajan määrityssovelluksen käynnistäminen"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Antaa luvanhaltijan käynnistää palveluntarjoajan määrityssovelluksen. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"verkon tilahavaintojen kuunteleminen"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Antaa sovellukselle luvan kuunnella verkon tilahavaintoja. Ei tavallisten sovellusten käyttöön."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"Muuttaa syöttölaitteen kalibrointia."</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Antaa sovelluksen muokata kosketusnäytön kalibrointiparametreja. Ei tavallisten sovellusten käyttöön."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM-varmenteiden käyttö"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Antaa sovelluksen käyttää DRM-varmenteita ja hallita niiden käyttäjiä. Ei tavallisten sovellusten käyttöön."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Aseta salasanasäännöt"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Hallinnoi ruudun lukituksenpoistosalasanoissa sallittuja merkkejä ja salasanan pituutta."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Tarkkaile ruudun lukituksen poistoyrityksiä"</string>
@@ -1225,8 +1188,8 @@
<string name="ringtone_picker_title" msgid="3515143939175119094">"Soittoäänet"</string>
<string name="ringtone_unknown" msgid="5477919988701784788">"Tuntematon soittoääni"</string>
<plurals name="wifi_available">
- <item quantity="one" msgid="6654123987418168693">"Wi-Fi-verkko käytettävissä"</item>
- <item quantity="other" msgid="4192424489168397386">"Wi-Fi-verkkoja käytettävissä"</item>
+ <item quantity="one" msgid="6654123987418168693">"Wifi-verkko käytettävissä"</item>
+ <item quantity="other" msgid="4192424489168397386">"Wifi-verkkoja käytettävissä"</item>
</plurals>
<plurals name="wifi_available_detailed">
<item quantity="one" msgid="1634101450343277345">"Avoin wifi-verkko käytettävissä"</item>
@@ -1236,10 +1199,10 @@
<string name="network_available_sign_in" msgid="8495155593358054676">"Kirjaudu verkkoon"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-yhteyden muodostaminen epäonnistui"</string>
+ <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wifi-yhteyden muodostaminen epäonnistui"</string>
<string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" : huono internetyhteys."</string>
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Suora wifi-yhteys"</string>
- <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käynnistä suora wifi-yhteys. Wi-Fi-asiakas/-hotspot poistetaan käytöstä."</string>
+ <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käynnistä suora wifi-yhteys. Wifi-asiakas/-hotspot poistetaan käytöstä."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Suoran wifi-yhteyden käynnistäminen epäonnistui."</string>
<string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct on käytössä"</string>
<string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tarkastele asetuksia koskettamalla"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Sallii sovelluksen käyttää salasanalla suojattua tallennustilaa."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Hallinnoi näppäinvahdin näyttämistä ja piilottamista"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Antaa sovelluksen hallita näppäinvahtia."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Seuraa luottamuksen tilamuutoksia."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Antaa sovelluksen seurata luottamuksen tilamuutoksia."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Luotettavaan tahoon sitoutuminen"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Antaa sovelluksen sitoutua luotettavaan tahoon."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Vuorovaikutus päivitys- ja palautusjärjestelmän kanssa"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Sallii sovelluksen vuorovaikutuksen palautusjärjestelmän ja järjestelmäpäivitysten kanssa."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Ohjaa zoomausta napauttamalla kahdesti"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Taustakuva"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Vaihda taustakuvaa"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Ilmoituskuuntelija"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Ehtojen toimituspalvelu"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN on aktivoitu"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> on aktivoinut VPN-yhteyden"</string>
<string name="vpn_text" msgid="3011306607126450322">"Voit hallinnoida verkkoa koskettamalla."</string>
@@ -1493,12 +1451,12 @@
<string name="data_usage_3g_limit_title" msgid="7093334419518706686">"2G-3G-tiedonsiirto pois käytöstä"</string>
<string name="data_usage_4g_limit_title" msgid="7636489436819470761">"4G-tiedonsiirto pois käytöstä"</string>
<string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"Mobiilitiedonsiirto pois käytöstä"</string>
- <string name="data_usage_wifi_limit_title" msgid="8992154736441284865">"Wi-Fi-tiedonsiirto pois käytöstä"</string>
+ <string name="data_usage_wifi_limit_title" msgid="8992154736441284865">"Wifi-tiedonsiirto pois käytöstä"</string>
<string name="data_usage_limit_body" msgid="3317964706973601386">"Ota käyttöön koskettamalla."</string>
<string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-3G-tiedonsiirtoraja ylitetty"</string>
<string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G-tiedonsiirtoraja ylitetty"</string>
<string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"Mobiilitiedonsiirtoraja ylitetty"</string>
- <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wi-Fi-tiedonsiirtoraja ylitetty"</string>
+ <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wifi-tiedonsiirtoraja ylitetty"</string>
<string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> yli asetetun rajan"</string>
<string name="data_usage_restricted_title" msgid="5965157361036321914">"Rajoitettu taustatietojen käyttö"</string>
<string name="data_usage_restricted_body" msgid="6741521330997452990">"Poista rajoitus koskettamalla."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 276be79..fe29fb8 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"To"</string>
<string name="petabyteShort" msgid="5637816680144990219">"Po"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> jours"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> j et <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> j et <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> h"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h et <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h et <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min et <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min et <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
<string name="untitled" msgid="4638956954852782576">"<Sans_titre>"</string>
<string name="ellipsis" msgid="7899829516048813237">"..."</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchroniser"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"La mémoire de la tablette est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"La mémoire de la montre est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"La mémoire du téléphone est pleine. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Le réseau peut être surveillé"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Par un tiers inconnu"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Sonnerie activée"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Arrêt en cours..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Votre tablette va s\'éteindre."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Votre montre va s\'éteindre."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Votre téléphone va s\'éteindre."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Voulez-vous éteindre l\'appareil?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Redémarrer en mode sans échec"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode Avion"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Le mode Avion est activé."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Le mode Avion est désactivé."</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Paramètres"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Services payants"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Effectuer des opérations payantes"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vos messages"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"désinstaller des raccourcis"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permet à l\'application de supprimer des raccourcis de la page d\'accueil sans intervention de l\'utilisateur."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"transférer les appels sortants"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permet à l\'application de lire le numéro composé lors d\'un appel sortant et lui donne la possibilité de rediriger l\'appel vers un autre numéro ou d\'abandonner l\'appel."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Permet à l\'application de traiter les appels sortants et de modifier le numéro à composer. Cette autorisation lui permet de surveiller, rediriger ou empêcher les appels sortants."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"recevoir des messages texte"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Permet à l\'application de recevoir et de traiter les messages texte. Cette autorisation lui donne la possibilité de surveiller ou de supprimer les messages envoyés à votre appareil sans vous les montrer."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"recevoir des messages multimédias"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permet à l\'application de récupérer le contenu de la fenêtre active. Des applications malveillantes peuvent exploiter cette fonctionnalité pour récupérer et lire la totalité du contenu de la fenêtre, à l\'exception des mots de passe."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"activer temporairement l\'accessibilité"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permet à une application d\'activer temporairement l\'accessibilité sur l\'appareil. Des applications malveillantes peuvent activer l\'accessibilité sans le consentement de l\'utilisateur."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"récupérer les jetons de fenêtre"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Permet à une application de récupérer les jetons de fenêtre. Des applications malveillantes peuvent effectuer des interactions non autorisées avec la fenêtre de l\'application, se faisant passer pour le système."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"récupérer les statistiques de référence"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Permet à une application d\'obtenir des statistiques de référence. Des applications malveillantes peuvent observer les statistiques de référence de fenêtres dans d\'autres applications."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"récupérer les données sur les fenêtres"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permet à une application de récupérer les données sur les fenêtres dans le gestionnaire de fenêtres. Des applications malveillantes peuvent récupérer des données destinées à un usage interne du système."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtrer les événements"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Permet à une application d\'enregistrer un filtre d\'entrée pour filtrer le flux de tous les événements des utilisateurs avant qu\'ils ne soient traités. Des applications malveillantes peuvent contrôler l\'interface utilisateur du système sans l\'intervention de l\'utilisateur."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"agrandir l\'écran"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Permet à une application d\'agrandir le contenu à l\'écran. Les applications malveillantes peuvent transformer ce contenu et rendre l\'appareil inutilisable."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"arrêt partiel"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Place le gestionnaire d\'activités en état d\'arrêt, mais n\'effectue pas d\'arrêt complet."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"empêcher les changements d\'applications"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permet à l\'application d\'envoyer une notification indiquant la réception d\'un message texte. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux messages entrants."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"envoyer une diffusion de réception de WAP par poussée"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permet à l\'application d\'envoyer une notification indiquant la réception d\'un message WAP par poussée. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux messages multimédias entrants ou pour remplacer le contenu d\'une page Web par du contenu malveillant."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"diffuser le classement des réseaux"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Autorise l\'application à diffuser une notification signalant que les réseaux doivent être évalués. Cela n\'est jamais nécessaire pour les applications normales."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"restreindre le nombre de processus en cours d\'exécution"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permet à l\'application de définir le nombre maximal de processus devant s\'exécuter. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forcer la fermeture des applications en arrière-plan"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service RPV. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"se fixer à un fond d\'écran"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un fond d\'écran. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"s\'associer à un service d\'interaction vocale"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'interaction vocale. Ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"lier à un écran distant"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un écran distant. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"s\'associer à un service de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de widget. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"associer à un fournisseur d\'itinéraires enregistré"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permet à l\'application autorisée de s\'associer à des fournisseurs d\'itinéraires enregistrés. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur d\'un périphérique"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet à l\'application autorisée d\'envoyer des intentions à l\'administrateur de l\'appareil. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"s\'associer à une entrée de téléviseur"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'une entrée de téléviseur. Les applications standards ne devraient pas avoir à utiliser cette fonctionnalité."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ajouter ou supprimer un administrateur de l\'appareil"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permet à l\'application d\'ajouter ou de supprimer des administrateurs actifs de l\'appareil. Les applications standards ne devraient jamais utiliser cette autorisation."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"modifier l\'orientation de l\'écran"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet à une application d\'utiliser n\'importe quel décodeur installé pour lire les fichiers multimédias."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gérer les certificats de confiance"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet à l\'application d\'installer et de désinstaller les certificats CA en tant que certificats de confiance."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"exécuter l\'application lorsque l\'appareil est inactif"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Cette autorisation permet au système Android d\'exécuter l\'application en arrière-plan lorsque l\'appareil est inactif."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"lier aux services inactifs"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Cette autorisation permet à la plateforme Android de se lier aux services inactifs d\'une application."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lire ou modifier les ressources appartenant au groupe de diagnostics"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet à l\'application d\'obtenir des droits en lecture et en écriture pour toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers du répertoire /dev). Cela peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou le fournisseur de services."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"activer ou désactiver les composants d\'une application"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Permet à l\'application d\'accéder aux données de profil enregistrées sur votre appareil, comme votre nom et vos coordonnées. L\'application peut alors vous identifier et envoyer les données de votre profil à des tiers."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"modifier votre fiche de contact"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Permet à l\'application de modifier les données de profil enregistrées sur votre appareil, telles que votre nom et vos coordonnées, ou d\'en ajouter. Elle peut alors vous identifier et envoyer vos données de profil à des tiers."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"capteurs corporels (tels que les moniteurs de fréquence cardiaque)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Permet à l\'application d\'accéder aux données des capteurs utilisés pour mesurer des valeurs physiologiques, telles que votre fréquence cardiaque."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"lire les flux de réseaux sociaux"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Permet à l\'application d\'accéder à vos mises à jour sur les réseaux sociaux, ainsi qu\'à celles de vos amis, et de les synchroniser. Soyez prudent lorsque vous partagez de l\'information. Cette autorisation permet à l\'application de lire les communications entre vous et vos amis sur les réseaux sociaux, indépendamment de leur caractère confidentiel. Remarque : Il est possible que cette autorisation ne soit pas appliquée sur tous les réseaux sociaux."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"modifier vos flux de réseaux sociaux"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permet à l\'application de contrôler les fonctionnalités de téléphonie de l\'appareil. Une application disposant de cette autorisation peut, par exemple, basculer d\'un réseau à l\'autre et activer ou désactiver le signal radio du téléphone à votre insu."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"voir l\'état et l\'identité du téléphone"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet à l\'application d\'accéder aux fonctionnalités téléphoniques de l\'appareil. Cette autorisation permet à l\'application de déterminer le numéro de téléphone et les identifiants de l\'appareil, si un appel est actif et le numéro distant connecté par un appel."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"Accéder aux états précis du téléphone"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permet à l\'application d\'accéder aux états précis du téléphone. Cette autorisation lui permet de déterminer le statut d\'appel réel, si un appel est actif ou en arrière-plan, si des appels ont échoué, l\'état précis de la connexion et si cette dernière a échoué."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"empêcher la tablette de passer en mode veille"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"empêcher le téléphone de passer en mode veille"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permet à l\'application d\'empêcher la tablette de passer en mode veille."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Modifier l\'état du WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permet à l\'application de connecter la tablette aux réseaux WiMAX et de l\'en déconnecter."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permet à l\'application de connecter le téléphone aux réseaux WiMAX et de l\'en déconnecter."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"classer les réseaux"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Autorise l\'application à classer les réseaux et à influencer la sélection du réseau par la tablette."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Autorise l\'application à classer les réseaux et à influencer la sélection du réseau par le téléphone."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"s\'associer à des appareils Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permet à l\'application d\'accéder à la configuration du Bluetooth sur la tablette, et d\'établir et accepter des connexions avec les appareils associés."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permet à l\'application d\'accéder à la configuration du Bluetooth sur le téléphone, et d\'établir et accepter des connexions avec les appareils associés."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet aux applications de récupérer, d\'examiner et d\'autoriser les notifications, y compris celles envoyées par d\'autres applications."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications. Ne devrait jamais être nécessaire pour les applications normales."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"s\'associer à un service de fournisseur de conditions"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service de fournisseur de conditions. Ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"faire appel à l\'application de configuration du fournisseur de services"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet à l\'application autorisée de faire appel à l\'application de configuration fournie par le fournisseur de services. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"détecter des observations sur les conditions du réseau"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet à une application de détecter les observations sur les conditions du réseau. Ne devrait jamais être nécessaire pour les applications standards."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"modifier le calibrage du périphérique d\'entrée"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permet à l\'application de modifier les paramètres de calibrage de l\'écran tactile. Ne devrait jamais être nécessaire pour les applications standards."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accéder aux certificats GDN"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permet à une application de fournir et d\'utiliser les certificats de GDN. Cela ne devrait jamais être nécessaire pour les applications normales."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Choisir le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
@@ -1301,11 +1264,11 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Si vous activez la mémoire de stockage USB, certaines applications en cours d\'utilisation vont être fermées et risquent de rester indisponibles jusqu\'à ce que la mémoire de stockage USB soit désactivée."</string>
<string name="dlg_error_title" msgid="7323658469626514207">"Échec du fonctionnement de la mémoire de stockage USB."</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Connecté en tant qu\'app. multimédia"</string>
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Connecté en tant qu\'appareil multimédia"</string>
<string name="usb_ptp_notification_title" msgid="1960817192216064833">"Connecté en tant qu\'appareil photo"</string>
<string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Connecté en tant que programme d\'installation"</string>
<string name="usb_accessory_notification_title" msgid="7848236974087653666">"Connecté à un accessoire USB"</string>
- <string name="usb_notification_message" msgid="2290859399983720271">"Appuyez pour accéder aux autres options USB."</string>
+ <string name="usb_notification_message" msgid="2290859399983720271">"Appuyez ici pour accéder aux autres options USB."</string>
<string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"Formater mémoire?"</string>
<string name="extmedia_format_title" product="default" msgid="3648415921526526069">"Formater la carte SD?"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"Tous les fichiers stockés sur la mémoire de stockage USB vont être effacés. Cette action est irréversible."</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permet à une application d\'accéder au stockage sécurisé keyguard."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Contrôler l\'affichage et le masquage de la protection des touches"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permet à une application de contrôler la protection des touches."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Détecter les modifications de l\'état de confiance"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permet à une application de détecter les modifications de l\'état de confiance."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Lier à un service d\'agent de confiance"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permet à une application de se lier à un service d\'agent de confiance."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interagir avec le système de récupération et de mise à jour"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Permet à une application d\'interagir avec le système de récupération et les mises à jour système."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Appuyer deux fois pour régler le zoom"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fond d\'écran"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Changer de fond d\'écran"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Outil d\'écoute des notifications"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Fournisseur de conditions"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activé"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN activé par <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Appuyez ici pour gérer le réseau."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 6a6ed88..dae681d 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"To"</string>
<string name="petabyteShort" msgid="5637816680144990219">"Po"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> jours"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> j et <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> j et <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> h"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h et <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h et <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min et <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min et <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
<string name="untitled" msgid="4638956954852782576">"<Sans nom>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronisation"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"La mémoire de la tablette est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"La mémoire de la montre est saturée. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"La mémoire du téléphone est pleine. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Il est possible que le réseau soit surveillé."</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Par un tiers inconnu"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Sonnerie activée"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Arrêt en cours..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Votre tablette va s\'éteindre."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"La montre va s\'éteindre."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Votre téléphone va s\'éteindre."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Voulez-vous éteindre l\'appareil ?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Redémarrer en mode sans échec"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode Avion"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Le mode Avion est activé."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Le mode Avion est désactivé."</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Paramètres"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Services payants"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Effectuer des opérations payantes"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vos messages"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"désinstaller des raccourcis"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permettre à l\'application de supprimer des raccourcis de l\'écran d\'accueil sans l\'intervention de l\'utilisateur"</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"transférer les appels sortants"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permettre à l\'application de lire le numéro composé lors d\'un appel sortant, et lui donner la possibilité de rediriger l\'appel vers un autre numéro ou d\'abandonner l\'appel"</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Permet à l\'application de traiter les appels sortants et de modifier le numéro à composer. Cette autorisation lui permet de surveiller, rediriger ou empêcher les appels sortants."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"recevoir des messages texte (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Permet à l\'application de recevoir et de traiter les SMS. Cette autorisation lui donne la possibilité de surveiller ou supprimer les messages envoyés à votre appareil sans vous les montrer."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"recevoir des messages texte (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permet à l\'application de récupérer le contenu de la fenêtre active. Des applications malveillantes peuvent exploiter cette fonctionnalité pour récupérer et lire la totalité du contenu de la fenêtre, à l\'exception des mots de passe."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"activer temporairement l\'accessibilité"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permet à une application d\'activer temporairement l\'accessibilité sur l\'appareil. Des applications malveillantes peuvent activer l\'accessibilité sans le consentement de l\'utilisateur."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"récupérer les jetons de fenêtre"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Permettre à une application de récupérer les jetons de fenêtre. Des applications malveillantes peuvent interagir avec la fenêtre de l\'application sans votre autorisation en se faisant passer pour le système."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"récupérer des statistiques de référence"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Permettre à une application de collecter des statistiques de référence. Des applications malveillantes peuvent suivre les statistiques de référence de fenêtres dans d\'autres applications."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"récupérer les informations sur les fenêtres"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permet à une application de récupérer les informations sur les fenêtres depuis le gestionnaire de fenêtres. Des applications malveillantes peuvent récupérer des informations destinées à un usage interne du système."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtrer les événements"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Permet à une application d\'enregistrer un filtre d\'entrée pour filtrer le flux de tous les événements des utilisateurs avant qu\'ils ne soient traités. Des applications malveillantes peuvent contrôler l\'interface utilisateur du système sans l\'intervention de l\'utilisateur."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"agrandir l\'écran"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Permet à une application d\'agrandir le contenu à l\'écran. Les applications malveillantes peuvent transformer ce contenu et rendre l\'appareil inutilisable."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"arrêt partiel"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Place le gestionnaire d\'activités en état d\'arrêt. N\'effectue pas un arrêt complet."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"empêcher les changements d\'applications"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permet à l\'application d\'envoyer une notification indiquant la réception d\'un SMS. Des applications malveillantes peuvent exploiter cette fonctionnalité pour créer de faux SMS entrants."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"Envoi de diffusion de réception de WAP PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permet à l\'application d\'envoyer une notification indiquant la réception d\'un message WAP PUSH. Des applications malveillantes peuvent exploiter cette fonctionnalité pour créer de faux MMS entrants ou pour remplacer le contenu d\'une page Web par du contenu malveillant."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"diffuser des notifications pour l\'évaluation des réseaux"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Autoriser l\'application à diffuser une notification signalant que les réseaux doivent être évalués. Cette autorisation n\'est pas nécessaire pour les applications standards."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"Nombre maximal de processus en cours d\'exécution"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permet à l\'application de contrôler le nombre maximal de processus devant s\'exécuter. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forcer la fermeture des applications en arrière-plan"</string>
@@ -371,7 +353,7 @@
<string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Permet à l\'application de lancer l\'interface utilisateur de confirmation de sauvegarde complète. Seules certaines applications peuvent bénéficier de cette permission."</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"Affichage de fenêtres non autorisées"</string>
<string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Permet à l\'application de créer des fenêtres destinées à être utilisées par l\'interface utilisateur du système interne. Les applications standards ne doivent pas utiliser cette fonctionnalité."</string>
- <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"Se superposer aux autres applis"</string>
+ <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"S\'afficher en surimpression dans les autres applis"</string>
<string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Permet à l\'application d\'ignorer d\'autres applications ou certaines parties de l\'interface utilisateur. Cela peut altérer votre utilisation de l\'interface de n\'importe quelle application, ou modifier ce que vous pensez voir dans d\'autres applications."</string>
<string name="permlab_setAnimationScale" msgid="2805103241153907174">"Réglage de la vitesse des animations"</string>
<string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Permet à l\'application de modifier à tout moment la vitesse générale des animations pour les ralentir ou les accélérer."</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service VPN. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"Se fixer sur un fond d\'écran"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un fond d\'écran. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"s\'associer à un service d\'interaction vocale"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'interaction vocale. Ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"s\'associer à un écran à distance"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permettre à l\'application autorisée de s\'associer à l\'interface de niveau supérieur d\'un écran à distance. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"associer à un service widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service widget. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"s\'associer à un fournisseur d\'itinéraires"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permettre à l\'application autorisée de s\'associer à n\'importe quel fournisseur d\'itinéraires. Ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur du périphérique"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet à l\'application autorisée d\'envoyer des intentions à l\'administrateur de l\'appareil. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"s\'associer à une entrée TV"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Permettre à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'une entrée TV. Ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ajouter ou supprimer un administrateur de l\'appareil"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permet à l\'application autorisée d\'ajouter ou de supprimer des administrateurs actifs de l\'appareil. Les applications standards ne devraient pas nécessiter cette autorisation."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"Changement d\'orientation de l\'écran"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet à une application d\'utiliser n\'importe quel décodeur installé pour lire les fichiers multimédias."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gérer les certificats de confiance"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet à l\'application d\'installer et de désinstaller les certificats CA en tant que certificats de confiance."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"exécuter l\'application lorsque l\'appareil est inactif"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Cette autorisation permet au système Android d\'exécuter l\'application en arrière-plan lorsque l\'appareil est inactif."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"associer aux services d\'inactivité"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Cette autorisation permet à la plate-forme Android de se lier aux services inactifs d\'une application."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"Lecture/écriture dans les ressources appartenant aux diagnostics"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet à l\'application d\'obtenir des droits en lecture/écriture concernant toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers du répertoire /dev). Ceci peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou l\'opérateur."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"activer ou désactiver les composants de l\'application"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Permet à l\'application d\'accéder aux informations de profil stockées sur votre appareil, telles que votre nom et vos coordonnées. L\'application peut alors vous identifier et envoyer vos informations de profil à des tiers."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"modifier votre fiche de contact"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Permet à l\'application de modifier les informations de profil stockées sur votre appareil, telles que votre nom et vos coordonnées, ou d\'en ajouter. Elle peut alors vous identifier et envoyer vos informations de profil à des tiers."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"capteurs corporels (tels que les cardiofréquencemètres)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Permet à l\'application d\'accéder aux données des capteurs utilisés pour mesurer des valeurs physiologiques, telles que votre fréquence cardiaque."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"lire votre flux de réseau social"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Permet à l\'application d\'accéder à vos mises à jour sur les réseaux sociaux, ainsi qu\'à celles de vos amis, et de les synchroniser. Soyez prudent lorsque vous partagez des informations. Cette autorisation permet à l\'application de lire les communications entre vous et vos amis sur les réseaux sociaux, indépendamment de leur caractère confidentiel. Remarque : il est possible que cette autorisation ne soit pas appliquée sur tous les réseaux sociaux."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"écrire sur votre flux social"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permet à l\'application de contrôler les fonctionnalités de téléphonie de l\'appareil. Une application disposant de cette autorisation peut, par exemple, basculer d\'un réseau à l\'autre et activer ou désactiver le signal radio du téléphone à votre insu."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"voir l\'état et l\'identité du téléphone"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet à l\'application d\'accéder aux fonctionnalités téléphoniques de l\'appareil. Cette autorisation permet à l\'application de déterminer le numéro de téléphone et les identifiants de l\'appareil, si un appel est actif et le numéro distant connecté par un appel."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"Accéder aux états précis du téléphone"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permet à l\'application d\'accéder aux états précis du téléphone. Cette autorisation lui permet de déterminer le statut d\'appel réel, si un appel est actif ou en arrière-plan, si des appels ont échoué, l\'état précis de la connexion et si cette dernière a échoué."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"empêcher la tablette de passer en mode veille"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"empêcher le téléphone de passer en mode veille"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permet à l\'application d\'empêcher la tablette de passer en mode veille."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Modifier l\'état du WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permet à l\'application de connecter la tablette aux réseaux WiMAX et de l\'en déconnecter."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permet à l\'application de connecter le téléphone aux réseaux WiMAX et de l\'en déconnecter."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"évaluer les réseaux"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Autoriser l\'application à classer les réseaux et à influencer la sélection du réseau sur la tablette"</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Autoriser l\'application à classer les réseaux et à influencer la sélection du réseau sur le téléphone"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"associer à des appareils Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permet à l\'application d\'accéder à la configuration du Bluetooth sur la tablette, et d\'établir et accepter des connexions avec les appareils associés."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permet à l\'application d\'accéder à la configuration du Bluetooth sur le téléphone, et d\'établir et accepter des connexions avec les appareils associés."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet aux applications de récupérer, d\'examiner et d\'autoriser les notifications, y compris celles envoyées par d\'autres applications."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'écoute des notifications. Ne devrait jamais être nécessaire pour les applications normales."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"s\'associer à un service de fournisseur de conditions"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service de fournisseur de conditions. Ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"faire appel à l\'application de configuration fournie par l\'opérateur"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet à l\'application autorisée de faire appel à l\'application de configuration fournie par l\'opérateur. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"détecter des observations sur les conditions du réseau"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet à une application de détecter des observations sur les conditions du réseau. Les applications standards ne devraient pas nécessiter cette autorisation."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"modifier le calibrage du périphérique d\'entrée"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permettre à l\'application de modifier les paramètres de calibrage de l\'écran tactile. Ne devrait jamais être nécessaire pour les applications standards."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accéder aux certificats de GDN"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permettre à une application de fournir et d\'utiliser des certificats de GDN. Ne devrait jamais être nécessaire pour les applications standards."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Choisir le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
@@ -752,7 +715,7 @@
<item msgid="7897544654242874543">"Bureau"</item>
<item msgid="1103601433382158155">"Télécopie bureau"</item>
<item msgid="1735177144948329370">"Télécopie domicile"</item>
- <item msgid="603878674477207394">"Bipeur"</item>
+ <item msgid="603878674477207394">"Pager"</item>
<item msgid="1650824275177931637">"Autre"</item>
<item msgid="9192514806975898961">"Personnalisé"</item>
</string-array>
@@ -795,7 +758,7 @@
<string name="phoneTypeWork" msgid="8863939667059911633">"Bureau"</string>
<string name="phoneTypeFaxWork" msgid="3517792160008890912">"Télécopie bureau"</string>
<string name="phoneTypeFaxHome" msgid="2067265972322971467">"Télécopie domicile"</string>
- <string name="phoneTypePager" msgid="7582359955394921732">"Bipeur"</string>
+ <string name="phoneTypePager" msgid="7582359955394921732">"Pager"</string>
<string name="phoneTypeOther" msgid="1544425847868765990">"Autre"</string>
<string name="phoneTypeCallback" msgid="2712175203065678206">"Rappel"</string>
<string name="phoneTypeCar" msgid="8738360689616716982">"Voiture"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permet à une application d\'accéder au stockage sécurisé keyguard."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Contrôler l\'affichage et le masquage de la protection des touches"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permet à une application de contrôler la protection des touches."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Détecter les modifications de l\'état de confiance"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permettre à une application de détecter les modifications de l\'état de confiance."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"S\'associer à un service d\'agent de confiance"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permettre à une application de s\'associer à un service d\'agent de confiance."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interagir avec le système de récupération et de mise à jour"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Permet à une application d\'interagir avec le système de récupération et les mises à jour du système."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Appuyez deux fois pour régler le zoom."</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fond d\'écran"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Changer de fond d\'écran"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Outil d\'écoute des notifications"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Fournisseur de conditions"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activé"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN activé par <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Appuyez ici pour gérer le réseau."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 957e76a..c240cb2 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> दिन"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> दिन <xliff:g id="HOURS">%2$d</xliff:g> घंटे"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> दिन <xliff:g id="HOURS">%2$d</xliff:g> घंटा"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> घंटे"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> घं. <xliff:g id="MINUTES">%2$d</xliff:g> मि."</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> घं. <xliff:g id="MINUTES">%2$d</xliff:g> मि."</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> मिनट"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> मि. <xliff:g id="SECONDS">%2$d</xliff:g> से."</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> मि. <xliff:g id="SECONDS">%2$d</xliff:g> से."</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> सेकंड"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> सेकंड"</string>
<string name="untitled" msgid="4638956954852782576">"<शीर्षक-रहित>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"समन्वयन"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"बहुत से <xliff:g id="CONTENT_TYPE">%s</xliff:g> हटाए जाते हैं."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"टेबलेट संग्रहण भर गया है. स्थान रिक्त करने के लिए कुछ फ़ाइलें हटाएं."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"घड़ी संग्रहण भर गया है. स्थान रिक्त करने के लिए कुछ फ़ाइलें हटाएं."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"फ़ोन संग्रहण भर गया है. स्थान रिक्त करने के लिए कुछ फ़ाइलें हटाएं."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"नेटवर्क को मॉनिटर किया जा सकता है"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"किसी अज्ञात तृतीय पक्ष के द्वारा"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"रिंगर चालू"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"शट डाउन हो रहा है..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"आपकी टेबलेट शट डाउन हो जाएगी."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"आपकी घड़ी बंद हो जाएगी."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"आपका फ़ोन शट डाउन हो जाएगा."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"क्या आप शट डाउन करना चाहते हैं?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"सुरक्षित मोड में रीबूट करें"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"हवाई जहाज मोड"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"हवाई जहाज मोड चालू है"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"हवाई जहाज मोड बंद है"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"सेटिंग"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"वे सेवाएं जिन पर आप खर्चा करते हैं"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ऐसे कार्य करें जिससे आपका धन खर्च हो सकता है."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"आपके संदेश"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"शॉर्टकट अनइंस्टॉल करें"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"एप्लिकेशन को उपयोगकर्ता के हस्तक्षेप के बिना होमस्क्रीन शॉर्टकट निकालने की अनुमति देता है."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"आउटगोइंग कॉल को कहीं और भेजें"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"ऐप्स को किसी कॉल को भिन्न नंबर पर रिडायरेक्ट करने या पूरी तरह से कॉल निरस्त करने के विकल्प के साथ आउटगोइंग कॉल के दौरान डायल किए जा रहे नंबर को देखने की अनुमति देती है."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"ऐप्स को आउटगोइंग कॉल संसाधित करने और डायल किए जाने वाला नंबर बदलने देता है. यह अनुमति ऐप्स को आउटगोइंग कॉल की निगरानी करने, रीडायरेक्ट करने, या उन्हें रोकने देती है."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"पाठ संदेश (SMS) प्राप्त करें"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"ऐप्स को SMS संदेशों को प्राप्त और संसाधित करने देता है. इसका अर्थ है कि ऐप्स आपके उपकरण पर भेजे गए संदेशों की निगरानी आपको दिखाए बिना कर सकता है और उन्हें हटा सकता है."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"पाठ संदेश (MMS) प्राप्त करें"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"ऐप्स को सक्रिय विंडो की सामग्री पुनर्प्राप्त करने देता है. दुर्भावनापूर्ण ऐप्स विंडो की संपूर्ण सामग्री प्राप्त कर सकते हैं और पासवर्ड को छोड़कर इसके सभी पाठ जांच सकते हैं."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"आसान तरीका को अस्थायी रूप से सक्षम करें"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"ऐप्स को उपकरण पर आसान तरीका को अस्थायी रूप से सक्षम करने देता है. दुर्भावनापूर्ण ऐप्स उपयोगकर्ता की सहमति के बिना आसान तरीका को सक्षम कर सकते हैं."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"विंडो टोकन प्राप्त करें"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"एप्लिकेशन को विंडो टोकन प्राप्त करने देती है. दुर्भावनापूर्ण ऐप्स सिस्टम का प्रतिरूपण करने वाली एप्लिकेशन विंडो से अनधिकृत इंटरैक्शन कर सकते हैं."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"फ़्रेम के आंकड़े प्राप्त करें"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"एप्लिकेशन को फ़्रेम के आंकड़े एकत्र करने देती है. दुर्भावनापूर्ण ऐप्स अन्य ऐप्स से विंडो के फ़्रेम के आंकड़ों को देख सकते हैं."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"विंडो जानकारी प्राप्त करें"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"ऐप्स को विंडो प्रबंधक से windows के बारे में जानकारी प्राप्त करने देता है. दुर्भावनापूर्ण ऐप्स आंतरिक सिस्टम उपयोग के लिए अभिप्रेत जानकारी को प्राप्त कर सकते हैं."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"ईवेंट फ़िल्टर करें"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"ऐप्स को इनपुट फ़िल्टर पंजीकृत करने देता है, जो सभी उपयोगकर्ता ईवेंट के स्ट्रीम को भेजे जाने से पहले फ़िल्टर करता है. दुर्भावनापूर्ण ऐप्स उपयोगकर्ता के हस्तक्षेप के बिना सिस्टम UI को नियंत्रित कर सकता है."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"डिस्प्ले को आवर्धित करें"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"ऐप्स को डिस्प्ले की सामग्री आवर्धित करने देता है. दुर्भावनापूर्ण ऐप्स डिस्प्ले सामग्री को इस तरह से बदल सकते हैं कि उपकरण अनुपयोगी रेंडर होता है."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"आंशिक शटडाउन"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"गतिविधि प्रबंधक को शटडाउन स्थिति में रखता है. पूर्ण शटडाउन निष्पादित नहीं करता है."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ऐप्स स्विच करने से रोकता है"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"ऐप्स को वह सूचना प्रसारित करने देता है जो SMS संदेश ने प्राप्त की है. दुर्भावनापूर्ण ऐप्स इसका उपयोग नकली इनकमिंग संदेश गढ़ने के लिए कर सकते हैं."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH-प्राप्त प्रसारण भेजें"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"ऐप्स को वह सूचना प्रसारित करने देता है जो WAP PUSH संदेश को प्राप्त हुआ है. दुर्भावनापूर्ण ऐप्स इसका उपयोग नकली MMS संदेश प्राप्त करने या किसी वेबपृष्ठ की सामग्री को दुर्भावनापूर्ण दूसरे रूप से चुपचाप प्रतिस्थापित करने के लिए कर सकते हैं."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"स्कोर नेटवर्क प्रसारण भेजें"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"ऐप्स को यह सूचना प्रसारित करने देती है कि नेटवर्क को स्कोर किए जाने की आवश्यकता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"चल रही प्रक्रियाओं की संख्या सीमित करें"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"ऐप्स को चलाई जाने वाली अधिकतम प्रक्रियाओं को नियंत्रित करने देता है. सामान्य ऐप्स के लिए कभी आवश्यक नहीं होती."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"पृष्ठभूमि ऐप्स को बलपूर्वक बंद करें"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"धारक को किसी Vpn सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"वॉलपेपर से आबद्ध करें"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"धारक को किसी वॉलपेपर के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"किसी ध्वनि सहभागिताकर्ता से आबद्ध हों"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"धारक को किसी ध्वनि सहभागिता सेवा के शीर्ष-स्तर के इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"रिमोट डिस्प्ले से आबद्ध करें"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"धारक को किसी रिमोट डिस्प्ले के शीर्ष-स्तरीय इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"किसी विजेट सेवा से आबद्ध करें"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"धारक को किसी विजेट सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"किसी रूट प्रदाता सेवा से आबद्ध हों"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"धारक को किसी भी पंजीकृत रूट प्रदाता से आबद्ध रहने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"किसी उपकरण व्यवस्थापक के साथ सहभागिता करें"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"धारक को किसी उपकरण व्यवस्थापक को उद्देश्य भेजने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"टीवी इनपुट से आबद्ध करें"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ऐप्स को प्लेबैक डीकोड करने के लिए किसी भी इंस्टॉल किए गए डीकोडर का उपयोग करने देता है."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"विश्वसनीय क्रेडेंशियल प्रबंधित करें"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"ऐप्स को CA प्रमाणपत्रों को विश्वसनीय क्रेडेंशियल के रूप में इंस्टॉल और अनइंस्टॉल करने दें"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"निष्क्रिय समय के दौरान एप्लिकेशन चलाएं"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"यह अनुमति Android सिस्टम को उपकरण के उपयोग में नहीं रहने पर एप्लिकेशन को पृष्ठभूमि में चलाने देती है."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"निष्क्रिय सेवाओं से आबद्ध करें"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"यह अनुमति Android सिस्टम को किसी एप्लिकेशन की निष्क्रिय सेवाओं से आबद्ध होने देती है."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"निदान के स्वामित्व वाले संसाधनों को पढ़ें/लिखें"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"ऐप्स को diag समूह के स्वामित्व वाले किसी संसाधन को पढ़ने और उसमें लिखने देता है; उदाहरण के लिए, /dev की फ़ाइलें. यह सिस्टम की स्थिरता और सुरक्षा को संभावित रूप से प्रभावित कर सकता है. इसका उपयोग निर्माता या ऑपरेटर द्वारा केवल हार्डवेयर-विशिष्ट निदान के लिए किया जाना चाहिए."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"ऐप्स घटकों को सक्षम या अक्षम करें"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"ऐप्स को आपके उपकरण में संग्रहीत व्यक्तिगत प्रोफ़ाइल जानकारी, जैसे आपका नाम और संपर्क जानकारी, पढ़ने देता है. इसका अर्थ है कि ऐप्स आपको पहचान सकता है और आपकी प्रोफ़ाइल जानकारी अन्य लोगों को भेज सकता है."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"स्वयं का संपर्क कार्ड बदलें"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"ऐप्स को आपके उपकरण में संग्रहीत निजी प्रोफ़ाइल जानकारी, जैसे आपका नाम और संपर्क जानकारी को बदलने या उसमें कुछ जोड़ने देता है. इसका अर्थ है कि ऐप्स आपको पहचान सकता है और आपकी प्रोफ़ाइल जानकारी अन्य लोगों को भेज सकता है."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"बॉडी सेंसर (जैसे हृदय गति मॉनीटर)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"एप्लिकेशन को ऐसे सेंसर का डेटा एक्सेस करने देती है जिनका उपयोग आप यह मापने के लिए करते हैं कि आपके शरीर के भीतर क्या चल रहा है, जैसे हृदय गति."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"अपनी सामाजिक स्ट्रीम पढ़ें"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"एप को आपके और आपके मित्रों की नई सामाजिक जानकारी तक पहुंचने और उन्हें समन्वयित करने देता है. जानकारी साझा करते समय सावधान रहें - इससे गोपनीयता पर ध्यान दिए बिना, एप सामाजिक नेटवर्क पर आपके और आपके मित्रों के बीच संचारों को पढ़ सकता है. ध्यान दें: यह अनुमति सभी सामाजिक नेटवर्क पर लागू नहीं की जा सकती."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"सामाजिक स्ट्रीम में लिखें"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"ऐप्स को उपकरण की फ़ोन सुविधाएं नियंत्रित करने देता है. इस अनुमति वाला कोई ऐप्स आपको सूचित किए बिना नेटवर्क स्विच कर सकता है, फ़ोन का रेडियो चालू और बंद कर सकता है और ऐसे ही अन्य कार्य कर सकता है."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"फ़ोन की स्थिति और पहचान पढ़ें"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"ऐप्स को उपकरण की फ़ोन सुविधाओं तक पहुंचने देता है. यह अनुमति ऐप्स को फ़ोन नंबर और उपकरण आईडी, कॉल सक्रिय है या नहीं, और कॉल द्वारा कनेक्ट किया गया दूरस्थ नंबर निर्धारित करने देती है."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"सटीक फ़ोन स्थितियों को पढ़ना"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"ऐप्स को सटीक फ़ोन स्थितियों की एक्सेस देती है. यह अनुमति ऐप्स को कॉल की वास्तविक स्थिति, चाहे वह कॉल सक्रिय हो या पृष्ठभूमि में हो, कॉल विफलताओं, सटीक डेटा कनेक्शन की स्थिति और डेटा कनेक्शन विफलताओं का पता लगाने देती है."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"टेबलेट को निष्क्रिय होने से रोकें"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"फ़ोन को निष्क्रिय होने से रोकें"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ऐप्स को टेबलेट को प्रयोग में नहीं हो जाने से रोकता है."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX स्थिति बदलें"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"ऐप्स को WiMAX नेटवर्क से टेबलेट को कनेक्ट और डिस्कनेक्ट करने देता है."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"ऐप्स को WiMAX नेटवर्क से फ़ोन को कनेक्ट और डिस्कनेक्ट करने देता है."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"स्कोर नेटवर्क"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"ऐप्स को नेटवर्क को रैंक करने देती है और इस बात पर ज़ोर देती है कि टेबलेट को किस नेटवर्क को प्राथमिकता देनी चाहिए."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"ऐप्स को नेटवर्क को रैंक करने देती है और इस बात पर ज़ोर देती है कि फ़ोन को किस नेटवर्क को प्राथमिकता देनी चाहिए."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetooth उपकरणों के साथ युग्मित करें"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"ऐप्स को टेबलेट पर Bluetooth का कॉन्फ़िगरेशन देखने, और युग्मित उपकरणों के साथ कनेक्शन बनाने और स्वीकार करने देता है."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"ऐप्स को फ़ोन पर Bluetooth का कॉन्फ़िगरेशन देखने, और युग्मित उपकरणों के साथ कनेक्शन बनाने और स्वीकार करने देता है."</string>
@@ -674,9 +645,9 @@
<string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"ऐप्स को किसी खाते की समन्वयन सेटिंग संशोधित करने देता है. उदाहरण के लिए, इसका उपयोग लोग ऐप्स का समन्वयन किसी खाते से सक्षम करने में हो सकता है."</string>
<string name="permlab_readSyncStats" msgid="7396577451360202448">"समन्वयन आंकड़े पढ़ें"</string>
<string name="permdesc_readSyncStats" msgid="1510143761757606156">"ऐप्स को किसी खाते के समन्वयन आंकड़े, साथ ही समन्वयित ईवेंट का इतिहास और समन्वयित डेटा की मात्रा पढ़ने देता है."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"सदस्यता-प्राप्त फ़ीड पढ़ें"</string>
+ <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ग्राहकी-प्राप्त फ़ीड पढ़ें"</string>
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"ऐप्स को वर्तमान में समन्वयित फ़ीड के बारे में विवरण प्राप्त करने देता है."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"सदस्यता-प्राप्त फ़ीड लिखें"</string>
+ <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"ग्राहकी-प्राप्त फ़ीड लिखें"</string>
<string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"ऐप्स को आपके वर्तमान समन्वयित फ़ीड को संशोधित करने देता है. दुर्भावनापूर्ण ऐप्स आपके समन्वयित फ़ीड को बदल सकते है."</string>
<string name="permlab_readDictionary" msgid="4107101525746035718">"शब्दकोश में आपके द्वारा जोड़े गए शब्दों को पढ़ें"</string>
<string name="permdesc_readDictionary" msgid="659614600338904243">"ऐप्स को ऐसे सभी शब्दों, नामों और वाक्यांशों को पढ़ने देता है जो संभवत: उपयोगकर्ता द्वारा उपयोगकर्ता शब्दकोश में संग्रहीत किए गए हों."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"ऐप्स को सूचनाओं को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य ऐप्स के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना श्रवणकर्ता सेवा से जुड़ें"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"धारक को सूचना श्रवणकर्ता सेवा के शीर्ष स्तरीय इंटरफ़ेस से जुड़ने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होनी चाहिए."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"किसी स्थिति प्रदाता सेवा से आबद्ध हों"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"धारक को किसी स्थिति प्रदाता सेवा के शीर्ष-स्तर के इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन ऐप्स प्रारंभ करें"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"धारक को वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन ऐप्स प्रारंभ करने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"नेटवर्क स्थितियों के अवलोकनों को सुनें"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ऐप्स को नेटवर्क स्थितियों के अवलोकनों को सुनने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"इनपुट उपकरण कैलिब्रेशन बदलें"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"ऐप्स को टच स्क्रीन के कैलिब्रेशन पैरामीटर को बदलने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM प्रमाणपत्र एक्सेस करें"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"एप्लिकेशन को DRM प्रमाणपत्रों का प्रावधान और उपयोग करने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यकता नहीं होना चाहिए."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करें"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"स्क्रीन-अनलॉक पासवर्ड में अनुमति प्राप्त लंबाई और वर्णों को नियंत्रित करें."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"स्क्रीन-अनलॉक के प्रयासों पर निगरानी रखें"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"ऐप्स को कीगार्ड सुरक्षित संग्रहण एक्सेस करने देती है."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"कीगार्ड दिखाना और छिपाना नियंत्रित करें"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"ऐप्स को कीगार्ड नियंत्रित करने देती है."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"ट्रस्ट स्थिति बदलावों को सुनें."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"किसी एप्लिकेशन को ट्रस्ट स्थिति के बदलावों को सुनने की अनुमति देती है."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ट्रस्ट एजेंट सेवा से आबद्ध करना"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"किसी एप्लिकेशन को ट्रस्ट एजेंट सेवा से आबद्ध करने की अनुमति देती है."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"अपडेट और पुनर्प्राप्ति सिस्टम के साथ सहभागिता करें"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"एप्लिकेशन को पुनर्प्राप्ति सिस्टम और सिस्टम अपडेट के साथ सहभागिता करने देती है."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"ज़ूम नियंत्रण के लिए दो बार स्पर्श करें"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"वॉलपेपर"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"वॉलपेपर बदलें"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"सूचना श्रवणकर्ता"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"स्थिति प्रदाता"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN सक्रिय"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN को <xliff:g id="APP">%s</xliff:g> द्वारा सक्रिय किया गया है"</string>
<string name="vpn_text" msgid="3011306607126450322">"नेटवर्क प्रबंधित करने के लिए स्पर्श करें."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index e4db3e6..cfd6974 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> d"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> d <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> d <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> h"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
<string name="untitled" msgid="4638956954852782576">"<Bez naslova>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinkronizacija"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Previše brisanja stavki <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Prostor za pohranu tabletnog računala pun je. Izbrišite nekoliko datoteka kako biste oslobodili prostor."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Memorija sata je puna. Izbrišite neke datoteke da biste oslobodili prostor."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Prostor za pohranu na telefonu je pun. Izbrišite nekoliko datoteka kako biste oslobodili prostor."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mreža se možda nadzire"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Od strane nepoznate treće strane"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Zvono uključeno"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Isključivanje..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Vaš tabletni uređaj će se isključiti."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Sat će se isključiti."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Vaš će se telefon isključiti."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Želite li isključiti uređaj?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Ponovno pokretanje u sigurnom načinu rada"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Način rada u zrakoplovu"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uključen je način rada u zrakoplovu"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Isključen je način rada u zrakoplovu"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Postavke"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Usluge koje se plaćaju"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Radite stvari koje će uzrokovati novčane troškove."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vaše poruke"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"deinstaliranje prečaca"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Aplikaciji omogućuje uklanjanje prečaca početnog zaslona bez intervencije korisnika."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"preusmjeravanje odlaznih poziva"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Omogućuje aplikaciji da vidi broj koji se bira prilikom odlaznog poziva uz opciju preusmjeravanja poziva na neki drugi broj ili prekidanja poziva."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Aplikaciji omogućuje obradu odlaznih poziva i promjenu broja za biranje. Ta dozvola aplikaciji omogućuje nadziranje, preusmjeravanje ili sprječavanje odlaznih poziva."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"primanje tekstnih poruka (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Aplikaciji omogućuje primanje i obradu SMS poruka. To znači da aplikacija može nadzirati ili izbrisati poruke poslane na vaš uređaj, a da vam ih ne prikaže."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"primanje tekstnih poruka (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Omogućuje aplikaciji dohvaćanje sadržaja aktivnog prozora. Zlonamjerne aplikacije mogu dohvatiti sav sadržaj prozora i pregledati sav njegov tekst osim zaporki."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"privremeno omogući dostupnost"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Aplikacija može privremeno omogućiti dostupnost na uređaju. Zlonamjerne aplikacije mogu omogućiti dostupnost bez korisnikova odobrenja."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"učitavanje prozora tokena"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Omogućuje aplikaciji učitavanje tokena prozora. Zlonamjerne aplikacije mogu stupati u neovlaštenu interakciju s prozorom aplikacije lažno se predstavljajući kao sustav."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"učitavanje statističkih pokazatelja okvira"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Omogućuje aplikaciji prikupljanje statističkih podataka okvira. Zlonamjerne aplikacije mogu pratiti statističke podatke okvira prozora iz drugih aplikacija."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"dohvaćanje informacija o prozoru"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Aplikaciji omogućuje dohvaćanje informacija o prozorima iz upravitelja prozora. Zlonamjerne aplikacije mogu dohvaćati informacije koje su namijenjene za internu uporabu sustava."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtriranje događaja"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Aplikaciji omogućuje registraciju ulaznog filtra koji filtrira strujanje svih korisničkih događaja prije otpreme. Zlonamjerne aplikacije mogu kontrolirati korisničko sučelje sustava bez znanja korisnika."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"uvećaj prikaz"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Omogućuje aplikaciji uvećavanje sadržaja zaslona. Zlonamjerne aplikacije mogu izmijeniti sadržaj zaslona tako da uređaj postane neupotrebljiv."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"djelomično isključivanje"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Postavlja upravitelja za aktivnost u stanje mirovanja. Ne isključuje ga u potpunosti."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"sprečavanje promjene aplikacije"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Omogućuje aplikaciji emitiranje obavijesti da je primljena SMS poruka. Zlonamjerne aplikacije mogu to upotrijebiti za krivotvorenje dolaznih SMS poruka."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"slanje WAP-PUSH-primljenih prijenosa"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Omogućuje aplikaciji emitiranje obavijesti da je primljena WAP PUSH poruka. Zlonamjerne aplikacije mogu to upotrijebiti da bi krivotvorile prijem MMS poruka ili da bi potajno zamijenile sadržaj bilo koje web-stranice zlonamjernim varijantama."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"slanje obavijesti za ocjenjivanje mreža"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Aplikaciji omogućuje emitiranje obavijesti da se mreža treba ocijeniti. Nije potrebno za normalne aplikacije."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"ograničavanje broja pokrenutih postupaka"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Omogućuje aplikaciji upravljanje maksimalnim brojem postupaka koji će biti pokrenuti. Nikada nije potrebno za uobičajene aplikacije."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"prisilno zatvaranje pozadinskih aplikacija"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Nositelju omogućuje vezanje uz sučelje najviše razine VPN usluge. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"povezano s pozadinskom slikom"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Nositelju omogućuje povezivanje sa sučeljem pozadinske slike najviše razine. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"povezivanje s uslugom glasovne interakcije"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Vlasniku omogućuje povezivanje sa sučeljem najviše razine usluge glasovne interakcije. Nije potrebno za normalne aplikacije."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vezanje uz udaljeni zaslon"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Nositelju omogućuje vezanje uza sučelje najviše razine udaljenog zaslona. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vezanje na uslugu widgeta"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge widgeta. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"povezivanje s davateljem usluge usmjeravanja poziva"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Nositelju omogućuje povezivanje s registriranim davateljem usluga usmjeravanja poziva. Nije potrebno za normalne aplikacije."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s administratorom uređaja"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Nositelju omogućuje slanje namjera administratoru uređaja. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"povezivanje s TV ulazom"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Aplikaciji omogućuje korištenje bilo kojim instaliranim dekoderom medija za dekodiranje radi reprodukcije."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"upravljanje pouzdanim vjerodajnicama"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Omogućuje aplikaciji instaliranje i deinstaliranje CA certifikata kao pouzdanih vjerodajnica."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"izvodi aplikaciju tijekom mirovanja"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"To dopuštenje omogućuje sustavu Android da izvodi aplikaciju u pozadini dok se uređaj ne upotrebljava."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"veži uz usluge u mirovanju"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"To dopuštenje omogućuje sustavu Android da se veže uz aplikacijine usluge u mirovanju."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"pisanje/čitanje u resursima čije je vlasnik dijagnostika"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Aplikaciji omogućuje čitanje i pisanje na bilo koji resurs u vlasništvu dijag. grupe; na primjer, datoteke u sustavu /dev. To bi moglo utjecati na stabilnost sustava i sigurnost. Dozvolu bi trebao upotrebljavati proizvođač ili operater SAMO za dijagnostiku koja se odnosi na hardver."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"omogućavanje ili onemogućavanje komponenti aplikacije"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Aplikaciji omogućuje čitanje osobnih podataka profila pohranjenih na uređaju, kao što su vaše ime ili kontaktni podaci. To znači da vas aplikacija može identificirati i slati informacije s vašeg profila drugima."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"izmjena vaše kontaktne kartice"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Aplikaciji omogućuje promjenu ili dodavanje osobnih podataka profila pohranjenih na uređaju, kao što su vaše ime i kontaktni podaci. To znači da vas aplikacija može identificirati i slati informacije s vašeg profila drugima."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"senzori tjelesnih funkcija (npr. monitori otkucaja srca)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Aplikaciji omogućuje pristup podacima iz senzora koje upotrebljavate za mjerenje onoga što se odvija u vašem tijelu, poput otkucaja srca."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"čitanje društvenog streama"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Aplikaciji omogućuje pristup vašim ažuriranjima na društvenim mrežama i ažuriranjima vaših prijatelja, kao i sinkronizaciju tih ažuriranja. Budite oprezni kad dijelite informacije – to aplikaciji omogućuje čitanje poruka između vas i vaših prijatelja na društvenim mrežama, neovisno o povjerljivosti. Napomena: ta se dozvola možda ne primjenjuje na svim društvenim mrežama."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"pisanje društvenog streama"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Omogućuje aplikaciji upravljanje telefonskim značajkama uređaja. Aplikacija s tom dozvolom može izmjenjivati mreže, uključiti i isključiti radiouređaj telefona i tome slično, a da vas o tome uopće ne obavijesti."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"čitanje statusa i identiteta telefona"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Aplikaciji omogućuje pristup telefonskim značajkama uređaja. Ta dozvola aplikaciji omogućuje utvrđivanje telefonskog broja i ID-ova uređaja, je li poziv aktivan te udaljeni broj koji je povezan pozivom."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"čitaj precizna stanja telefona"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Omogućuje aplikaciji pristup preciznim stanjima telefona. To dopuštenje omogućuje aplikaciji da odredi stvarni status poziva, je li poziv aktivan ili u pozadini, neuspjele pozive, precizne podatke o statusu veze te neuspjela uspostavljanja podatkovnih veza."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"spriječi mirovanje tabletnog uređaja"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"sprečava telefon da prijeđe u stanje mirovanja"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Aplikaciji omogućuje sprječavanje prelaska tabletnog računala u mirovanje."</string>
@@ -658,13 +632,10 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Promjena stanja WiMAX mreže"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Aplikaciji omogućuje povezivanje tabletnog računala s WiMAX mrežama i prekidanje veze tabletnog računala s njima."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Aplikaciji omogućuje povezivanje telefona s WiMAX mrežama i prekidanje veze telefona s njima."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ocjenjivanje mreža"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Aplikaciji omogućuje rangiranje mreža i utjecanje na odabir preferiranih mreža na tabletu."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Aplikaciji omogućuje rangiranje mreža i utjecanje na odabir preferiranih mreža na telefonu."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"uparivanje s Bluetooth uređajima"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Aplikaciji omogućuje pregled konfiguracije Bluetootha na tabletnom računalu te uspostavljanje i prihvaćanje veza s uparenim uređajima."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Aplikaciji omogućuje pregled konfiguracije Bluetootha na telefonu te uspostavljanje i prihvaćanje veza s uparenim uređajima."</string>
- <string name="permlab_nfc" msgid="4423351274757876953">"upravljanje beskontaktnom komunikacijom (NFC)"</string>
+ <string name="permlab_nfc" msgid="4423351274757876953">"upravljaj beskontaktnom (NFC) komunikacijom"</string>
<string name="permdesc_nfc" msgid="7120611819401789907">"Aplikaciji omogućuje komunikaciju s oznakama, karticama i čitačima komunikacije kratkog dometa (NFC)."</string>
<string name="permlab_disableKeyguard" msgid="3598496301486439258">"onemogućavanje zaključavanja zaslona"</string>
<string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Aplikaciji omogućuje onemogućavanje zaključavanja tipkovnice i svih pripadajućih sigurnosnih zaporki. Na primjer, telefon onemogućuje zaključavanje tipkovnice kod primanja dolaznog telefonskog poziva, nakon kojeg se zaključavanje tipkovnice ponovo omogućuje."</string>
@@ -686,7 +657,7 @@
<string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"čitanje sadržaja SD kartice"</string>
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Aplikaciji omogućuje čitanje sadržaja vaše USB pohrane."</string>
<string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Aplikaciji omogućuje čitanje sadržaja vaše SD kartice."</string>
- <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"izmjena/brisanje sadržaja USB-a"</string>
+ <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"izmjena/brisanje sadrž. USB-a"</string>
<string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"izmjena ili brisanje sadržaja SD kartice"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Dopušta pisanje u USB pohranu."</string>
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Aplikaciji omogućuje pisanje na SD karticu."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Omogućuje aplikaciji dohvaćanje, pregledavanje i brisanje obavijesti, uključujući obavijesti drugih aplikacija."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vezanje uz uslugu slušatelja obavijesti"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge slušatelja obavijesti. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"povezivanje s uslugom davatelja uvjeta"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Vlasniku omogućuje povezivanje sa sučeljem najviše razine usluge davatelja uvjeta. Nije potrebno za normalne aplikacije."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"pozovi operaterovu aplikaciju za konfiguraciju"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Dopušta nositelju pozivanje operaterove aplikacije za konfiguraciju. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"praćenje motrenja mrežnih uvjeta"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Omogućuje aplikaciji praćenje motrenja mrežnih uvjeta. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"promjena kalibracije uređaja za unos"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Omogućuje aplikaciji izmjenu parametara kalibracije dodirnog zaslona. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"pristup DRM certifikatima"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Aplikaciji omogućuje pružanje i korištenje DRM certifikata. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Postavi pravila zaporke"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Upravljajte duljinom zaporki za otključavanje zaslona i dopuštenim znakovima u tim zaporkama."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Nadgledaj pokušaje otključavanja zaslona"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Omogućuje aplikaciji pristupanje zaključanoj sigurnoj pohrani."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Upravljanje prikazivanjem i skrivanjem zaključavanja tipkovnice"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Omogućuje aplikaciji upravljanje zaključavanjem tipkovnice."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Prati promjene pouzdanog stanja."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Omogućuje aplikaciji praćenje promjena pouzdanog stanja."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Povezivanje s uslugom pouzdanog predstavnika"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Omogućuje aplikaciji povezivanje s uslugom pouzdanog predstavnika."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interakcija s ažuriranjem i sustavom za oporavak"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Omogućuje aplikaciji interakciju sa sustavom za oporavak i ažuriranjima sustava."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dodirnite dvaput za upravljanje zumiranjem"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Pozadinska slika"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Promjena pozadinske slike"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Slušatelj obavijesti"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Davatalj uvjeta"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> aktivirala je VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dodirnite za upravljanje mrežom."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 6130c5e..8d55245 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> nap"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> nap <xliff:g id="HOURS">%2$d</xliff:g> óra"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> nap <xliff:g id="HOURS">%2$d</xliff:g> óra"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> óra"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> óra <xliff:g id="MINUTES">%2$d</xliff:g> perc"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> óra <xliff:g id="MINUTES">%2$d</xliff:g> perc"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> perc"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> perc <xliff:g id="SECONDS">%2$d</xliff:g> mp"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> perc <xliff:g id="SECONDS">%2$d</xliff:g> mp"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> másodperc"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> másodperc"</string>
<string name="untitled" msgid="4638956954852782576">"<Névtelen>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Szinkronizálás"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Túl sok <xliff:g id="CONTENT_TYPE">%s</xliff:g> törlés."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"A táblagép tárhelye tele van. Szabadítson fel helyet néhány fájl törlésével."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Az óra tárhelye megtelt. Szabadítson fel helyet néhány fájl törlésével."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"A telefon tárhelye megtelt. Hely felszabadításához töröljön néhány fájlt."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Lehet, hogy a hálózat felügyelt"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Ismeretlen harmadik fél által"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Csengő bekapcsolva"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Leállítás..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"A táblagép ki fog kapcsolni."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Az óra ki fog kapcsolni."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"A telefon le fog állni."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Kikapcsolja?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Újraindítás csökkentett módban"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Repülőgép üzemmód"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Repülőgép üzemmód bekapcsolva"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Repülőgép üzemmód kikapcsolva"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Beállítások"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Fizetős szolgáltatások"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Olyan dolgok végrehajtása, amelyek pénzbe kerülnek."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Saját üzenetek"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"parancsikonok eltávolítása"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Lehetővé teszi egy alkalmazás számára, hogy felhasználói beavatkozás nélkül távolítson el parancsikonokat a kezdőképernyőről."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"kimenő hívások átirányítása"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Lehetővé teszi, hogy az alkalmazás kimenő híváskor lássa a tárcsázott számot, valamint a hívást átirányítsa egy másik számra, vagy megszakítsa."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Lehetővé teszi az alkalmazás számára a kimenő hívások kezdeményezését, és a tárcsázandó szám módosítását. Az engedéllyel rendelkező alkalmazás felügyelheti, átirányíthatja vagy megakadályozhatja a kimenő hívásokat."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"szöveges üzenetek (SMS) fogadása"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Lehetővé teszi az alkalmazás számára, hogy SMS-eket fogadjon és dolgozzon fel. Ez azt jelenti, hogy az alkalmazás megfigyelheti vagy törölheti a beérkező üzeneteket anélkül, hogy Ön látná azokat."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"szöveges üzenetek (MMS) fogadása"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Lehetővé teszi az alkalmazás számára az aktív ablak tartalmának letöltését. A rosszindulatú alkalmazások letölthetik az ablak teljes tartalmát, és a jelszavak kivételével az összes szöveget megvizsgálhatják."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"Ideiglenes hozzáférés engedélyezése"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Engedélyezi egy alkalmazás számára, hogy ideiglenesen hozzáférést biztosítson az eszközhöz. A kártékony alkalmazások a felhasználó beleegyezése nélkül engedélyezhetik a hozzáférést."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"ablaktoken lekérése"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Lehetővé teszi, hogy az alkalmazás lekérje az ablaktokent. A kártékony alkalmazások jogosulatlan kapcsolatot létesíthetnek az alkalmazásablakkal a rendszer nevében."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"keretstatisztikák lekérése"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Lehetővé teszi, hogy az alkalmazás keretstatisztikákat gyűjtsön. A kártékony alkalmazások figyelhetik a más alkalmazások ablakainak keretstatisztikáit."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"ablakkal kapcsolatos információk lekérése"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Lehetővé teszi, hogy az alkalmazás információkat kérjen le az ablakkezelőben lévő ablakokkal kapcsolatban. A rosszindulatú alkalmazások belső rendszerhasználathoz szükséges információkat kérhetnek le."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"események szűrése"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Lehetővé teszi az alkalmazás számára, hogy egy bemeneti szűrőt használjon, amely megszűri a falon megjelenő felhasználói eseményeket, még mielőtt megjelennének. A rosszindulatú alkalmazások felhasználói beavatkozás nélkül irányíthatják a rendszer kezelőfelületét."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"kijelző nagyítása"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Lehetővé teszi egy alkalmazás számára, hogy kinagyítsa a kijelzőn megjelenő tartalmat. Előfordulhat, hogy a rosszindulatú alkalmazások úgy alakítják át a kijelző tartalmát, hogy használhatatlanná válik az eszköz."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"részleges rendszerleállítás"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Leállítás állapotba helyezi a tevékenységkezelőt. Nem hajtja végre a teljes leállítást."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"alkalmazásváltás megakadályozása"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Lehetővé teszi az alkalmazás számára értesítés küldését SMS érkezéséről. A rosszindulatú alkalmazások beérkező SMS-ek hamisítására használhatják fel ezt."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH alapú üzenetek küldése"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Lehetővé teszi az alkalmazás számára értesítés küldését WAP PUSH üzenet érkezése esetén. A rosszindulatú alkalmazások arra használhatják ezt, hogy MMS-kézbesítési jelentést hamisítsanak, vagy hogy a háttérben rosszindulatú variánssal cseréljék le bármelyik weboldal tartalmát."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"hálózatpontozási értesítés küldése"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Lehetővé teszi, hogy az alkalmazás szétküldjön egy értesítést, amely szerint a hálózatokat pontozni kell. A normál alkalmazásoknak erre soha nincs szükségük."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"futó folyamatok számának korlátozása"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Lehetővé teszi az alkalmazás számára a futtatható folyamatok maximális számának vezérlését. Soha nem lehet rá szüksége a normál alkalmazásoknak."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"háttéralkalmazások leállításának kényszerítése"</string>
@@ -400,18 +382,14 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Lehetővé teszi a használó számára, hogy csatlakozzon egy VPN-szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"összekapcsolás háttérképpel"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lehetővé teszi, hogy a tulajdonos kötelezővé tegye egy háttérkép legfelső szintű felületét. A normál alkalmazásoknak erre soha nincs szüksége."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"csatlakozás egy hangvezérlőhöz"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Lehetővé teszi a használó számára, hogy csatlakozzon egy hangvezérlő szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"csatlakozás egy távoli kijelzőhöz"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lehetővé teszi a használó számára, hogy csatlakozzon egy távoli kijelző legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"csatlakozás modulszolgáltatáshoz"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lehetővé teszi a használó számára, hogy csatlakozzon egy modulszolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"csatlakozás egy útvonal-szolgáltatóhoz"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Az eszköz kezelője csatlakozhat bármely regisztrált útvonal-szolgáltatóhoz. A normál alkalmazások esetében erre nincs szükség."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"az eszközkezelő használata"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Lehetővé teszi a tulajdonos számára, hogy célokat küldjön egy eszközkezelőnek. A normál alkalmazásoknak erre soha nincs szüksége."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"csatlakozás tévébemenethez"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Lehetővé teszi, hogy a tulajdonos kapcsolódjon egy tévébemenet legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
+ <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Lehetővé teszi, hogy a tulajdonos kapcsolódjon egy tévébemenet legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"eszközrendszergazda hozzáadása vagy eltávolítása"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Lehetővé teszi a tulajdonos számára, hogy aktív eszközrendszergazdákat adjon meg vagy távolítson el. A normál alkalmazásoknál erre soha nincs szükség."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"képernyő irányának módosítása"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Lehetővé teszi egy alkalmazás számára bármely telepített médiadekóder használatát a lejátszás dekódolásához."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"megbízható tanúsítványok kezelése"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lehetővé teszi az alkalmazás számára a CA tanúsítványok telepítését és eltávolítását."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"alkalmazás futtatása tétlen időszakban"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ezzel az engedéllyel az Android a háttérben futtathatja az alkalmazást, amikor az eszközt nem használják."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"csatolás tétlen szolgáltatásokhoz"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Ez az engedély lehetővé teszi az Android számára, hogy összekapcsolódjon egy alkalmazás tétlen szolgáltatásaival."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"a diag tulajdonában lévő erőforrások olvasása és írása"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Lehetővé teszi egy alkalmazás számára, hogy olvassa és írja a diagnosztikai csoport minden erőforrását, például a /dev könyvtárban lévő fájlokat. Ez potenciálisan befolyásolhatja a rendszer stabilitását és biztonságát, ezért CSAK a gyártó vagy a szolgáltató használhatja hardverspecifikus diagnosztizálásra."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"alkalmazáskomponensek be- és kikapcsolása"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Lehetővé teszi az alkalmazás számára, hogy hozzáférést biztosítson az eszközön tárolt személyes profiladatokhoz, például a névhez és az elérhetőségekhez. Ez azt jelenti, hogy az alkalmazás azonosíthatja Önt, és elküldheti másoknak profiladatait."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"saját névjegykártya módosítása"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Lehetővé teszi az alkalmazás számára az eszközön tárolt személyes profiladatok, például a név és az elérhetőségek módosítását vagy hozzáadását. Ez azt jelenti, hogy az alkalmazás azonosíthatja Önt, és elküldheti másoknak profiladatait."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"testérzékelők (pl. pulzusmérő)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Lehetővé teszi, hogy az alkalmazás hozzáférjen az olyan érzékelők által észlelt adatokhoz, amelyek az Ön életfunkcióit – például a pulzusszámát – figyelik."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"közösségi adatfolyam olvasása"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Lehetővé teszi az alkalmazás számára, hogy hozzáférjen az Ön és ismerősei közösségi oldalakon szereplő frissítéseihez. Legyen elővigyázatos, amikor információt tesz közzé -- így az alkalmazás hozzáférhet az ismerőseivel a közösségi hálózatokon folytatott magánbeszélgetésekhez, a tartalom titkos jellegétől függetlenül. Megjegyzés: előfordulhat, hogy ez nincs minden közösségi hálózaton engedélyezve."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"írás a közösség adatfolyamra"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Lehetővé teszi az alkalmazás számára, hogy az eszköz telefonálási funkcióit vezérelje. Egy ilyen engedéllyel rendelkező alkalmazás váltani tud a hálózatok között, be- és kikapcsolhatja a telefon rádióját, és hasonlókat tehet anélkül, hogy valaha értesítené Önt."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"telefonállapot és azonosító olvasása"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Lehetővé teszi az alkalmazás számára, hogy hozzáférjen az eszköz telefonálási funkcióihoz. Az engedéllyel rendelkező alkalmazás meghatározhatja a telefonszámot és eszközazonosítókat, hogy egy hívás aktív-e, valamint híváskor a másik fél telefonszámát."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"pontos telefonállapot megállapítása"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Engedélyezi, hogy az alkalmazás hozzáférjen a pontos telefonállapothoz. Az ilyen engedéllyel rendelkező alkalmazás képes meghatározni a valós hívási állapotot, azt, hogy egy hívás aktív-e vagy a háttérben van, a hívás meghiúsult-e, illetve képes meghatározni az adatkapcsolat pontos állapotát és az adatkapcsolati műveletek meghiúsulását."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"táblagép alvás üzemmódjának megakadályozása"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"telefon alvó üzemmódjának megakadályozása"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Lehetővé teszi az alkalmazás számára, hogy megakadályozza, hogy a táblagép alvó üzemmódra váltson."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX-állapot módosítása"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Lehetővé teszi az alkalmazás számára, hogy a táblagépet csatlakoztassa WiMAX-hálózathoz vagy leválassza azt róla."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Lehetővé teszi az alkalmazás számára, hogy a telefont csatlakoztassa WiMAX-hálózathoz vagy leválassza azt róla."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"hálózatok pontozása"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Lehetővé teszi, hogy az alkalmazás rangsorolja a hálózatokat, illetve befolyásolja, hogy a táblagép mely hálózatokat részesítse előnyben."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Lehetővé teszi, hogy az alkalmazás rangsorolja a hálózatokat, illetve befolyásolja, hogy a telefon mely hálózatokat részesítse előnyben."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetooth-eszközök párosítása"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Lehetővé teszi az alkalmazás számára a táblagépen lévő Bluetooth beállításainak megtekintését, valamint kapcsolatok kezdeményezését és fogadását a párosított eszközökkel."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Lehetővé teszi az alkalmazás számára a telefonon lévő Bluetooth beállításainak megtekintését, valamint kapcsolatok kezdeményezését és fogadását a párosított eszközökkel."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Lehetővé teszi, hogy az alkalmazás értesítéseket kérdezzen le, vizsgáljon és tisztítson meg, beleértve az egyéb alkalmazások által közzétett értesítéseket is."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"csatlakozzon értesítésfigyelő szolgáltatáshoz"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lehetővé teszi a használó számára, hogy csatlakozzon egy értesítésfigyelő szolgáltatás legfelső szintű felületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"csatlakozás egy feltételbiztosító szolgáltatáshoz"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Lehetővé teszi a használó számára, hogy csatlakozzon egy feltételbiztosító szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"a szolgáltatói konfigurációs alkalmazás hívása"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lehetővé teszi a használó számára a szolgáltató által biztosított konfigurációs alkalmazás hívását. A normál alkalmazásoknak erre soha nincs szükségük."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"hálózati körülményekkel kapcsolatos észrevételek figyelemmel kísérése"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Lehetővé teszi egy alkalmazás számára, hogy figyelemmel kísérje a hálózati körülményekkel kapcsolatos észrevételeket. A normál alkalmazásoknak erre soha nincs szükségük."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"beviteli eszköz kalibrációjának módosítása"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Lehetővé teszi, hogy az alkalmazás módosítsa az érintőképernyő kalibrációs paramétereit. A normál alkalmazásoknál erre elvileg soha nincs szükség."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM-tanúsítványokhoz való hozzáférés"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Engedélyezi egy alkalmazás számára a DRM-tanúsítványokhoz való hozzáférést és azok használatát. Átlagos alkalmazásoknak erre nem lehet szükségük."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Jelszavakkal kapcsolatos szabályok beállítása"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"A képernyőzár-feloldási jelszavakban engedélyezett karakterek és hosszúság vezérlése."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Képernyőzár-feloldási kísérletek figyelése"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Lehetővé teszi egy alkalmazás számára, hogy hozzáférjen a kóddal védett tárhelyhez."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Billentyűzár megjelenítésének és elrejtésének vezérlése"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Lehetővé teszi egy alkalmazás számára a billentyűzár vezérlését."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Trust-állapot változásának figyelése"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Lehetővé teszi, hogy az alkalmazás figyelje a trust-állapot változásait."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Csatlakozás egy trust agent szolgáltatáshoz"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Lehetővé teszi, hogy az alkalmazás egy trust agent szolgáltatáshoz csatlakozzon."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Kapcsolatfelvétel a frissítési és helyreállítási rendszerrel"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Lehetővé teszi egy alkalmazás számára, hogy kapcsolatba lépjen a helyreállítási rendszerrel és a rendszerfrissítésekkel."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Érintse meg kétszer a nagyítás beállításához"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Háttérkép"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Háttérkép megváltoztatása"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Értesítésfigyelő"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Feltételbiztosító"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN aktiválva"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"A(z) <xliff:g id="APP">%s</xliff:g> aktiválta a VPN-t"</string>
<string name="vpn_text" msgid="3011306607126450322">"Érintse meg a hálózat kezeléséhez."</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index a4a5f48..c544ddb 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"Տբ"</string>
<string name="petabyteShort" msgid="5637816680144990219">"Պբ"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> օր"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> օր <xliff:g id="HOURS">%2$d</xliff:g> ժ"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> օր <xliff:g id="HOURS">%2$d</xliff:g> ժ"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> ժ"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> ժ <xliff:g id="MINUTES">%2$d</xliff:g> ր"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> ժ <xliff:g id="MINUTES">%2$d</xliff:g> ր"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> րոպե"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> ր <xliff:g id="SECONDS">%2$d</xliff:g> վ"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> ր <xliff:g id="SECONDS">%2$d</xliff:g> վ"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> վ"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> վ"</string>
<string name="untitled" msgid="4638956954852782576">"<Անանուն>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Համաժամել"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Չափից շատ <xliff:g id="CONTENT_TYPE">%s</xliff:g> հեռացումներ:"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Գրասալիկի պահոցը լիքն է: Ջնջեք մի քանի ֆայլ` տարածք ազատելու համար:"</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Ժամացույցի ֆայլերի պահեստը լիքն է: Ջնջեք որոշ ֆայլեր՝ տարածք ազատելու համար:"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Հեռախոսի պահոցը լիքն է: Ջնջեք մի քանի ֆայլեր` տարածություն ազատելու համար:"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Ցանցը կարող է վերահսկվել"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Անհայտ երրորդ կողմի կողմից"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Զանգակը միացված է"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Անջատվում է…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Ձեր գրասալիկը կանջատվի:"</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ձեր ժամացույցը կանջատվի:"</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Ձեր հեռախոսը կանջատվի:"</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Ցանկանու՞մ եք անջատել:"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Վերաբեռնել անվտանգ ռեժիմի"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Ինքնաթիռային ռեժիմ"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Ինքնաթիռային ռեժիմը միացված է"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Ինքնաթիռային ռեժիմը անջատված է"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Կարգավորումներ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Ծառայություններ, որոնց համար կգանձվեք"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Կատարել գործողություններ, որի դիմաց ձեր հաշվից գումար կծախսվի:"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Ձեր հաղորդագրությունները"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"ապատեղադրել դյուրանցումները"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Հավելվածին թույլ է տալիս հեռացնել գլխավոր էկրանի դյուրանցումները՝ առանց օգտագործողի միջամտության:"</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"վերաուղղել ելքային զանգերը"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Թույլ է տալիս ծրագրին ելքային զանգի ընթացքում տեսնել արդեն հավաքած համարը՝ հնարավորություն տալով վերահղել կամ անջատել զանգը։"</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Թույլ է տալիս հավելվածին մշակել ելքային զանգերը և փոխել համարհավաքումը: Վնասարար հավելվածները կարող են վերահսկել, վերահասցեավորել կամ կանխել ելքային զանգերը:"</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"ստանալ տեքստային հաղորդագրություններ (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Թույլ է տալիս հավելվածին ստանալ և մշակել SMS հաղորդագրությունները: Սա նշանակում է, որ հավելվածը կարող է ստուգել կամ ջնջել ձեր սարքին ուղարկված հաղորդագրությունները` առանց դրանք ձեզ ցուցադրելու:"</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"ստանալ տեքստային հաղորդագրություններ (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Թույլ է տալիս հավելվածին առբերել ակտիվ պատուհանի պարունակությունը: Վնասարար հավելվածները կարող են առբերել պատուհանի լրիվ պարունակությունը և հետազոտել դրա ամբողջ տեքստը` բացառությամբ գաղտնաբառերի:"</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"ժամանակավոր միացնել մուտքի հնարավորությունը"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Թույլ է տալիս հավելվածին ժամանակավորապես մուտքի հնարավորություն տալ սարքին: Վնասարար հավելվածները կարող են մուտքի հնարավորություն ընձեռել առանց օգտվողի համաձայնության:"</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"առբերել պատուհանի այլանիշը"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Ծրագրին թույլ է տալիս առբերել պատուհանի այլանիշը: Վնասակար ծրագրերը կարող են չթույլատրված ազդեցություն ունենալ ծրագրի պատուհանին՝ նմանակելով համակարգը:"</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"առբերել շրջանակի վիճակագրությունը"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Ծրագրին թույլ է տալիս հավաքել շրջանակի վիճակագրությունը: Վնասակար ծրագրերը կարող են այլ ծրագրերից հետևել շրջանակի վիճակագրությանը պատուհանների համար:"</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"առբերել պատուհանի տեղեկություները"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Թույլ է տալիս հավելվածին առբերել պատուհանների մասին տեղեկատվություններ պատուհանի կառավարչից: Վնասարար հավելվածները կարող են առբերել տեղեկություններ, որը նախատեսված է ներքին համակարգի օգտագործման համար:"</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"զտել իրադարձությունները"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Թույլ է տալիս հավելվածին գրանցել մուտքագրման զտիչ, որը զտում է օգտվողի իրադարձությունների ամբողջ հոսքը` նախքան դրանք կուղարկվեն: Վնասարար հավելվածը կարող է կառավարել համակարգի UI-ը` առանց ձեր միջամտության:"</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"խոշորացնել ցուցադրիչը"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Թույլ է տալիս հավելվածին խոշորացնել ցուցադրիչի բովանդակությունը: Վնասարար հավելվածները կարող են փոխակերպել ցուցադրիչի բովանդակությունը այնպես, որ սարքը դառնա անպիտան:"</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"մասնակի անջատում"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Դնում է գործունեության կառավարչին անջատման կարգավիճակի մեջ: Չի իրականացնում ամբողջական անջատում:"</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"կանխել ծրագրի փոխարկումները"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Թույլ է տալիս հավելվածին հաղորդել ծանուցում, որ ստացվել է SMS հաղորդագրություն: Վնասարար հավելվածները կարող են օգտագործել սա` կեղծելու մուտքային SMS հաղորդագրությունները:"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ուղարկել ստացված WAP-PUSH-ի հաղորդում"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Թույլ է տալիս հավելվածին հաղորդել ծանուցում, որ ստացվել է WAP PUSH հաղորդագրություն: Վնասարար հավելվածները կարող են օգտագործել սա` կեղծելու MMS հաղորդագրության ստացումը կամ աննկատ փոխարինելու ցանկացած կայքի բովանդակությունը վնասարար տարբերակներով:"</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ուղարկել ցանցերի գնահատականի հեռարձակում"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Ծրագրին թույլ է տալիս հեռարձակել ծանուցում, որ ցանցերը պետք է հաշվարկվեն: Նորմալ ծրագրերում երբեք պետք չի գալիս:"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"սահմանափակել աշխատող գործընթացների թիվը"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Թույլ է տալիս հավելվածին վերահսկել գործընթացների առավելագույն թիվը, որ աշխատելու են: Երբևէ անհրաժեշտ չէ սովորական հավելվածների համար:"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"ստիպել, որ առաջին պլանի հավելվածները փակվեն"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Թույլ է տալիս սեփականատիրոջը միանալ Vpn ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"միանալ պաստառին"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Թույլ է տալիս սեփականատիրոջը միանալ պաստառի վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"կապվել ձայնային փոխազդիչին"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Թույլ է տալիս սեփականատիրոջը միանալ ձայնային փոխազդիչի բազային միջերեսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"միանալ հեռակա էկրանին"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Թույլ է տալիս սեփականատիրոջը միանալ հեռակա էկրանի վերին մակարդակի ինտերֆեյսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"միանալ վիջեթ ծառայությանը"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Թույլ է տալիս սեփականատիրոջը միանալ վիջեթ ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"կապվել երթուղու մատակարարի ծառայությանը"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Թույլ է տալիս տիրոջը կապվել երթուղու մատակարարներից ցանկացածին: Սովորական ծրագրերի համար երբեք անհրաժեշտ չէ:"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"փոխգործակցել սարքի կառավարչի հետ"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Թույլ է տալիս սեփականատիրոջը ուղարկել մտադրություններ սարքի կառավարչին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"միանալ հեռուստացույցի մուտքին"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Թույլ է տալիս սեփականատիրոջը միանալ հեռուստացույցի մուտքի վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ավելացնել կամ հեռացնել սարքի արդմինիստրատոր"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Թույլ է տալիս սեփականատիրոջը ավելացնել կամ հեռացնել սարքի ակտիվ ադմինիստրատորներ: Երբեք չպետք է անհրաժեշտ լինի սովորական ծրագրերին:"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"փոխել էկրանի դիրքավորումը"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Թույլ է տալիս հավելվածին օգտագործել ցանկացած տեղադրված մեդիա վերծանիչ` նվագարկումը ապակոդավորելու համար:"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"կառավարել վստահելի հավաստագրերը"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Թույլատրում է հավելվածին տեղադրել և ապատեղադրել CA վկայագրերը՝ որպես վստահելի հավաստագրեր:"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"գործադրել ծրագրեր պարապուրդի ժամանակ"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Այս թույլտվությունը հնարավորություն է տալիս, որ Android համակարգը ծրագրեր գործադրի ֆոնային ռեժիմում, երբ սարքը չի օգտագործվում:"</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"կապակցել ոչ ակտիվ ծառայությունների հետ"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Այս թույլտվությունը հնարավորություն է տալիս Android համակարգին կապ հաստատել ծրագրի չաշխատող ծառայությունների հետ:"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"կարդալ կամ գրել ախտորոշիչին պատկանող ռեսուրսները"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Թույլ է տալիս հավելվածին կարդալ և գրել ախտորոշիչ խմբին պատկանող ցանկացած ռեսուրսում, ինչպես օրինակ ֆայլերը /dev-ում: Դա կարող է ազդել համակարգի կայունության և անվտանգության վրա: Սա պետք է օգտագործել միայն արտադրողի կամ օպերատորի կողմից սարքին հատուկ ախտորոշման համար:"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"միացնել կամ անջատել հավելվածի բաղադրիչները"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Թույլ է տալիս հավելվածին կարդալ ձեր սարքում պահված անհատական պրոֆիլի տվյալները, ինչպիսիք են ձեր անունը և կոնտակտային տվյալները: Սա նշանակում է, որ հավելվածը կարող է ձեզ ճանաչել և ուղարկել ձեր պրոֆիլի տվյալները ուրիշներին:"</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"փոփոխել ձեր սեփական կոնտակտային քարտը"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Թույլ է տալիս հավելվածին փոխել կամ ավելացնել ձեր սարքում պահված անհատական պրոֆիլի տվյալները, ինչպիսիք են ձեր անունը և կոնտակտային տվյալները: Սա նշանակում է, որ հավելվածը կարող է ձեզ ճանաչել և ուղարկել ձեր պրոֆիլի տվյալները ուրիշներին:"</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"մարմնի սենսորներ (օր.` սրտի)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Ծրագրին թույլ է տալիս մատչել ձեր կողմից օգտագործվող սենսորների տվյալները՝ չափելու, թե ինչ է տեղի ունենում ձեր մարմնի ներսում, ինչպես օրինակ՝ սրտի զարկերը:"</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"կարդալ ձեր սոցիալական հոսքը"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Թույլ է տալիս հավելվածին մուտք գործել և համաժամեցնել ձեր և ձեր ընկերների սոցիալական թարմացումները: Զգույշ եղեք տեղեկություններ տարածելիս. այն թույլ է տալիս հավելվածին կարդալ ձեր և ձեր ընկերների միջև անձնական հաղորդագրությունները սոցիալական ցանցերում` անկախ գաղտնիությունից: Նշում. այս թույլտվությունը չի կարող գործածվել բոլոր սոցիալական ցանցերում:"</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"գրել ձեր սոցիալական հոսքում"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Թույլ է տալիս հավելվածին կառավարել սարքի հեռախոսային գործիքները: Այս թույլտվությամբ հավելվածը կարող է փոխարկել ցանցերը, միացնելև անջատել հեռախոսի ռադիոն և նման այլ բաներ` առանց ձեզ երբևէ տեղեկացնելու:"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"կարդալ հեռախոսի կարգավիճակը և ինքնությունը"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Թույլ է տալիս հավելվածին օգտագործել սարքի հեռախոսային գործիքները: Այս թույլտվությունը հավելվածին հնարավորություն է տալիս որոշել հեռախոսահամարը և սարքի ID-ները, արդյոք զանգը ակտիվ է և միացված զանգի հեռակա հեռախոսահամարը:"</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"դիտել հեռախոսի ճշգրիտ կարգավիճակները"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Թույլ է տալիս ծրագրին մուտք ունենալ հեռախոսի ճշգրիտ կարգավիճակներին: Այս թույլատվության շնորհիվ ծրագիրը կարող է որոշել զանգի իրական կարգավիճակը, արդյոք զանգը ակտիվ է, թե հետին պլանում է, զանգերի ժամանակ տեղի ունեցած սխալները, տվյալների միացման ճշգրիտ կարգավիճակը և տվյալների միացման ժամանակ տեղի ունեցած սխալները:"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"զերծ պահել գրասալիկը քնելուց"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"կանխել հեռախոսի քնի ռեժիմին անցնելը"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Թույլ է տալիս հավելվածին կանխել գրասալիկի` քնի ռեժիմին անցնելը:"</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Փոխել WiMAX-ի կարգավիճակը"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Թույլ է տալիս հավելվածին գրասալիկը միացնել WiMAX ցանցին և անջատվել այդ ցանցից:"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Թույլ է տալիս հավելվածին հեռախոսը միացնել WiMAX ցանցին և անջատել այդ ցանցից:"</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ցանցերի գնահատական"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Ծրագրին թույլ է տալիս դասակարգել ցանցերը և ազդել գրասալիկի նախընտրելի ցանցի ընտրության գործընթացի վրա:"</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Ծրագրին թույլ է տալիս դասակարգել ցանցերը և ազդել հեռախոսի նախընտրելի ցանցի ընտրության գործընթացի վրա:"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"զուգակցվել Bluetooth սարքերի հետ"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Թույլ է տալիս հավելվածին տեսնել Bluetooth-ի կարգավորումը գրասալիկի վրա և կապվել ու կապեր ընդունել զուգակցված սարքերի հետ:"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Թույլ է տալիս հավելվածին տեսնել Bluetooth-ի կարգավորումը հեռախոսի վրա և կապվել ու կապեր ընդունել զուգակցված սարքերի հետ:"</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Թույլ է տալիս հավելվածին առբերել, ուսումնասիրել և մաքրել ծանուցումներն, այդ թվում նաև այլ հավելվածների կողմից գրառվածները:"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"միանալ ծանուցումների ունկնդրիչ ծառայությանը"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Թույլ է տալիս սեփականատիրոջը միանալ ծանուցումները ունկնդրող ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"կապվել պայմանների մատակարարի ծառայությանը"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Թույլ է տալիս սեփականատիրոջը միանալ պայմանների մատակարարների բազային միջերեսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"գործարկել օպերատորի կողմից տրամադրված կազմաձևման ծրագիրը"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Թույլ է տալիս սեփականատիրոջը գործարկել օպերատորի կողմից տրամադրված կազմաձևման ծրագիրը: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"լսել դիտարկումներ ցանցային պայմանների վերաբերյալ"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Հավելվածին թույլ է տալիս լսել դիտարկումներ ցանցային պայմանների վերաբերյալ: Սովորական հավելվածների համար երբեք պետք չի գալիս:"</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"փոփոխել մուտքի սարքի չափաբերումը"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Թույլ է տալիս ծրագրին փոփոխել հպէկրանի չափաբերման կարգավորումները: Սովորական ծրագրերի համար երբեք պետք չի գալու:"</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM հավաստագրերի մատչում"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Ծրագրին թույլ է տալիս տրամադրել և օգտագործել DRM վկայագրեր: Սովորական ծրագրերի համար երբեք պետք չի գալիս:"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Սահմանել գաղտնաբառի կանոնները"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Վերահսկել էկրանի ապակողպման գաղտնաբառերի թույլատրելի երկարությունն ու գրանշանները:"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Վերահսկել էկրանի ապակողպման փորձերը"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Թույլ է տալիս հավելվածին մուտք գործել ստեղնակողպեքով պաշտպանված պահոց:"</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Կառավարել ստեղնակողպեքի ցուցադրումը և թաքցնումը"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Թույլ է տալիս հավելվածին կառավարել ստեղնաշարի պաշտպանիչը:"</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Լսել վստահության կարգավիճակի փոփոխությունները:"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Ծրագրին թույլ է տալիս լսել վստահության կարգավիճակի փոփոխությունները:"</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Կապվել վստահելի գործակալի ծառայությանը"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ծրագրին թույլ է տալիս կապվել վստահելի գործակալի ծառայությանը:"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Փոխազդել թարմացման և վերականգնման համակարգի հետ"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Թույլ է տալիս ծրագրին փոխազդել վերականգնման համակարգի և համակարգի թարմացումների հետ:"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Հպեք երկու անգամ` դիտափոխման կարգավորման համար"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Պաստառ"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Փոխել պաստառը"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Ծանուցման ունկնդիր"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Պայմանների մատակարար"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN-ը ակտիվացված է"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN-ն ակտիվացված է <xliff:g id="APP">%s</xliff:g>-ի կողմից"</string>
<string name="vpn_text" msgid="3011306607126450322">"Հպեք` ցանցի կառավարման համար:"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 6003a23..791d5b9 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> hari"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> hari <xliff:g id="HOURS">%2$d</xliff:g> jam"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> hari <xliff:g id="HOURS">%2$d</xliff:g> jam"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> jam"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> jam <xliff:g id="MINUTES">%2$d</xliff:g> mnt"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> jam <xliff:g id="MINUTES">%2$d</xliff:g> mnt"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> mnt"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> mnt <xliff:g id="SECONDS">%2$d</xliff:g> dtk"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> mnt <xliff:g id="SECONDS">%2$d</xliff:g> dtk"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> dtk"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> dtk"</string>
<string name="untitled" msgid="4638956954852782576">"<Tanpa judul>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinkron"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Terlalu banyak <xliff:g id="CONTENT_TYPE">%s</xliff:g> penghapusan."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Penyimpanan tablet penuh. Hapus beberapa file untuk mengosongkan ruang."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Penyimpanan arloji penuh. Hapus beberapa file untuk mengosongkan ruang."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Penyimpanan di ponsel penuh. Hapus sebagian file untuk mengosongkan ruang."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Jaringan mungkin dipantau"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Oleh pihak ketiga yang tidak dikenal"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Pendering nyala"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Sedang mematikan..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablet Anda akan dimatikan."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Arloji Anda akan dimatikan."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Ponsel Anda akan dimatikan."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Anda ingin mematikannya?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reboot ke mode aman"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode pesawat"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mode pesawat AKTIF"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mode pesawat MATI"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Setelan"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Layanan berbayar"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Lakukan hal yang dapat dikenai biaya."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Pesan Anda"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"mencopot pemasangan pintasan"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Mengizinkan aplikasi menghapus pintasan Layar Utama tanpa tindakan dari pengguna."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"ubah rute panggilan keluar"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Memungkinkan aplikasi melihat nomor yang dihubungi saat melakukan panggilan keluar dengan opsi untuk mengalihkan panggilan ke nomor lain atau membatalkan panggilan sepenuhnya."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Memungkinkan aplikasi memproses panggilan keluar dan mengubah nomor yang akan dipanggil. Izin ini memungkinkan aplikasi memantau, mengalihkan, atau mencegah panggilan keluar."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"terima pesan teks (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Memungkinkan aplikasi menerima dan memproses pesan SMS. Ini artinya aplikasi dapat memantau atau menghapus pesan yang dikirim ke perangkat Anda tanpa menunjukkannya kepada Anda."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"terima pesan teks (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Mengizinkan apl mengambil konten jendela aktif. Apl berbahaya dapat mengambil seluruh konten jendela dan memeriksa semua teksnya kecuali sandi."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"aktifkan aksesibilitas untuk sementara"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Memungkinkan aplikasi mengaktifkan aksesibilitas pada perangkat untuk sementara. Aplikasi berbahaya dapat mengaktifkan aksesibilitas tanpa izin pengguna."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"mengambil token jendela"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Memungkinkan aplikasi mengambil token jendela. Aplikasi berbahaya dapat melakukan interaksi yang tidak sah dengan jendela aplikasi dengan meniru sistem."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"mengambil statistik bingkai"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Memungkinkan aplikasi mengumpulkan statistik bingkai. Aplikasi berbahaya dapat mengamati statistik bingkai jendela dari aplikasi lain."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"mengambil info jendela"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Mengizinkan aplikasi mengambil informasi tentang jendela dari pengelola jendela. Aplikasi berbahaya dapat mengambil informasi yang ditujukan untuk penggunaan sistem internal."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"memfilter acara"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Mengizinkan aplikasi mendaftarkan filter masukan yang memfilter streaming semua acara pengguna sebelum acara dikirimkan. Aplikasi berbahaya dapat mengontrol UI sistem tanpa campur tangan pengguna."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"memperbesar tampilan"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Izinkan aplikasi memperbesar konten tampilan. Aplikasi berbahaya dapat mengubah konten tampilan dengan merender perangkat menjadi tidak dapat digunakan."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"penghentian sebagian"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Letakkan pengelola aktivitas dalam kondisi mati. Tidak melakukan penonaktifan penuh."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"cegah pergantian aplikasi"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Mengizinkan apl menyiarkan pemberitahuan bahwa pesan SMS telah diterima. Apl berbahaya dapat menggunakan ini untuk memalsukan pesan SMS masuk."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"kirim siaran WAP-PUSH-diterima"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Mengizinkan apl menyiarkan pemberitahuan bahwa pesan WAP PUSH telah diterima. Apl berbahaya dapat menggunakan ini untuk memalsukan penerimaan pesan MMS atau diam-diam mengganti konten laman web apa pun dengan varian berbahaya."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"mengirim siaran beri skor jaringan"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Memungkinkan aplikasi menyiarkan pemberitahuan bahwa jaringan perlu diberi skor. Tidak pernah diperlukan untuk aplikasi normal."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"batasi jumlah dari proses yang berjalan"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Mengizinkan apl mengontrol jumlah maksimum proses yang akan berjalan. Tidak pernah diperlukan oleh apl normal."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"paksa aplikasi latar belakang agar menutup"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan Vpn. Tidak pernah diperlukan oleh apl normal."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"mengikat ke wallpaper"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu wallpaper. Tidak pernah diperlukan oleh apl normal."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"mengikat ke pemicu interaksi suara"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Memungkinkan pemegang mengikat antarmuka tingkat tinggi dari layanan interaksi suara. Tidak pernah diperlukan oleh aplikasi normal."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"mengikat ke layar jarak jauh"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Mengizinkan pemegang mengikat ke antarmuka tingkat atas dari layar jarak jauh. Tidak pernah diperlukan untuk aplikasi normal."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"mengikat ke layanan widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan widget. Tidak pernah diperlukan oleh apl normal."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"mengikat ke layanan penyedia rute"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Memungkinkan pemegang mengikat ke penyedia rute terdaftar mana pun. Tidak pernah dibutuhkan untuk aplikasi normal."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan admin perangkat"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Mengizinkan pemegang mengirimkan tujuan kepada administrator perangkat. Tidak pernah diperlukan oleh apl normal."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"mengikat ke masukan TV"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Mengizinkan apl menggunakan pengawasandi media apa pun yang terpasang guna mengawasandikan media untuk diputar."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"kelola kredensial tepercaya"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Izinkan aplikasi memasang dan mencopot pemasangan sertifikat CA sebagai kredensial tepercaya."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"menjalankan aplikasi selama waktu nganggur"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Izin ini memungkinkan sistem Android menjalankan aplikasi di latar belakang saat perangkat tidak digunakan."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"mengikat ke layanan yang sedang menganggur"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Izin ini memungkinkan sistem Android mengikat layanan waktu menganggur aplikasi."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"baca/tulis ke sumber daya yang dimiliki oleh diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Mengizinkan apl membaca dan menulis ke sumber daya apa pun yang dimiliki oleh grup diag; misalnya, file dalam /dev. Izin ini berpotensi memengaruhi kestabilan dan keamanan sistem. Sebaiknya ini HANYA digunakan untuk diagnosis khusus perangkat keras oleh pabrikan atau operator."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"mengaktifkan atau menonaktifkan komponen apl"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Memungkinkan aplikasi membaca informasi profil pribadi yang tersimpan di perangkat Anda, misalnya nama dan informasi kontak Anda. Ini artinya aplikasi dapat mengenali dan mengirim informasi profil Anda ke orang lain."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"ubah kartu kontak Anda"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Memungkinkan aplikasi mengubah atau menambah informasi profil pribadi yang tersimpan di perangkat Anda, seperti nama dan informasi kontak. Ini berarti aplikasi tersebut dapat mengenali Anda dan mengirim informasi profil Anda ke orang lain."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"sensor tubuh (misal: monitor detak jantung)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Memungkinkan aplikasi mengakses data dari sensor yang Anda gunakan untuk mengukur yang terjadi di dalam tubuh, misalnya detak jantung."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"membaca aliran sosial Anda"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Memungkinkan aplikasi mengakses dan menyinkronkan pembaruan sosial dari Anda dan teman. Hati-hati ketika berbagi informasi -- izin ini memungkinkan aplikasi membaca komunikasi antara Anda dan teman di jejaring sosial, terlepas dari kerahasiaan. Catatan: izin ini tidak dapat diberlakukan di semua jejaring sosial."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"menulis ke aliran sosial Anda"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Mengizinkan apl mengontrol fitur telepon perangkat. Apl dengan izin ini dapat mengalihkan jaringan, menyalakan dan mematikan radio ponsel, dan melakukan hal serupa lainnya tanpa pernah memberi tahu Anda."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"baca identitas dan status ponsel"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Memungkinkan aplikasi mengakses fitur telepon perangkat. Izin ini memungkinkan aplikasi menentukan nomor telepon dan ID perangkat, apakah suatu panggilan aktif atau tidak, dan nomor jarak jauh yang tersambung oleh sebuah panggilan."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"membaca keadaan ponsel dengan akurat"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Memungkinkan aplikasi mengakses keadaan ponsel dengan akurat. Izin ini memungkinkan aplikasi menentukan status panggilan yang sebenarnya, apakah panggilan sedang aktif atau di latar belakang, kegagalan panggilan, status sambungan data yang akurat, dan kegagalan sambungan data."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"cegah tablet dari tidur"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"mencegah ponsel menjadi tidak aktif"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Mengizinkan apl mencegah tablet tidur."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Ubah status WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Memungkinkan aplikasi menyambungkan tablet ke dan memutus tablet dari jaringan WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Memungkinkan aplikasi menyambungkan ponsel ke dan memutus ponsel dari jaringan WiMAX."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"memberi skor jaringan"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Memungkinkan aplikasi menilai jaringan dan memengaruhi jaringan mana yang sebaiknya dipilih tablet."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Memungkinkan aplikasi menilai jaringan dan memengaruhi jaringan mana yang sebaiknya dipilih ponsel."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"sandingkan dengan perangkat Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Memungkinkan aplikasi melihat konfigurasi Bluetooth di tablet, dan membuat serta menerima sambungan dengan perangkat yang disandingkan."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Memungkinkan aplikasi melihat konfigurasi Bluetooth di ponsel, dan membuat serta menerima sambungan dengan perangkat yang disandingkan."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Mengizinkan aplikasi mengambil, memeriksa, dan menghapus pemberitahuan, termasuk pemberitahuan yang diposkan oleh aplikasi lain."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"mengikat layanan pendengar pemberitahuan"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Memungkinkan pemegang mengikat antarmuka tingkat teratas dari suatu layanan pendengar pemberitahuan. Tidak pernah diperlukan oleh aplikasi normal."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"mengikat ke layanan penyedia ketentuan"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Memungkinkan pemegang mengikat antarmuka tingkat tinggi dari layanan penyedia ketentuan. Tidak pernah diperlukan oleh aplikasi normal."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"memanggil aplikasi konfigurasi yang disediakan operator"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Memungkinkan pemegang meminta aplikasi konfigurasi yang disediakan operator. Tidak pernah diperlukan aplikasi normal."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"mendengar untuk observasi kondisi jaringan"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Memungkinkan aplikasi mendengar untuk observasi kondisi jaringan. Tidak pernah dibutuhkan oleh aplikasi normal."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"mengubah kalibrasi perangkat masukan"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Memungkinkan aplikasi mengubah parameter kalibrasi layar sentuh. Tidak diperlukan oleh aplikasi normal."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"mengakses sertifikat DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Memungkinkan aplikasi menyediakan dan menggunakan sertifikat DRM. Tidak pernah dibutuhkan untuk aplikasi normal."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Setel aturan sandi"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrol panjang dan karakter yang diizinkan dalam sandi pembuka layar."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Upaya pembukaan kunci layar monitor"</string>
@@ -1016,7 +981,7 @@
<string name="save_password_remember" msgid="6491879678996749466">"Ingat"</string>
<string name="save_password_never" msgid="8274330296785855105">"Jangan"</string>
<string name="open_permission_deny" msgid="7374036708316629800">"Anda tidak memiliki izin untuk membuka laman ini."</string>
- <string name="text_copied" msgid="4985729524670131385">"Teks disalin ke papan klip."</string>
+ <string name="text_copied" msgid="4985729524670131385">"Teks disalin ke clipboard."</string>
<string name="more_item_label" msgid="4650918923083320495">"Lainnya"</string>
<string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
<string name="menu_space_shortcut_label" msgid="2410328639272162537">"spasi"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Mengizinkan aplikasi mengakses pengaman penyimpanan aman."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Kontrol untuk menampilkan dan menyembunyikan pengaman"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Izinkan aplikasi untuk mengontrol pengaman."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Dengarkan perubahan status kepercayaan."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Mengizinkan aplikasi mendengarkan perubahan dalam status kepercayaan."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Ikat ke layanan agen kepercayaan"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Mengizinkan aplikasi mengikat ke layanan agen kepercayaan."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Berinteraksi dengan sistem pemulihan dan pembaruan"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Mengizinkan aplikasi berinteraksi dengan sistem pemulihan dan pembaruan sistem."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Sentuh dua kali untuk mengontrol perbesar/perkecil"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ubah wallpaper"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Pendengar pemberitahuan"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Penyedia ketentuan"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN diaktifkan"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Sentuh untuk mengelola jaringan."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 0e83a2f..a16e5d0 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> giorni"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> giorno <xliff:g id="HOURS">%2$d</xliff:g> ore"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> giorno <xliff:g id="HOURS">%2$d</xliff:g> ora"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> ore"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> ora <xliff:g id="MINUTES">%2$d</xliff:g> minuti"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> ora <xliff:g id="MINUTES">%2$d</xliff:g> minuto"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> minuti"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> minuto <xliff:g id="SECONDS">%2$d</xliff:g> secondi"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> minuto <xliff:g id="SECONDS">%2$d</xliff:g> secondo"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> secondi"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> secondo"</string>
<string name="untitled" msgid="4638956954852782576">"<Senza nome>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizzazione"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Troppe eliminazioni di <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Spazio di archiviazione del tablet esaurito. Elimina alcuni file per liberare spazio."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"La memoria dell\'orologio è piena. Elimina alcuni file per liberare spazio."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Spazio di archiviazione del telefono esaurito. Elimina alcuni file per liberare spazio."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"La rete potrebbe essere monitorata"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Da una terza parte sconosciuta"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Suoneria attiva"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Spegnimento..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Il tablet verrà spento."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"L\'orologio verrà spento."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Il telefono verrà spento."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Spegnere?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Riavvia in modalità provvisoria"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modalità aereo"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modalità aereo attiva"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modalità aereo non attiva"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Impostazioni"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Servizi che prevedono un costo"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Svolgono operazioni che possono comportare un costo."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"I tuoi messaggi"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"eliminazione di scorciatoie"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Consente all\'applicazione di rimuovere le scorciatoie della schermata Home automaticamente."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"reindirizzamento chiamate in uscita"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Consente all\'app di rilevare il numero digitato durante una chiamata in uscita, con la possibilità di reindirizzare la telefonata a un numero diverso o interromperla del tutto."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Consente all\'applicazione di elaborare le chiamate in uscita e di modificare il numero da comporre. Questa autorizzazione consente all\'applicazione di monitorare, reindirizzare o impedire le chiamate in uscita."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"ricezione messaggi di testo (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Consente all\'applicazione di ricevere ed elaborare messaggi SMS. Significa che l\'applicazione potrebbe monitorare o eliminare i messaggi inviati al tuo dispositivo senza mostrarteli."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"ricezione messaggi di testo (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Consente all\'applicazione di recuperare i contenuti della finestra attiva. Le applicazioni dannose potrebbero recuperare l\'intero contenuto della finestra ed esaminare tutto il testo, tranne le password."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"attivazione temporanea dell\'accessibilità"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Consente a un\'applicazione di attivare temporaneamente l\'accessibilità sul dispositivo. Le applicazioni dannose potrebbero attivare l\'accessibilità senza il consenso dell\'utente."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"recupero del token delle finestre"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Consente a un\'applicazione di recuperare il token delle finestre. Le app dannose potrebbero effettuare interazioni non consentite con la finestra dell\'applicazione identificandosi come il sistema."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"recupero di statistiche del frame"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Consente a un\'applicazione di raccogliere statistiche del frame. Le app dannose potrebbero osservare le statistiche del frame relative alle finestre da altre app."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"recupero di informazioni sulle finestre"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Consente a un\'applicazione di recuperare informazioni sulle finestre dalla gestione finestre. Le applicazioni dannose potrebbero recuperare informazioni destinate all\'utilizzo da parte del sistema interno."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtro eventi"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Consente a un\'applicazione di registrare un filtro di ingresso che filtra lo stream di tutti gli eventi degli utenti prima che vengano inviati. Un\'applicazione dannosa potrebbe controllare l\'interfaccia utente del sistema senza l\'intervento dell\'utente."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"ingrandimento dello schermo"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Consente a un\'applicazione di ingrandire i contenuti di uno schermo. Le applicazioni dannose potrebbero trasformare i contenuti dello schermo in modo da rendere inutilizzabile il dispositivo."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"chiusura parziale"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Mette il gestore delle attività in uno stato di chiusura. Non esegue una chiusura completa."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedire commutazione applicazione"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Consente all\'applicazione di trasmettere una notifica che informa della ricezione di un messaggio SMS. Le applicazioni dannose potrebbero farne uso per creare messaggi SMS in arrivo."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"invio broadcast ricevuti tramite WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Consente all\'applicazione di trasmettere una notifica che informa della ricezione di un messaggio WAP PUSH. Le applicazioni dannose potrebbero farne uso per simulare la ricezione di messaggi MMS o per sostituire di nascosto i contenuti di qualsiasi pagina web con varianti dannose."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"invio trasmissione classificazione reti"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Consente all\'app di trasmettere una notifica indicante che le reti devono essere classificate. Opzione non necessaria per le app normali."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"numero limite di processi in esecuzione"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Consente all\'applicazione di controllare il numero massimo di processi che verranno eseguiti. Mai necessaria per le applicazioni normali."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"chiusura forzata applicazioni di background"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Consente l\'associazione all\'interfaccia principale di un servizio VPN. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"associazione a sfondo"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Consente l\'associazione di uno sfondo all\'interfaccia principale. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"collegamento a un servizio di interazione vocale"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di interazione vocale. Non dovrebbe essere mai necessaria per le normali app."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"collega a un display remoto"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un display remoto. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"associazione a un servizio widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Consente l\'associazione all\'interfaccia principale di un servizio widget. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"collegamento a un servizio provider di routing"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Consente al titolare di collegarsi a qualsiasi provider di routing registrato. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interazione con un amministratore dispositivo"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Consente l\'invio di intent a un amministratore del dispositivo. L\'autorizzazione non dovrebbe mai essere necessaria per le normali applicazioni."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"collegamento a ingresso TV"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un ingresso TV. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"aggiungere o rimuovere un amministratore del dispositivo"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Consente al titolare di aggiungere o rimuovere gli amministratori attivi del dispositivo. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"modifica orientamento dello schermo"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Consente all\'applicazione di utilizzare qualsiasi decoder multimediale installato per la decodifica ai fini della riproduzione."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestione di credenziali attendibili"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Consente all\'app di installare e disinstallare certificati CA come credenziali attendibili."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"esegui l\'applicazione nel tempo di inattività del sistema"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Questa autorizzazione consente al sistema Android di eseguire l\'applicazione in background mentre il dispositivo non è in uso."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"associazione a servizi non disponibili"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Questa autorizzazione consente al sistema Android di associarsi ai servizi inattivi di un\'applicazione."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lettura/scrittura risorse di proprietà di diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Consente all\'applicazione di leggere le risorse del gruppo diag e scrivere in esse, ad esempio i file in /dev. Ciò potrebbe influire su stabilità e sicurezza del sistema. Dovrebbe essere utilizzata SOLTANTO per diagnostiche specifiche dell\'hardware effettuate dal produttore o dall\'operatore."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"attivazione/disattivazione componenti applicazioni"</string>
@@ -482,12 +458,10 @@
<string name="permlab_writeCallLog" msgid="8552045664743499354">"scrittura del registro chiamate"</string>
<string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Consente all\'applicazione di modificare il registro chiamate del tablet, inclusi i dati sulle chiamate in arrivo e in uscita. Le applicazioni dannose potrebbero farne uso per cancellare o modificare il registro chiamate."</string>
<string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Consente all\'applicazione di modificare il registro chiamate del telefono, inclusi i dati sulle chiamate in arrivo e in uscita. Le applicazioni dannose potrebbero farne uso per cancellare o modificare il registro chiamate."</string>
- <string name="permlab_readProfile" msgid="4701889852612716678">"lettura scheda contatti pers."</string>
+ <string name="permlab_readProfile" msgid="4701889852612716678">"lettura scheda cont. personale"</string>
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Consente all\'applicazione di leggere informazioni del profilo personale memorizzate sul dispositivo, come il tuo nome e le tue informazioni di contatto. Ciò significa che l\'applicazione può identificarti e inviare le informazioni del tuo profilo ad altri."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"modifica scheda contatti"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Consente all\'applicazione di modificare o aggiungere informazioni ai dati del profilo personale memorizzati sul dispositivo, come il tuo nome e le tue informazioni di contatto. Significa che l\'applicazione può identificarti e inviare le informazioni del tuo profilo ad altri."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"sensori per il corpo (come il cardiofrequenzimetro)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Consente all\'app di accedere a dati derivanti dai sensori utilizzati per rilevare cosa sta accadendo nel tuo corpo, ad esempio la frequenza cardiaca."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"lettura del tuo stream sociale"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Consente all\'applicazione di accedere agli aggiornamenti dei social network tra te e i tuoi amici e di sincronizzarli. Fai attenzione quando condividi informazioni: questa autorizzazione consente all\'applicazione di leggere le comunicazioni tra te e i tuoi amici sui social network, indipendentemente dal livello di riservatezza. Nota. È possibile che questa autorizzazione non sia applicabile su tutti i social network."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"scrittura nel tuo stream sociale"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Consente all\'applicazione di controllare le funzioni telefoniche del dispositivo. Un\'applicazione con questa autorizzazione può cambiare rete, attivare/disattivare il segnale radio del telefono e così via a tua insaputa."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lettura stato e identità telefono"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Consente all\'applicazione di accedere alle funzioni telefoniche del dispositivo. Questa autorizzazione consente all\'applicazione di determinare il numero di telefono e gli ID dei dispositivi, se una chiamata è attiva e il numero remoto connesso da una chiamata."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"rileva gli stati esatti del telefono"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Consente all\'app di accedere allo stato esatto del telefono. Questa autorizzazione consente all\'app di determinare il reale stato della chiamata: se una chiamata è attiva, in sottofondo o non riuscita. Inoltre, rileva l\'esatto stato della connessione dati nonché le connessioni dati non riuscite."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"disattivazione stand-by del tablet"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"disattivazione stand-by del telefono"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Consente all\'applicazione di impedire lo stand-by del tablet."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Modifica stato WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Consente all\'applicazione di connettere/disconnettere il tablet dalle reti WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Consente all\'applicazione di connettere/disconnettere il telefono dalle reti WiMAX."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"valutazione reti"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Consente all\'app di stilare una classifica delle reti e determinare quali di queste il tablet deve prediligere."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Consente all\'app di stilare una classifica delle reti e determinare quali di queste il telefono deve prediligere."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"accoppiamento con dispositivi Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Consente all\'applicazione di visualizzare la configurazione del Bluetooth sul tablet e di stabilire e accettare connessioni con dispositivi accoppiati."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Consente all\'applicazione di visualizzare la configurazione del Bluetooth sul telefono e di stabilire e accettare connessioni con dispositivi accoppiati."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Consente all\'app di recuperare, esaminare e cancellare notifiche, comprese quelle pubblicate da altre app."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincolo a un servizio listener di notifica"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Consente al titolare di vincolarsi all\'interfaccia di primo livello di un servizio listener di notifica. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"collegamento a un servizio provider di condizioni"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio provider di condizioni. Non dovrebbe essere mai necessaria per le normali app."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"richiamo dell\'app di configurazione operatore-provider"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Consente al titolare di richiamare l\'app di configurazione dell\'operatore-provider. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ascolto delle osservazioni sulle condizioni di rete"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Consente a un\'applicazione di ascoltare le osservazioni sulle condizioni di rete. Da non utilizzare mai con app normali."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"modifica calibrazione del dispositivo di immissione"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Consente all\'app di modificare i parametri di calibrazione del touch screen. Questa opzione non deve essere utilizzata per le app normali."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accesso a certificati DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Consente a un\'app di fornire e utilizzare ceritificati DRM. Questa opzione non deve essere utilizzata per app normali."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Impostazione regole password"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlla la lunghezza e i caratteri ammessi nelle password di sblocco dello schermo."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Controllo tentativi di sblocco dello schermo"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Consente a un\'applicazione di accedere all\'archivio sicuro keguard."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Controllo della visualizzazione e dell\'occultamento di keyguard"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Consente a un\'applicazione di controllare keguard."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Rilevamento modifiche dello stato trust."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Consente a un\'applicazione di rilevare le modifiche nello stato trust."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Associazione a un servizio trust agent"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Consente a un\'applicazione di associarsi a un servizio trust agent."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interazione con il sistema di ripristino e aggiornamento"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Consente a un\'applicazione di interagire con il sistema di ripristino e con gli aggiornamenti di sistema."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Tocca due volte per il comando dello zoom"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Sfondo"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambia sfondo"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Listener di notifica"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provider condizioni"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN attiva"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN attivata da <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Tocca per gestire la rete."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 8002d3a..d412dfb 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> ימים"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"יום <xliff:g id="DAYS">%1$d</xliff:g> <xliff:g id="HOURS">%2$d</xliff:g> שע\'"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"יום <xliff:g id="DAYS">%1$d</xliff:g> שעה <xliff:g id="HOURS">%2$d</xliff:g>"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> שעות"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"שעה <xliff:g id="HOURS">%1$d</xliff:g> <xliff:g id="MINUTES">%2$d</xliff:g> דק\'"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> שעות <xliff:g id="MINUTES">%2$d</xliff:g> דק\'"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> דקות"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"דקה <xliff:g id="MINUTES">%1$d</xliff:g> <xliff:g id="SECONDS">%2$d</xliff:g> שנ\'"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"דקה <xliff:g id="MINUTES">%1$d</xliff:g> שנ\' <xliff:g id="SECONDS">%2$d</xliff:g>"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> שניות"</string>
- <string name="durationSecond" msgid="985669622276420331">"שנייה <xliff:g id="SECONDS">%1$d</xliff:g>"</string>
<string name="untitled" msgid="4638956954852782576">">ללא כותרת<"</string>
<string name="ellipsis" msgid="7899829516048813237">"..."</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"סינכרון"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"יש מחיקות רבות מדי של <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"שטח האחסון של הטאבלט מלא. מחק קבצים כדי לפנות מקום."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"שטח האחסון של השעון מלא. מחק כמה קבצים כדי לפנות שטח."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"שטח האחסון של הטלפון מלא. מחק חלק מהקבצים כדי לפנות שטח."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ייתכן שהרשת מנוטרת"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"על ידי צד שלישי לא מוכר"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"צלצול מופעל"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"מכבה..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"הטאבלט שלך יכבה."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"השעון יכבה."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"הטלפון שלך יכובה."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"האם ברצונך לבצע כיבוי?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"אתחל למצב בטוח"</string>
@@ -176,7 +163,7 @@
<string name="global_action_lock" msgid="2844945191792119712">"נעילת מסך"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"כיבוי"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"דיווח על באג"</string>
- <string name="bugreport_title" msgid="2667494803742548533">"שלח דיווח על באג"</string>
+ <string name="bugreport_title" msgid="2667494803742548533">"מלא דיווח על באג"</string>
<string name="bugreport_message" msgid="398447048750350456">"פעולה זו תאסוף מידע על מצב המכשיר הנוכחי שלך על מנת לשלוח אותו כהודעת דוא\"ל. היא תימשך זמן קצר מרגע פתיחת דיווח הבאג ועד שיהיה ניתן לבצע שליחה. התאזר בסבלנות."</string>
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"מצב שקט"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"הקול כבוי"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"מצב טיסה"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"מצב טיסה מופעל"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"מצב טיסה כבוי"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"הגדרות"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"שירותים שעולים כסף"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ביצוע פעולות שעשויות לעלות לך כסף."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"ההודעות שלך"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"הסר התקנה של קיצורי דרך"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"מאפשר לאפליקציה להסיר קיצורי דרך במסך דף הבית ללא התערבות המשתמש."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"ניתוב מחדש של שיחות יוצאות"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"מאפשרת לאפליקציה לראות את המספר המחויג במהלך ביצוע שיחה יוצאת, עם האפשרות להפנות את השיחה למספר אחר או לבטל את השיחה לחלוטין."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"מאפשר לאפליקציה לעבד שיחות יוצאות ולשנות את המספר שיש לחייג. אישור זה מאפשר לאפליקציה לעקוב אחר שיחות יוצאות, לבצע הפניה מחדש שלהן או אף למנוע את ביצוען."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"קבלת הודעות טקסט (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"מאפשר לאפליקציה לקבל ולעבד הודעות SMS. משמעות הדבר היא שהאפליקציה יכולה לעקוב אחר הודעות שנשלחו למכשיר או למחוק אותן מבלי להציג לך אותן."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"קבלת הודעות טקסט (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"מאפשר לאפליקציה לאחזר את התוכן של החלון הפעיל. אפליקציות זדוניות עלולות לאחזר את תוכן החלון כולו ולבחון את כל הטקסט שבו, מלבד סיסמאות."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"הפעלת נגישות זמנית"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"מאפשר לאפליקציה להפעיל באופן זמני נגישות במכשיר. אפליקציות זדוניות עלולות לאפשר נגישות ללא הסכמת משתמש."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"אחזור אסימון חלון"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"מאפשרת לאפליקציה לאחזר את אסימון החלון. אפליקציות זדוניות עשויות לבצע אינטראקציה בלתי מורשית עם חלון האפליקציה, ולהעמיד פנים שהן המערכת."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"אחזור סטטיסטיקת מסגרת"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"מאפשרת לאפליקציה לאסוף סטטיסטיקת מסגרת. אפליקציות זדוניות עשויות לבחון את סטטיסטיקת המסגרת של חלונות מאפליקציות אחרות."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"אחזר מידע חלון"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"מאפשר לאפליקציה לאחזר מידע לגבי החלונות ממנהל החלונות. אפליקציות זדוניות עשויות לאחזר מידע המיועד לשימוש מערכת פנימי."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"סנן אירועים"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"מאפשר לאפליקציה לרשום מסנן קלט שמסנן את הזרם של כל אירועי המשתמש לפני שהם נשלחים. אפליקציה זדונית עשויה לשלוט ב-UI של המערכת ללא התערבות משתמש."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"הגדלת תצוגה"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"מאפשר לאפליקציה להגדיל את התוכן של תצוגה. אפליקציות זדוניות עלולות לשנות את תוכן התצוגה כך שהמכשיר יהפוך לבלתי שמיש."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"כיבוי חלקי"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"מעביר את מנהל הפעילויות למצב כיבוי. לא מבצע כיבוי מלא."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"מנע החלפת אפליקציות"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"מאפשר לאפליקציה לשדר התראה על כך שהתקבלה הודעת SMS. אפליקציות זדוניות עלולות להשתמש בכך כדי לזייף הודעות SMS נכנסות."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"שלח שידור שהתקבל באמצעות WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"מאפשר לאפליקציה לשדר התראה על כך שהתקבלה הודעה מסוג WAP PUSH. אפליקציות זדוניות עלולות להשתמש בכך כדי לזייף קבלה של הודעות MMS או כדי להחליף בחשאי את התוכן של דף אינטרנט כלשהו בגירסאות זדוניות."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"שלח שידור לדירוג רשתות"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"מאפשר לאפליקציה לשדר התראה על כדי שיש לדרג את הרשתות. לא בשימוש עבור אפליקציות רגילות."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"הגבל את מספר התהליכים הפועלים"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"מאפשר לאפליקציה לשלוט על המספר המרבי של תהליכים שיפעלו. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"אילוץ סגירה של אפליקציות ברקע"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"מאפשר למשתמש לבצע איגוד לממשק ברמה עליונה של שירות VPN. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"קשור לטפט"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של טפט. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"איגוד לשירות אינטראקציה קולית"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"מאפשרת לבעלים לאגד לממשק ברמה העליונה של שירות אינטראקציה קולית. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"איגוד לצג מרוחק"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של צג רחוק. לעולם אינה אמורה להיות נחוצה לאפליקציות רגילות."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"הכפפה לשירות Widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של שירות Widget. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"איגוד לשירות של ספק ניתוב"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"מאפשרת לבעלים לאגד לספקי ניתוב רשומים. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"קיים אינטראקציה עם מנהל המכשיר"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"מאפשר למשתמש לשלוח כוונות למנהל התקנים. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"איגוד לקלט טלוויזיה"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"הרשאה זו מאפשרת לאפליקציה להשתמש בכל מפענח מדיה מותקן כדי לבצע פענוח להשמעה."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"ניהול פרטי כניסה מהימנים"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"מאפשרת לאפליקציה להתקין ולהסיר אישורי CA כפרטי כניסה מהימנים."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"הרצת אפליקציה בזמן מצב לא פעיל"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ההרשאה הזו מאפשרת למערכת Android להריץ את האפליקציה ברקע כשהמכשיר אינו בשימוש."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"אגד עם שירותים במצב לא פעיל"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"ההרשאה הזו מאפשרת למערכת Android לאגד אל שירותי אפליקציה במצב לא פעיל."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"קרא/כתוב במשאבים בבעלות diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"מאפשר לאפליקציה לקרוא ולכתוב בכל משאב שבבעלות קבוצת ה-diag; לדוגמה, קבצים ב-/dev. פעולה זו עשויה להשפיע על היציבות והאבטחה של המערכת. אפשרות זו צריכה לשמש רק את היצרן או המפעיל, לצורך אבחונים ספציפיים לחומרה."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"הפעלה או השבתה של רכיבי אפליקציות"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"מאפשר לאפליקציה לקרוא פרטים מהפרופיל האישי המאוחסנים במכשיר, כגון שמך ופרטי אנשי הקשר שלך. משמעות הדבר שהאפליקציה תוכל לזהות אותך ולשלוח את פרטי הפרופיל שלך לאנשים אחרים."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"שינוי כרטיס איש הקשר שלך"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"מאפשר לאפליקציה לשנות או להוסיף נתונים לפרטי הפרופיל האישי המאוחסנים במכשיר, כגון שמך ופרטי הקשר שלך. משמעות הדבר שהאפליקציה יכולה לזהות אותך ועשוי לשלוח את פרטי הפרופיל שלך לאנשים אחרים."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"חיישני גוף (כמו מוניטורים עבור קצב לב)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"מאפשר לאפליקציה לגשת לנתוני חיישנים שבהם אתה משתמש כדי למדוד פעילות המתרחשת בתוך הגוף, כמו קצב לב."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"קריאת הזרם החברתי שלך"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"מאפשר לאפליקציה גישה ויכולת סנכרון של עדכונים חברתיים שאתה וחבריך מבצעים. היזהר בעת שיתוף מידע -- הדבר מתיר לאפליקציה לקרוא התכתבויות בינך ובין חבריך ברשתות חברתיות, ללא התחשבות בסודיות. שים לב: ייתכן שאישור זה לא נאכף בכל הרשתות החברתיות."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"כתיבה בזרם החברתי שלך"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"מאפשר לאפליקציה לשלוט בתכונות הטלפון של המכשיר. אפליקציה בעלת הרשאה זו יכולה לעבור בין רשתות, להפעיל ולכבות את הרדיו בטלפון ולבצע פעולות נוספות דומות מבלי ליידע אותך."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"קריאת הסטטוס והזהות של הטלפון"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"מאפשר לאפליקציה לגשת לתכונות הטלפון של המכשיר. אישור זה מתיר לאפליקציה לגלות את מספר הטלפון ואת זיהויי המכשיר, האם שיחה פעילה ואת המספר המרוחק המחובר באמצעות שיחה."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"קריאת מצבי טלפון מדויקים"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"מאפשר לאפליקציה לגשת למצבי הטלפון המדויקים. ההרשאה הזו מאפשרית לאפליקציה לדעת מה סטטוס השיחה בפועל, האם שיחה פעילה או ברקע, כשלי שיחות, סטטוס מדויק על חיבור נתונים וכשלים בחיבור נתונים."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"מנע מהטאבלט לעבור למצב שינה"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"מניעת מעבר הטלפון למצב שינה"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"מאפשר לאפליקציה למנוע מהטאבלט לעבור למצב שינה."</string>
@@ -631,7 +605,7 @@
<string name="permlab_accessNetworkState" msgid="4951027964348974773">"הצג חיבורי רשת"</string>
<string name="permdesc_accessNetworkState" msgid="8318964424675960975">"מאפשר לאפליקציה להציג מידע לגבי חיבורי רשת, למשל, אילו רשתות קיימות ומחוברות."</string>
<string name="permlab_createNetworkSockets" msgid="8018758136404323658">"גישת רשת מלאה"</string>
- <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"מאפשר לאפליקציה ליצור Sockets ולהשתמש בפרוטוקולי רשת מותאמים אישית. הדפדפן, כמו אפליקציות אחרות, מספק אמצעים לשליחת נתונים לאינטרנט, כך שאישור זה אינו נחוץ לשליחת נתונים לאינטרנט."</string>
+ <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"מאפשר לאפליקציה ליצור Sockets ולהשתמש בפרוטוקולי רשת מותאמים אישית. הדפדפן ואפליקציות אחרות מספקות אמצעים לשליחת נתונים לאינטרנט, כך שאישור זה אינו נחוץ לשליחת נתונים לאינטרנט."</string>
<string name="permlab_writeApnSettings" msgid="505660159675751896">"שנה/עכב הגדרות רשת ותנועה"</string>
<string name="permdesc_writeApnSettings" msgid="5333798886412714193">"מאפשר לאפליקציה לשנות את הגדרות הרשת ולעכב ולבדוק את כל תנועת הרשת, לדוגמה, לשנות את ה-proxy והיציאה של כל רשת APN. אפליקציות זדוניות עלולות לעקוב אחר חבילות רשת, לבצע הפניה מחדש שלהן או לשנות אותן, ללא ידיעתך."</string>
<string name="permlab_changeNetworkState" msgid="958884291454327309">"שנה את קישוריות הרשת"</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"שנה את מצב WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"מאפשר לאפליקציה לחבר את הטאבלט לרשתות WiMAX ולהתנתק מהן."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"מאפשר לאפליקציה לחבר את הטלפון לרשתות WiMAX ולהתנתק מהן."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"דרג רשתות"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"מאפשר ליישום לדרג רשתות ולהשפיע על הרשתות שאותן הטאבלט יעדיף."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"מאפשר ליישום לדרג רשתות ולהשפיע על הרשתות שאותן הטלפון יעדיף."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"התאמה למכשירי Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"מאפשר לאפליקציה להציג את תצורת ה-Bluetooth בטאבלט, וכן ליצור ולקבל חיבורים עם מכשירים מותאמים."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"מאפשר לאפליקציה להציג את תצורת ה-Bluetooth בטלפון, וכן ליצור ולקבל חיבורים עם מכשירים מותאמים."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"מאפשר לאפליקציה לאחזר, לבדוק ולמחוק התראות, כולל כאלה שפורסמו על ידי אפליקציות אחרות."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"איגוד לשירות של מאזין להתראות"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של שירות מאזין להתראות. הרשאה זו אף פעם אינה נחוצה לאפליקציות רגילים."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"איגוד לשירות ספק תנאי"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"מאפשרת לבעלים לאגד לממשק ברמה העליונה של שירות ספק תנאי. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"הפעלה של אפליקציית תצורה שסופקה על ידי ספק"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ההרשאה הזו מאפשרת לבעלים להפעיל את אפליקציית התצורה שסופקה על ידי ספק. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"קליטת מעקב אחר תנאי רשת"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"מאפשרת לאפליקציה לקלוט מעקב אחר תנאי רשת. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"שינוי הכיול של מכשיר קלט"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"מאפשרת לאפליקציה לשנות את פרמטרי הכיול של מסך המגע. לעולם לא אמורה להיות נחוצה לאפליקציות רגילות."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"גישה אל אישורי DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"מאפשרת לאפליקציה לנהל תצורה של אישורי DRM ולהשתמש בהם. לעולם לא אמורה להיות נחוצה עבור אפליקציה רגילה."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"הגדר כללי סיסמה"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"שלוט באורך ובתווים המותרים בסיסמאות לביטול נעילת מסך."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"עקוב אחר ניסיונות לביטול נעילת מסך"</string>
@@ -1144,7 +1109,7 @@
<string name="cut" msgid="3092569408438626261">"חתוך"</string>
<string name="copy" msgid="2681946229533511987">"העתק"</string>
<string name="paste" msgid="5629880836805036433">"הדבק"</string>
- <string name="replace" msgid="5781686059063148930">"החלף..."</string>
+ <string name="replace" msgid="5781686059063148930">"להחליף..."</string>
<string name="delete" msgid="6098684844021697789">"מחק"</string>
<string name="copyUrl" msgid="2538211579596067402">"העתק כתובת אתר"</string>
<string name="selectTextMode" msgid="1018691815143165326">"בחר טקסט"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"מאפשר לאפליקציה לגשת לאחסון המוגן באמצעות מפתח."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"שלוט בהצגה והסתרה של מגן המקלדת"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"מאפשר לאפליקציה לשלוט במגן המקלדת."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"חיפוש שינויים במצב אמון."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"מאפשר לאפליקציה לחפש שינויים במצב אמון."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"איגוד אל שירות סוכן אמון"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"מאפשר לאפליקציה לאגוד אל שירות סוכן אמון."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"אינטראקציה עם מערכת שחזור ועדכונים"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"מאפשרת לאפליקציה ליצור אינטראקציה עם מערכת השחזור ועדכוני מערכת."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"גע פעמיים לבקרת מרחק מתצוגה"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"טפט"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"שנה טפט"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"מאזין להתראות"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ספק תנאי"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN מופעל"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN מופעל על ידי <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"גע כדי לנהל את הרשת."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 704b935..58495e8 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g>日"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g>日<xliff:g id="HOURS">%2$d</xliff:g>時間"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g>日<xliff:g id="HOURS">%2$d</xliff:g>時間"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g>時間"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g>時間<xliff:g id="MINUTES">%2$d</xliff:g>分"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g>時間<xliff:g id="MINUTES">%2$d</xliff:g>分"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g>分"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g>分<xliff:g id="SECONDS">%2$d</xliff:g>秒"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g>分<xliff:g id="SECONDS">%2$d</xliff:g>秒"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g>秒"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g>秒"</string>
<string name="untitled" msgid="4638956954852782576">"<新規>"</string>
<string name="ellipsis" msgid="7899829516048813237">"..."</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"同期"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g>での削除が多すぎます。"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"タブレットのストレージに空き領域がありません。ファイルを削除して空き領域を確保してください。"</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"ウォッチのストレージに空き領域がありません。ファイルを削除して空き領域を確保してください。"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"端末のストレージに空き領域がありません。ファイルを削除して空き領域を確保してください。"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ネットワークが監視される場合があります"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"不明な第三者"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"着信音オン"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"シャットダウン中..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"タブレットの電源をOFFにします。"</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"ウォッチの電源をOFFにします。"</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"携帯電話の電源を切ります。"</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"シャットダウンしますか?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"再起動してセーフモードに変更"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"機内モード"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"機内モードON"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"機内モードOFF"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"設定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"料金の発生するサービス"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"料金発生の可能性がある操作を実行します。"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"送受信したメッセージ"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"ショートカットのアンインストール"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"ユーザー操作なしでホーム画面のショートカットを削除することをアプリに許可します。"</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"発信先の変更"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"発信を別の番号に転送するか完全に中止するオプションで、発信中にダイヤルされた番号にアクセスすることをアプリに許可します。"</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"通話の発信とダイヤルする番号の変更をアプリに許可します。これにより、アプリが発信を監視、転送、阻止できるようになります。"</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"テキストメッセージ(SMS)の受信"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"SMSメッセージの受信と処理をアプリに許可します。これにより、アプリが端末に届いたメッセージを表示することなく監視または削除できるようになります。"</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"テキストメッセージ(MMS)の受信"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"作業中のウィンドウの内容を取得することをアプリに許可します。この許可を悪意のあるアプリに利用されると、ウィンドウの内容全体が取得されてパスワード以外のテキストがすべてチェックされる恐れがあります。"</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"ユーザー補助を一時的に有効にする"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"この端末のユーザー補助を一時的に有効にすることをアプリに許可します。悪意のあるアプリはユーザーの同意を得ずにユーザー補助を有効にする場合があります。"</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"ウィンドウトークンの取得"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"ウィンドウトークンの取得をアプリに許可します。この許可を悪意のあるアプリに利用されると、システムを装ったアプリケーションウィンドウで不正な操作が実行される恐れがあります。"</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"フレーム統計情報の取得"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"フレーム統計情報の収集をアプリに許可します。この許可を悪意のあるアプリに利用されると、他のアプリからウィンドウのフレーム統計情報を監視される恐れがあります。"</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"ウィンドウ情報の取得"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"ウィンドウマネージャからウィンドウに関する情報を取得することをアプリに許可します。悪意のあるアプリが内部システムの利用を目的に情報を取得する恐れがあります。"</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"イベントのフィルタリング"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"すべてのユーザーイベントが送られる前にストリームをフィルタリングする入力フィルタを登録することをアプリに許可します。悪意のあるアプリがユーザーの操作なしでシステムUIを制御する恐れがあります。"</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"表示の拡大"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"表示内容を拡大することをアプリに許可します。悪意のあるアプリが、端末を使用できなくなるように表示内容を変換する恐れがあります。"</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"部分的にシャットダウンする"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"アクティビティマネージャをシャットダウン状態にします。完全なシャットダウンは実行しません。"</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"アプリケーションの切り替えを禁止する"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"SMSメッセージの受信通知の配信をアプリに許可します。この許可を悪意のあるアプリケーションに利用されると、受信SMSメッセージが偽造される恐れがあります。"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH受信ブロードキャストの送信"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"WAP PUSHメッセージの受信通知を配信することをアプリに許可します。この許可を悪意のあるアプリに利用されると、MMSメッセージの受信確認が偽造されたりウェブページのコンテンツが悪意のあるコンテンツに密かに置き換えられたりする恐れがあります。"</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ネットワークスコアのブロードキャスト送信"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"ネットワークのスコアリングが必要であるという通知をブロードキャスト送信することをアプリに許可します。通常のアプリでは不要です。"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"実行中のプロセスの数を制限"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"実行するプロセスの上限数を制御することをアプリに許可します。通常のアプリでは不要です。"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"バックグラウンドのアプリの強制終了"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"VPNサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"壁紙にバインド"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"壁紙のトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"音声対話サービスへのバインド"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"音声対話サービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"リモートディスプレイへのバインド"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"リモートディスプレイのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ウィジェットサービスにバインド"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ウィジェットサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"ルートプロバイダサービスへのバインド"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"登録済みのルートプロバイダにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"デバイス管理者との通信"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"デバイス管理者へのintentの送信を所有者に許可します。通常のアプリでは不要です。"</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"テレビの入力へのバインド"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"テレビの入力のトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"端末の管理者の追加または削除"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"有効な端末の管理者を追加または削除することを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"画面の向きの変更"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"インストール済みのメディアデコーダーを使用して再生用にデコードすることをアプリに許可します。"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"信頼できる認証情報の管理"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"CA証明書を信頼できる認証情報としてインストールしたりアンインストールしたりすることをアプリに許可します。"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"アイドル状態でのアプリの実行"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"この権限により、端末が使用中でない場合でもAndroidシステムがバックグラウンドでアプリを実行できるようになります。"</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"アイドルサービスへのバインディング"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"この許可により、Androidシステムはアプリのアイドルサービスにバインディングできるようになります。"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"diagが所有するリソースの読み書き"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"diagグループが所有するリソース(/dev内のファイルなど)の読み書きをアプリに許可します。許可すると、システムの安定性とセキュリティに影響が生じる可能性があります。メーカー/通信事業者によるハードウェア固有の診断以外には使用しないでください。"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"アプリのコンポーネントの有効/無効化"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"端末に保存されている個人のプロフィール情報(名前、連絡先情報など)の読み取りをアプリに許可します。これにより、アプリがユーザーの身元を特定できるようになり、プロフィール情報を第三者に転送する可能性があります。"</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"自分の連絡先カードの変更"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"端末に保存されている個人のプロフィール情報(名前、連絡先情報など)の変更と追加をアプリに許可します。これにより、アプリがユーザーの身元を特定できるようになり、プロフィール情報を第三者に転送する可能性があります。"</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"ボディーセンサー(心拍数モニターなど)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"心拍数など、体内の変化の測定に使用するセンサーからのデータにアクセスすることをアプリに許可します。"</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"ソーシャルストリームを読む"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"あなたや友だちのソーシャル更新情報へのアクセスと同期をアプリに許可します。情報の共有は慎重に行ってください。これを許可すると、あなたと友だちがソーシャルネットワークで行ったやり取りを、機密性に関係なくアプリから読み取ることができるようになります。注: この許可は、一部のソーシャルネットワークでは適用されない場合があります。"</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"ソーシャルストリームに書く"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"端末の電話機能の制御をアプリに許可します。許可すると、アプリではユーザーに通知なくネットワークの切り替え、無線通信のON/OFFなどを行えるようになります。"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"端末のステータスとIDの読み取り"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"端末の電話機能へのアクセスをアプリに許可します。これにより、電話番号、端末ID、通話中かどうか、通話相手の電話番号をアプリから特定できるようになります。"</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"正確な電話ステータスの読み取り"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"正確な電話ステータスにアクセスすることをアプリに許可します。これにより、実際の発信ステータス(発信がアクティブか、バックグラウンドか)、発信エラー、正確なデータ接続ステータス、データ接続エラーをアプリから特定できるようになります。"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"タブレットのスリープを無効化"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"端末のスリープを無効にする"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"タブレットのスリープを無効にすることをアプリに許可します。"</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX状態の変更"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"タブレットのWiMAXネットワークへの接続と切断をアプリに許可します。"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"携帯端末のWiMAXネットワークへの接続と切断をアプリに許可します。"</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ネットワークスコア"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"ネットワークを順位付けし、タブレットでのネットワークの優先順位に反映することをアプリに許可します。"</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"ネットワークを順位付けし、携帯電話でのネットワークの優先順位に反映することをアプリに許可します。"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetoothデバイスのペアの設定"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"タブレットのBluetooth設定を表示すること、ペアの端末に接続すること/ペアの端末からの接続を受け入れることをアプリに許可します。"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"携帯端末のBluetooth設定を表示すること、ペアの端末に接続すること/ペアの端末からの接続を受け入れることをアプリに許可します。"</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"通知(他のアプリから投稿されたものも含む)を取得、調査、クリアすることをアプリに許可します。"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"通知リスナーサービスにバインド"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"通知リスナーサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"コンディションプロバイダサービスへのバインド"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"コンディションプロバイダサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"携帯通信会社が提供する設定アプリの呼び出し"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"携帯通信会社が提供する設定アプリを呼び出すことを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ネットワーク状況監視のためのリッスン"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ネットワーク状況を監視するためリッスンすることをアプリに許可します。通常のアプリで必要になることはありません。"</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"入力デバイスの調整を変更"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"タッチスクリーンの調整パラメータの変更をアプリに許可します。通常のアプリでは必要ありません。"</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM証明書へのアクセス権"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"DRM証明書のプロビジョニングと使用をアプリに許可します。通常のアプリでは不要です。"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"パスワードルールの設定"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"画面ロック解除パスワードの長さと使用できる文字を制御します。"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"画面ロック解除試行の監視"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"キーガードセキュアストレージへのアクセスをアプリに許可する"</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"キーガードの表示/非表示の制御"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"キーガードの制御をアプリに許可します。"</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"信頼状態の変更をリッスン"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"信頼状態の変更をリッスンすることをアプリに許可します。"</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"信頼できるエージェントサービスへのバインド"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"信頼できるエージェントサービスにバインドすることをアプリに許可します。"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"アップデートと回復システムへのアクセス"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"回復システムとシステムアップデートへのアクセスをアプリに許可します。"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"ダブルタップでズームコントロール"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"壁紙"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"壁紙を変更"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知リスナー"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"コンディションプロバイダ"</string>
<string name="vpn_title" msgid="19615213552042827">"VPNが有効になりました"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPNが<xliff:g id="APP">%s</xliff:g>により有効化されました"</string>
<string name="vpn_text" msgid="3011306607126450322">"タップしてネットワークを管理します。"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 0c179c0..c82b606 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"ტბაიტი"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> დღე"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> დღე <xliff:g id="HOURS">%2$d</xliff:g> სთ"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> დღე <xliff:g id="HOURS">%2$d</xliff:g> სთ"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> სთ"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> სთ <xliff:g id="MINUTES">%2$d</xliff:g> წთ"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> სთ <xliff:g id="MINUTES">%2$d</xliff:g> წთ"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> წთ"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> წთ <xliff:g id="SECONDS">%2$d</xliff:g> წმ"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> წთ <xliff:g id="SECONDS">%2$d</xliff:g> წმ"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> წმ"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> წმ"</string>
<string name="untitled" msgid="4638956954852782576">"უსათაურო"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"სინქრონიზაცია"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g>-ის ძალიან ბევრი წაშლილები."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"ტაბლეტის მეხსიერება გავსებულია. ადგილის გასათავისუფლებლად წაშალეთ ფაილების ნაწილი."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"საათის მეხსიერება გავსებულია. ადგილის გასათავისუფლებლად წაშალეთ ფაილების ნაწილი."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"ტელეფონის მეხსიერება გავსებულია. ადგილის გასათავისუფლებლად წაშალეთ ფაილების ნაწილი."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"შესაძლოა ქსელი მონიტორინგის ქვეშ იმყოფება"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"უცნობი მესამე მხარის მიერ"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"ზარი ჩართულია"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"გამორთვა…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"თქვენი ტაბლეტი გაითიშება."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"თქვენი საათი გაითიშება."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"თქვენი ტელეფონი გაითიშება."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"გსურთ გამორთვა?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"უსაფრთხო რეჟიმის ჩატვირთვა"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"თვითმფრინავის რეჟიმი"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"თვითმფრინავის რეჟიმი ჩართულია."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"თვითმფრინავის რეჟიმი გამორთულია."</string>
- <string name="global_action_settings" msgid="1756531602592545966">"პარამეტრები"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"სერვისები, რომელშიც ფულის გადახდა გიწევთ"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ისეთი აქტივობების განხორციელება, რომლებშიც ფულის გადახდა მოგიწევთ."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"თქვენი შეტყობინებები"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"მალსახმობების წაშლა"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"მთავარ ეკრანზე აპლიკაციისთვის მალსახმობების დამოუკიდებლად წაშლის უფლების მიცემა."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"გამავალი ზარების გადამისამართება"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"საშუალებას აძლევს აპს გამავალი ზარის დროს დაინახონ ზარის მიმღების ნომერი, ზარის სხვა მისამართზე გადამისამართებით ან ზარის საერთოდ შეწყვეტის საშუალებით."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"აპს შეეძლება გამავალი ზარების დამუშავება და ასაკრეფი ნომრის შეცვლა. ეს უფლება აპს აძლევს შესაძლებლობას აკონტროლოს, გადაამისამართოს ან აღკვეთოს გამავალი ზარები."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"ტექსტური შეტყობინებების (SMS) მიღება"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"აპს შეეძლება SMS შეტყობინებების მიღება და დამუშავება. ეს ნიშნავს, რომ აპს შეეძლება თქვენ მოწყობილობაზე გამოგზავნილი შეტყობინებების მონიტორინგი და მათი წაშლა თქვენთვის ჩვენების გარეშე."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"ტექსტური შეტყობინებების (MMS) მიღება"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"აპს შეეძლება აქტიური ფანჯრიდან კონტენტის მოძიება. მავნე აპებს შეუძლიათ ფანჯრის სრული კონტენტის მოძიება და ყველა ტექსტის წაკითხვა პაროლების გარდა."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"მარტივი წვდომის დროებით გააქტიურება"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"აპს შეეძლება მოწყობილობაზე გამარტივებული რეჟიმის ჩართვა. მავნე აპებს შეეძლებათ ამ რეჟიმის ჩართვა მომხმარებლის გაფრთხილების გარეშე."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"ფანჯრის ჟეტონის მოძიება"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"ნებას რთავს აპლიკაციას მოიძიოს ფანჯრის ჟეტონი. მავნე აპებს შეუძლია აპლიკაციის ფანჯარასთან არაავტორიზებული ინტერაქცია განახორციელოს და თავი სისტემად წარმოაჩინოს."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"ჩარჩოს სტატისტიკის მოძიება"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"ნებას რთავს აპლიკაციას შეაგროვოს ჩარჩოს სტატისტიკა. მავნე აპებმა შესაძლოა ფანჯრების ჩარჩოს სტატისტიკის მონიტორინგი განახორციელოს სხვა აპებიდან."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"ფანჯრის ინფორმაციის მოძიება"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"აპს შეეძლება ფანჯრების მენეჯერის მეშვეობით ფანჯრების შესახებ ინფორმაციის მოპოვება. მავნე აპლიკაციებს შეეძლებათ ისეთი ინფორმაციის მოპოვება, რომელიც შიდა სისტემური მოხმარებისთვის არის განკუთვნილი."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"ღონისძიებების გაფილტვრა"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"აპლიკაციას შეეძლება რეგისტრაცია შეტანის ფილტრებისა, რომლებიც ასუფთავებენ მომხმარებლის ღონისძიების ყველა დინებას. მავნე აპმა შესაძლოა ეს ფუნქცია სისტემის UI კონტროლისთვის გამოიყენოს, მომხმარებლის ინტერვენციის გარეშე."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"ეკრანის გადიდება"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"აპლიკაციას შეეძლება, შეცვალოს დისპლეის კონტენტი. მავნე აპებმა შეიძლება იმგვარად გარდაქმნან დისპლეის კონტენტი, რომ მოწყობილობა გამოუსადეგარი გახდეს."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"ნაწილობრივი გამორთვა"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"აქტივობების მენეჯერს გათიშვის რეჟიმში აყენებს. სრულ გათიშვას არ ახორციელებს."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"აპის გადართვებისგან დაცვა"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"აპს საშუალებას აძლევს გააგზავნოს შეტყობინება SMS შეტყობინების მიღების თაობაზე. მავნე აპლიკაციებში ეს ფუნქცია შეიძლება გამოყენებული იქნას SMS შეტყობინებების მიღების იმიტაციიისათვის."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH-ით მიღებული სამაუწყებლო შეტყობინების გაგზავნა"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"აპს შეეძლება, გაგზავნოს შეტყობინება WAP PUSH შეტყობინების მიღების თაობაზე. მავნე აპებმა ეს შეიძლება გამოიყენონ MMS შეტყობინების მიღების გასაყალბებლად ან ნებისმიერი ვებგვერდის კონტენტის სახიფათო ვარიანტებით ჩუმად ჩასანაცვლებლად."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ქსელის შეფასებების მაუწყებლობის გაგზავნა"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"აპს ნებას რთავს გადასცეს შეტყობინება, რომ ქსელები შეფასებას საჭიროებს. ჩვეულებრივ აპებს ეს არასოდეს ჭირდება."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"მიმდინარე პროცესების რაოდენობის ლიმიტი"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"აპს შეეძლება, გააკონტროლოს მიმდინარე პროცესების მაქსიმალური რაოდენობა. ჩვეულებრივ აპებში არასდროს არის საჭირო."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"უკანა ფონის აპის იძულებით დახურვა"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"აპს შეეძლება Vpn სერვისის ზედა დონის ინტერფეისთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"ფონზე მიჭედება"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"მფლობელს შეეძლება ფონის ზედა დონის ინტერფეისთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"ხმის ინტერაქტორთან შეკავშირება"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"მფლობელს შეეძლება შეკავშირდეს ხმის ინტერაქციის სერვისების ზედა დონის ინტერფეისთან. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დასჭირდეს."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"დისტანციურ მონიტორზე მიბმა"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"მფლობელს შეეძლება მიებას დისტანციურ მონიტორის ზედა დონის ინტერფეისს. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დაჭირდეს."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ვიჯეტ სერვისთან დაკავშირება"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"აპს შეეძლება ზედა დონის ინტერფეისის ვიჯეტთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"მარშრუტის სერვისის პროვაიდერთან შეკავშირება"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"საშუალებას აძლევს მფლობელს შეკავშირდეს მარშრუტების ნებისმიერ პროვაიდერთან. ჩვეულებრივ აპებს უმეტეს შემთხვევაში არ დაჭირდება."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"მოწყობილობის ადმინთან ინტერაქცია"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"აპს შეეძლება მოწყობილობის ადმინისტრატორისთვის intent ობიექტების გაგზავნა. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"TV შეყვანასთან მიბმა"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"აპს შეეძლება TV შეყვანის ზედა დონის ინტერფეისთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"მოწყობილობის ადმინისტრატორს დამატება ან ამოშლა"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"საშუალებას აძლევს მფლობელს დაამატოს ან ამოშალოს მოწყობილობის აქტიური ადმინისტრატორები. ჩვეულებრივ აპებს, ალბათ, არასოდეს დაჭირდება"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"ეკრანის ორიენტაციის შეცვლა"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"აპს დასაკრავად შეეძლება გამოიყენოს ნებისმიერი დაყენებული მედია დეკოდერი."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"სანდო მტკიცებულებების მართვა"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"აპისთვის ნების დართვა, მოახდინოს CA სერტიფიკატების სანდო მტკიცებულებებად ინსტალაცია და დეინსტალაცია."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"უქმე მდგომარეობისას აპლიკაციის გაშვება"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ეს უფლება Android-ის სისტემას უფლებას ანიჭებს ფონურად გაუშვას აპლიკაცია, როდესაც მოწყობილობა არ გამოიყენება."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"უქმე სერვისებზე მიბმა"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"ეს უფლება საშუალებას აძლევს Android-ის სისტემას, განახორციელოს აპლიკაციის უქმე სერვისების მიბმა."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"სისტემის დიაგნოსტიკის რესურსებში წაკითხვა/ჩაწერის უფლება"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"აპს შეეძლება, წაიკითხოს ან ჩაწეროს ნებისმიერ რესურსში, რომელიც დიაგნოსტიკის ჯგუფს ეკუთვნის, მაგალითად, ფაილები /dev-ში. ამან შესაძლოა იმოქმედოს სისტემის სტაბილურობასა და უსაფრთხოებაზე. მისი გამოყენება მხოლოდ მწარმოებლის ან ოპერატორის მიერ ტექნიკის სპეციფიკური დიაგნოსტიკისთვის უნდა მოხდეს."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"აპის კომპონენტების ჩართვა ან გამორთვა"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"აპს შეეძლება მოწყობილობაზე შენახული პირადი პროფილის ინფორმაციის წაკითხვა, მაგალითად, თქვენი სახელისა და საკონტაქტო ინფორმაციის. ეს ნიშნავს, რომ აპს შეუძლია თქვენი იდენტიფიცირება და თქვენი პირადი ინფორმაციის სხვებისთვის გაგზავნა."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"თქვენი საკონტაქტო ინფორმაციის შეცვლა"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"აპს შეეძლება მოწყობილობაზე შენახული პირადი პროფილის ინფორმაციის შეცვლა ან დამატება, მაგალითად, თქვენი სახელისა და საკონტაქტო ინფორმაციის. ეს ნიშნავს, რომ აპს შეუძლია თქვენი იდენტიფიცირება და თქვენი პირადი ინფორმაციის სხვებისთვის გაგზავნა."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"სხეულის სენსორები (მაგ. გულისცემის მონიტორები)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"საშუალებას აძლევს აპს იქონიოს წვდომა თქვენ მიერ გამოყენებული სენსორებიდან, რათა გაზომოთ, რა ხდება თქვენ სხეულში, მაგ. გულის ცემის რითმი."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"სოციალური ნაკადის წაკითხვა"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"აპს შეეძლება თქვენი და თქვენი მეგობრების სოციალური განახლებებთან წვდომა და სინქრონიზაცია. ინფორმაციის გაზიარებისას იყავით ფრთხიად - აპს ექნება შესაძლებლობა, რომ წაიკითხოს სოციალურ ქსელებში კომუნიკაცია თქვენსა და თქვენს მეგობრებს შორის კონფიდენციალურობის მიუხედავად. შენიშვნა: ეს უფლება შესაძლოა ვერ იყოს გამოყენებული ყველა სოციალურ ქსელში."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"თქვენს სოციალურ მაუწყებლობაზე დაწერა"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"აპს შეეძლება აკონტროლოს მოწყობილობაზე ტელეფონის ფუნქციები. ამ უფლების მქონე აპს შეუძლია ქსელების გადართვა, ტელეფონის რადიოს ჩართვა და გამორთვა, მომხმარებლისათვის შეტყობინების გარეშე."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ტელეფონის სტატუსისა და იდენტობის წაკითხვა"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"აპს შეეძლება ჰქონდეს წვდომა მოწყობილობის სატელეფონო ფუნქციებზე. აპმა მსგავსი უფლებით შეძლებს დაადგინოს ტელეფონის ნომერი, მისი სერიული გამოცემა, აქტიური ზარი, დაკავშირებული ნომერი და მსგავსი."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ტელეფონის ზუსტი მდგომარეობების დადგენა"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"ანიჭებს აპს ტელეფონის ზუსტ მდგომარეობაზე წვდომას. ეს უფლება საშუალებას აძლევს აპს შეიტყოს ინფორმაცია ზარის რეალურ სტატუსზე, აქტიურია ზარი თუ უკანა ფონზეა, ვერ განხორციელებული ზარები, მონაცემთა გადაცემის ზუსტი სტატუსი და ვერ განხორციელებული მონაცემთა კავშირები."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"დაიცავით ტაბლეტი დაძინებისგან"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ტელეფონის ძილის რეჟიმში გადასვლის აღკვეთა"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"აპს შეეძლება ხელი შეუშალოს ტაბლეტის დაძინებას."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX მდგომარეობის შეცვლა"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"აპს შეეძლება, დაუკავშიროს და გამოაერთოს ტაბლეტი WiMAX ქსელებიდან."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"აპს შეეძლება, დაუკავშიროს და გამოაერთოს ტელეფონი WiMAX ქსელებიდან."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ქსელების შეფასება"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"აპს ნებას რთავს შეაფასოს ქსელები და იქონიოს ზეგავლენა, თუ რომელი ქსელი ამჯობინოს ტაბლეტმა."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"აპს ნებას რთავს შეაფასოს ქსელები და იქონიოს ზეგავლენა, თუ რომელი ქსელი ამჯობინოს ტელეფონმა."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetooth მოწყობილობებთან დაწყვილება"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"აპს შეეძლება, ნახოს Bluetooth-ის კონფიგურაცია ტაბლეტზე, შექმნას და მიიღოს კავშირები დაწყვილებულ მოწყობილობებთან."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"აპს შეეძლება, ნახოს Bluetooth-ის კონფიგურაცია ტელეფონზე და შექმნას და მიიღოს კავშირები დაწყვილებულ მოწყობილობებთან."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"აპს შეეძლება მოიძიოს, გამოიკვლიოს და წაშალოს შეტყობინებები, მათ შორის სხვა აპების მიერ გამოქვეყნებული."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"შეტყობინებების მოსმენის სერვისთან დაკავშირება"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"მფლობელს შეეძლება შეტყობინებების მსმენლის სერვისის ზედა დონის ინტერფეისთან დაკავშირება. არ უნდა მოხდეს მისი გამოყენება ჩვეუელებრივი აპებისთვის.ფ"</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"მდგომარეობის პროვაიდერის სერვისებთან შეკავშირება"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"მფლობელს შეეძლება შეკავშირდეს მდგომარეობის პროვაიდერის სერვისების ზედა დონის ინტერფეისთან. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დასჭირდეს."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ოპერატორის მიერ მოწოდებული კოფიგურაციის აპის გამოხმობა"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"საშუალებას აძლევს მფლობელს გამოიწვიოს ოპერატორის მიერ მოწოდებული კონფიგურაციის აპი. ჩვეულებრივ აპს ეს წესით არასოდეს არ უნდა დაჭირდეს."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"განხორციელდეს ქსელის მდგომარეობის მონიტორინგი"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"საშუალებას აძლევს აპლიკაციებს განახორციელოს ქსელის მდგომარეობის მონიტორინგი. ეს ფუნქცია ჩვეულებრივ აპებს არ ჭირდება."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"შეყვანის მოწყობილობის კალიბრაციის ცვლილება"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"საშუალებას აძლევს აპს შეცვალოს სენსორული ეკრანის კალიბრაციის პარამეტრები. ჩვეულებრივ აპებს წესით არ უნდა დაჭირდეს."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM სერთიფიკატებზე წვდომა"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"საშუალებას აძლევს აპლიკაციას დანერგოს და გამოიყენოს DRM სერთიფიკატები. ეს უფლება ჩვეულებრივ აპებს არ ჭირდება."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"პაროლის წესების დაყენება"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"გააკონტროლეთ ეკრანის განბლოკვის პაროლში დაშვებული სიმბოლოები და მისი სიგრძე."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"ეკრანის განბლოკვის მცდელობების გაკონტროლება"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"აპლიკაციას ღილაკების დამცავის უსაფრთხო საცავზე წვდომის უფლება ექნება."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"ღილაკების დამცავის გამოჩენისა და დამალვის მართვა"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"აპლიკაციას შეეძლება ღილაკების დამცავის კონტროლი."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"ნდობის მდგომარეობის ცვლილებების მოსმენა."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"საშუალებას აძლევს აპლიკაციას მოუსმინოს ცვლილებებს სანდო მდგომარეობაში."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"სანდო აგენტის სერვისზე მიმაგრება."</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"საშუალებას აძლევს აპლიკაციას მიემაგროს სანდო აგენტის სერვისს."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"განახლებასთან და აღდგენის სისტემასთან ინტერაქცია"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"საშუალებას აძლევს აპლიკაციას მოახდინოს აღდგენის სისტემასთან და სისტემის განახლებასთან ინტერაქცია."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"მასშტაბის მართვისთვის შეეხეთ ორჯერ."</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"ფონი"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"ფონის შეცვლა"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"შეტყობინებების მსმენელი"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"მდგომარეობის პროვაიდერი"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN გააქტიურებულია"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN გააქტიურებულია <xliff:g id="APP">%s</xliff:g>-ის მიერ"</string>
<string name="vpn_text" msgid="3011306607126450322">"შეეხეთ ქსელის სამართავად."</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 4d6f0a3..dbe2d7f 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -68,7 +68,7 @@
</plurals>
<string name="imei" msgid="2625429890869005782">"IMEI"</string>
<string name="meid" msgid="4841221237681254195">"MEID"</string>
- <string name="ClipMmi" msgid="6952821216480289285">"លេខសម្គាល់អ្នកហៅចូល"</string>
+ <string name="ClipMmi" msgid="6952821216480289285">"លេខសម្គាល់អ្នកហៅចូល"</string>
<string name="ClirMmi" msgid="7784673673446833091">"លេខសម្គាល់អ្នកហៅចេញ"</string>
<string name="CfMmi" msgid="5123218989141573515">"បញ្ជូនការហៅបន្ត"</string>
<string name="CwMmi" msgid="9129678056795016867">"រង់ចាំការហៅ"</string>
@@ -125,7 +125,7 @@
<string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> ៖ មិនបានបញ្ជូនបន្ត"</string>
<string name="fcComplete" msgid="3118848230966886575">"កូដលក្ខណៈពេញលេញ។"</string>
<string name="fcError" msgid="3327560126588500777">"បញ្ហាការតភ្ជាប់ ឬកូដលក្ខណៈមិនត្រឹមត្រូវ។"</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"យល់ព្រម"</string>
+ <string name="httpErrorOk" msgid="1191919378083472204">"យល់ព្រម"</string>
<string name="httpError" msgid="7956392511146698522">"មានកំហុសបណ្ដាញ។"</string>
<string name="httpErrorLookup" msgid="4711687456111963163">"រកមិនឃើញ URL ។"</string>
<string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"គ្រោងការណ៍ផ្ទៀងផ្ទាត់តំបន់បណ្ដាញមិនត្រូវបានគាំទ្រ។"</string>
@@ -183,7 +183,7 @@
<string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"បើកសំឡេង"</string>
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"ពេលជិះយន្តហោះ"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"បានបើករបៀបពេលជិះយន្តហោះ"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"បានបិទរបៀបពេលជិះយន្តហោះ"</string>
+ <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"បានបិទរបៀបពេលជិះយន្តហោះ"</string>
<string name="global_action_settings" msgid="1756531602592545966">"ការកំណត់"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"របៀបសុវត្ថិភាព"</string>
@@ -195,7 +195,7 @@
<string name="permgrouplab_messages" msgid="7521249148445456662">"សាររបស់អ្នក"</string>
<string name="permgroupdesc_messages" msgid="7821999071003699236">"អាន និងសរសេរសារ SMS, អ៊ីមែល និងសារផ្សេងៗទៀតរបស់អ្នក។"</string>
<string name="permgrouplab_personalInfo" msgid="3519163141070533474">"ព័ត៌មានផ្ទាល់ខ្លួនរបស់អ្នក"</string>
- <string name="permgroupdesc_personalInfo" msgid="8426453129788861338">"ចូលដំណើរការព័ត៌មានដោយផ្ទាល់អំពីអ្នក ដែលបានរក្សាទុកក្នុងកាតទំនាក់ទំនងរបស់អ្នក។"</string>
+ <string name="permgroupdesc_personalInfo" msgid="8426453129788861338">"ចូលដំណើរការព័ត៌មានដោយផ្ទាល់អំពីអ្នក ដែលបានរក្សាទុកក្នុងកាតទំនាក់ទំនងរបស់អ្នក។"</string>
<string name="permgrouplab_socialInfo" msgid="5799096623412043791">"ព័ត៌មានសង្គមរបស់អ្នក"</string>
<string name="permgroupdesc_socialInfo" msgid="7129842457611643493">"ចូលដំណើរការព័ត៌មានដោយផ្ទាល់អំពីទំនាក់ទំនង និងការភ្ជាប់សង្គមរបស់អ្នក។"</string>
<string name="permgrouplab_location" msgid="635149742436692049">"ទីតាំងរបស់អ្នក"</string>
@@ -351,8 +351,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"ឲ្យកម្មវិធីប្រកាសការជូនដំណឹងការទទួលសារ SMS ។ កម្មវិធីព្យាបាទអាចប្រើវាដើម្បីបន្លំសារ SMS ចូល។"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ផ្ញើការប្រកាសបានទទួល WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"ឲ្យកម្មវិធីប្រកាសការជូនដំណឹងថាបានទទួលសារ WAP PUSH ។ កម្មវិធីព្យាបាទអាចប្រើវាដើម្បីក្លែងបង្កាន់ដៃសារ MMS ឬជំនួសមាតិកាទំព័របណ្ដាញណាមួយស្ងាត់ៗដោយអ្វីដែលក្លែងក្លាយ។"</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ផ្ញើពិន្ទុការប្រកាសបណ្ដាញ"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"ឲ្យកម្មវិធីប្រកាសការជូនដំណឹងដែលបណ្ដាញតម្រូវឲ្យដាក់ពិន្ទុ។ មិនចាំបាច់សម្រាប់កម្មវិធីធម្មតា។"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"កំណត់ចំនួនដំណើរការដែលកំពុងដំណើរការ"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"ឲ្យកម្មវិធីពិនិត្យចំនួនដំណើរការអតិបរមាដែលនឹងដំណើរការ។ មិនចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"បង្ខំឲ្យបិទកម្មវិធីក្នុងផ្ទៃខាងក្រោយ"</string>
@@ -386,7 +384,7 @@
<string name="permdesc_readInputState" msgid="8387754901688728043">"ឲ្យកម្មវិធីមើលគ្រាប់ចុចដែលអ្នកចុចពេលមានអន្តរកម្មជាមួយកម្មវិធីផ្សេង (ដូចជា បញ្ចូលពាក្យសម្ងាត់)។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_bindInputMethod" msgid="3360064620230515776">"ចងទៅវិធីសាស្ត្របញ្ចូល"</string>
<string name="permdesc_bindInputMethod" msgid="3250440322807286331">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃវិធីសាស្ត្របញ្ចូល។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
- <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"ចងសេវាកម្មភាពមធ្យោបាយងាយស្រួល"</string>
+ <string name="permlab_bindAccessibilityService" msgid="5357733942556031593">"ចងសេវាកម្មភាពមធ្យោបាយងាយស្រួល"</string>
<string name="permdesc_bindAccessibilityService" msgid="7034615928609331368">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃសេវាកម្មភាពងាយស្រួល។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_bindPrintService" msgid="8462815179572748761">"ចងសេវាកម្មបោះពុម្ព"</string>
<string name="permdesc_bindPrintService" msgid="7960067623209111135">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃសេវាកម្មធាតុក្រាហ្វិក។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
@@ -404,7 +402,7 @@
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"អនុញ្ញាតឲ្យម្ចាស់ភ្ជាប់ទៅចំណុចប្រទាក់កម្រិតកំពូលរបស់សេវាកម្មអន្តរកម្មសំឡេង។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ភ្ជាប់ទៅការបង្ហាញពីចម្ងាយ"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"អនុញ្ញាតឲ្យម្ចាស់ភ្ជាប់ទៅចំណុចប្រទាក់កម្រិតកំពូលនៃការបង្ហាញពីចម្ងាយ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
- <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ចងសេវាកម្មធាតុក្រាហ្វិក"</string>
+ <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ចងសេវាកម្មធាតុក្រាហ្វិក"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃសេវាកម្មធាតុក្រាហ្វិក។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_bindRouteProvider" msgid="4869394607915096847">"ភ្ជាប់ទៅសេវាកម្មក្រុមហ៊ុនផ្ដល់ច្រក"</string>
<string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"អនុញ្ញាតឲ្យម្ចាស់ភ្ជាប់ទៅក្រុមហ៊ុនផ្ដល់ច្រកដែលបានចុះឈ្មោះ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
@@ -412,7 +410,7 @@
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ឲ្យម្ចាស់ផ្ញើគោលបំណងទៅអ្នកគ្រប់គ្រងឧបករណ៍។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"ភ្ជាប់ទៅការបញ្ចូលទូរទស្សន៍"</string>
<string name="permdesc_bindTvInput" msgid="2371008331852001924">"អនុញ្ញាតឲ្យម្ចាស់ភ្ជាប់ទៅចំណុចប្រទាក់កម្រិតខ្ពស់នៃការបញ្ចូលទូរទស្សន៍។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
- <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"បន្ថែម ឬលុបកម្មវិធីគ្រប់គ្រងឧបករណ៍"</string>
+ <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"បន្ថែម ឬលុបកម្មវិធីគ្រប់គ្រងឧបករណ៍"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"អនុញ្ញាតឲ្យម្ចាស់បន្ថែម ឬលុបកម្មវិធីគ្រប់គ្រងឧបករណ៍សកម្មចេញ។ មិនគួរប្រើសម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"ប្ដូរទិសអេក្រង់"</string>
<string name="permdesc_setOrientation" msgid="3046126619316671476">"ឲ្យកម្មវិធីប្ដូរការបង្វិលអេក្រង់នៅពេលណាមួយ។ មិនចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
@@ -424,9 +422,9 @@
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"ឲ្យកម្មវិធីស្នើសញ្ញាដែលបានផ្ដល់ត្រូវផ្ញើទៅដំណើរការស្ថិតស្ថេរទាំងអស់។"</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"ធ្វើឲ្យកម្មវិធីដំណើរការជានិច្ច"</string>
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"ឲ្យកម្មវិធីធ្វើជាផ្នែកស្ថិតស្ថេរដោយខ្លួនឯងក្នុងអង្គចងចាំ។ វាអាចកំណត់អង្គចងចាំដែលអាចប្រើបានចំពោះកម្មវិធីផ្សេងៗ ដោយធ្វើឲ្យកុំព្យូទ័របន្ទះយឺត។"</string>
- <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"ឲ្យកម្មវិធី ធ្វើជាផ្នែកអចិន្ត្រៃយ៍នៃខ្លួនក្នុងអង្គចងចាំ។ វាអាចកម្រិតអង្គចងចាំអាចប្រើបាន ដើម្បីធ្វើឲ្យកម្មវិធីផ្សេងធ្វើឲ្យទូរស័ព្ទរបស់អ្នកយឺត។"</string>
+ <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"ឲ្យកម្មវិធី ធ្វើជាផ្នែកអចិន្ត្រៃយ៍នៃខ្លួនក្នុងអង្គចងចាំ។ វាអាចកម្រិតអង្គចងចាំអាចប្រើបាន ដើម្បីធ្វើឲ្យកម្មវិធីផ្សេងធ្វើឲ្យទូរស័ព្ទរបស់អ្នកយឺត។"</string>
<string name="permlab_deletePackages" msgid="184385129537705938">"លុបកម្មវិធី"</string>
- <string name="permdesc_deletePackages" msgid="7411480275167205081">"ឲ្យកម្មវិធីលុបកញ្ចប់ Android ។ កម្មវិធីព្យាបាទអាចប្រើវា ដើម្បីលុបកម្មវិធីសំខាន់ៗ។"</string>
+ <string name="permdesc_deletePackages" msgid="7411480275167205081">"ឲ្យកម្មវិធីលុបកញ្ចប់ Android ។ កម្មវិធីព្យាបាទអាចប្រើវា ដើម្បីលុបកម្មវិធីសំខាន់ៗ។ "</string>
<string name="permlab_clearAppUserData" msgid="274109191845842756">"លុបទិន្នន័យរបស់កម្មវិធីផ្សេង"</string>
<string name="permdesc_clearAppUserData" msgid="4625323684125459488">"ឲ្យកម្មវិធីសម្អាតទិន្នន័យអ្នកប្រើ។"</string>
<string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"លុបឃ្លាំងសម្ងាត់កម្មវិធីផ្សេងៗ"</string>
@@ -477,7 +475,7 @@
<string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"ឲ្យកម្មវិធីកែទិន្នន័យអំពីទំនាក់ទំនងរបស់អ្នកដែលបានរក្សាទុកក្នុងកុំព្យូទ័របន្ទះ រួមមានប្រេកង់ដែលអ្នកបានហៅ អ៊ីមែល ឬទាក់ទងតាមវិធីផ្សេងៗជាមួយទំនាក់ទំនងជាក់លាក់។ សិទ្ធិនេះអនុញ្ញាតឲ្យកម្មវិធីលុបទិន្នន័យទំនាក់ទំនងរបស់អ្នក។"</string>
<string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"ឲ្យកម្មវិធីកែទិន្នន័យអំពីទំនាក់ទំនងរបស់អ្នកដែលបានរក្សាទុកក្នុងទូរស័ព្ទរបស់អ្នក រួមមានប្រេកង់ដែលអ្នកបានហៅ អ៊ីមែល ឬបានទាក់ទងតាមវិធីផ្សេងៗជាមួយទំនាក់ទំនាក់ជាក់លាក់។ សិទ្ធិនេះឲ្យកម្មវិធីលុបទិន្នន័យទំនាក់ទំនង។"</string>
<string name="permlab_readCallLog" msgid="3478133184624102739">"អានកំណត់ហេតុហៅ"</string>
- <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"ឲ្យកម្មវិធីអានបញ្ជីហៅកុំព្យូទ័របន្ទះរបស់អ្នក រួមមានទិន្នន័យអំពីការហៅចូល និងចេញ។ សិទ្ធិនេះអនុញ្ញាតឲ្យកម្មវិធីរក្សាទុកទិន្នន័យបញ្ជីហៅរបស់អ្នក ហើយកម្មវិធីព្យាបាទអាចចែករំលែកទិន្នន័យបញ្ជីហៅដោយមិនឲ្យអ្នកដឹង។"</string>
+ <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"ឲ្យកម្មវិធីអានបញ្ជីហៅកុំព្យូទ័របន្ទះរបស់អ្នក រួមមានទិន្នន័យអំពីការហៅចូល និងចេញ។ សិទ្ធិនេះអនុញ្ញាតឲ្យកម្មវិធីរក្សាទុកទិន្នន័យបញ្ជីហៅរបស់អ្នក ហើយកម្មវិធីព្យាបាទអាចចែករំលែកទិន្នន័យបញ្ជីហៅដោយមិនឲ្យអ្នកដឹង។"</string>
<string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"ឲ្យកម្មវិធីអានបញ្ជីហៅទូរស័ព្ទរបស់អ្នក រួមមានទិន្នន័យអំពីការហៅចូល និងចេញ។ សិទ្ធិនេះអនុញ្ញាតឲ្យកម្មវិធីរក្សាទុកទិន្នន័យបញ្ជីហៅរបស់អ្នក ហើយកម្មវិធីព្យាបាទអាចចែករំលែកទិន្នន័យបញ្ជីហៅដោយមិនឲ្យអ្នកដឹង។"</string>
<string name="permlab_writeCallLog" msgid="8552045664743499354">"សរសេរបញ្ជីហៅ"</string>
<string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"ឲ្យកម្មវិធីកែបញ្ជីហៅកុំព្យូទ័របន្ទះរបស់អ្នករួមមានទិន្នន័យអំពីការហៅចូល និងចេញ។កម្មវិធីព្យាបាទអាចប្រើវា ដើម្បីលុប ឬកែបញ្ជីហៅរបស់អ្នក។"</string>
@@ -611,7 +609,7 @@
<string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"ឲ្យកម្មវិធីកំណត់ជំនួយទំហំផ្ទាំងរូបភាពប្រព័ន្ធ។"</string>
<string name="permlab_masterClear" msgid="2315750423139697397">"កំណត់ប្រព័ន្ធទៅលំនាំដើមរោងចក្រឡើងវិញ"</string>
<string name="permdesc_masterClear" msgid="3665380492633910226">"ឲ្យកម្មវិធីកំណត់ប្រព័ន្ធដូចការកំណត់ចេញពីរោងចក្រឡើងវិញពេញលេញ ដោយលុបទិន្នន័យ ការកំណត់រចនាសម្ព័ន្ធ និងកម្មវិធីបានដំឡើង។"</string>
- <string name="permlab_setTime" msgid="2021614829591775646">"កំណត់ម៉ោង"</string>
+ <string name="permlab_setTime" msgid="2021614829591775646">"កំណត់ម៉ោង"</string>
<string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"ឲ្យកម្មវិធីប្ដូរម៉ោងកុំព្យូទ័របន្ទះ។"</string>
<string name="permdesc_setTime" product="default" msgid="1855702730738020">"ឲ្យកម្មវិធីប្ដូរម៉ោងទូរស័ព្ទ។"</string>
<string name="permlab_setTimeZone" msgid="2945079801013077340">"កំណត់តំបន់ពេលវេលា"</string>
@@ -777,7 +775,7 @@
<string-array name="organizationTypes">
<item msgid="7546335612189115615">"កន្លែងធ្វើការ"</item>
<item msgid="4378074129049520373">"ផ្សេងៗ"</item>
- <item msgid="3455047468583965104">"តាមតម្រូវការ"</item>
+ <item msgid="3455047468583965104">"តាមតម្រូវការ"</item>
</string-array>
<string-array name="imProtocols">
<item msgid="8595261363518459565">"AIM"</item>
@@ -793,7 +791,7 @@
<string name="phoneTypeHome" msgid="2570923463033985887">"ផ្ទះ"</string>
<string name="phoneTypeMobile" msgid="6501463557754751037">"ចល័ត"</string>
<string name="phoneTypeWork" msgid="8863939667059911633">"កន្លែងធ្វើការ"</string>
- <string name="phoneTypeFaxWork" msgid="3517792160008890912">"ទូរសារកន្លែងធ្វើការ"</string>
+ <string name="phoneTypeFaxWork" msgid="3517792160008890912">"ទូរសារកន្លែងធ្វើការ"</string>
<string name="phoneTypeFaxHome" msgid="2067265972322971467">"ទូរសារផ្ទះ"</string>
<string name="phoneTypePager" msgid="7582359955394921732">"ភេយ័រ"</string>
<string name="phoneTypeOther" msgid="1544425847868765990">"ផ្សេងៗ"</string>
@@ -918,7 +916,7 @@
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"ព្យាយាមលំនាំច្រើនពេក"</string>
<string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"ដើម្បីដោះសោ ចូលគណនី Google របស់អ្នក។"</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"ឈ្មោះអ្នកប្រើ (អ៊ីមែល)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"ពាក្យសម្ងាត់"</string>
+ <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"ពាក្យសម្ងាត់"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"ចូល"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"ឈ្មោះអ្នកប្រើ ឬពាក្យសម្ងាត់មិនត្រឹមត្រូវ។"</string>
<string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"ភ្លេចឈ្មោះអ្នកប្រើ ឬពាក្យសម្ងាត់របស់អ្នក?\nមើល "<b>"google.com/accounts/recovery"</b>" ។"</string>
@@ -963,7 +961,7 @@
<string name="factorytest_failed" msgid="5410270329114212041">"បានបរាជ័យក្នុងការសាកល្បងរោងចក្រ"</string>
<string name="factorytest_not_system" msgid="4435201656767276723">"សកម្មភាព FACTORY_TEST ត្រូវបានគាំទ្រសម្រាប់តែកញ្ចប់បានដំឡើងក្នុង /system/app."</string>
<string name="factorytest_no_action" msgid="872991874799998561">"រកមិនឃើញកញ្ចប់ដែលផ្ដល់សកម្មភាព FACTORY_TEST ។"</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"ចាប់ផ្ដើមឡើងវិញ"</string>
+ <string name="factorytest_reboot" msgid="6320168203050791643">"ចាប់ផ្ដើមឡើងវិញ"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"ទំព័រមានចំណងជើង \"<xliff:g id="TITLE">%s</xliff:g>\" សរសេរ៖"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
<string name="js_dialog_before_unload_title" msgid="2619376555525116593">"បញ្ជាក់ការរុករក"</string>
@@ -1021,7 +1019,7 @@
<string name="prepend_shortcut_label" msgid="2572214461676015642">"ម៉ឺនុយ +"</string>
<string name="menu_space_shortcut_label" msgid="2410328639272162537">"ដកឃ្លា"</string>
<string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
- <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"លុប"</string>
+ <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"លុប"</string>
<string name="search_go" msgid="8298016669822141719">"ស្វែងរក"</string>
<string name="searchview_description_search" msgid="6749826639098512120">"ស្វែងរក"</string>
<string name="searchview_description_query" msgid="5911778593125355124">"ស្វែងរកសំណួរ"</string>
@@ -1105,18 +1103,18 @@
<string name="preposition_for_date" msgid="9093949757757445117">"នៅ <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"នៅម៉ោង <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"ក្នុងឆ្នាំ <xliff:g id="YEAR">%s</xliff:g>"</string>
- <string name="day" msgid="8144195776058119424">"ថ្ងៃ"</string>
+ <string name="day" msgid="8144195776058119424">"ថ្ងៃ"</string>
<string name="days" msgid="4774547661021344602">"ថ្ងៃ"</string>
<string name="hour" msgid="2126771916426189481">"ម៉ោង"</string>
<string name="hours" msgid="894424005266852993">"ម៉ោង"</string>
- <string name="minute" msgid="9148878657703769868">"នាទី"</string>
+ <string name="minute" msgid="9148878657703769868">"នាទី"</string>
<string name="minutes" msgid="5646001005827034509">"នាទី"</string>
- <string name="second" msgid="3184235808021478">"វិនាទី"</string>
+ <string name="second" msgid="3184235808021478">"វិនាទី"</string>
<string name="seconds" msgid="3161515347216589235">"វិនាទី"</string>
- <string name="week" msgid="5617961537173061583">"សប្ដាហ៍"</string>
- <string name="weeks" msgid="6509623834583944518">"សប្ដាហ៍"</string>
- <string name="year" msgid="4001118221013892076">"ឆ្នាំ"</string>
- <string name="years" msgid="6881577717993213522">"ឆ្នាំ"</string>
+ <string name="week" msgid="5617961537173061583">"សប្ដាហ៍"</string>
+ <string name="weeks" msgid="6509623834583944518">"សប្ដាហ៍"</string>
+ <string name="year" msgid="4001118221013892076">"ឆ្នាំ"</string>
+ <string name="years" msgid="6881577717993213522">"ឆ្នាំ"</string>
<plurals name="duration_seconds">
<item quantity="one" msgid="6962015528372969481">"1 វិនាទី"</item>
<item quantity="other" msgid="1886107766577166786">"<xliff:g id="COUNT">%d</xliff:g> វិនាទី"</item>
@@ -1132,12 +1130,12 @@
<string name="VideoView_error_title" msgid="3534509135438353077">"បញ្ហាវីដេអូ"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"វីដេអូនេះមិនត្រឹមត្រូវសម្រាប់ចរន្តចូលឧបករណ៍នេះ។"</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"មិនអាចចាក់វីដេអូនេះ។"</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"យល់ព្រម"</string>
+ <string name="VideoView_error_button" msgid="2822238215100679592">"យល់ព្រម"</string>
<string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="noon" msgid="7245353528818587908">"រសៀល"</string>
<string name="Noon" msgid="3342127745230013127">"រសៀល"</string>
<string name="midnight" msgid="7166259508850457595">"កណ្ដាលអធ្រាត្រ"</string>
- <string name="Midnight" msgid="5630806906897892201">"កណ្ដាលអធ្រាត្រ"</string>
+ <string name="Midnight" msgid="5630806906897892201">"កណ្ដាលអធ្រាត្រ"</string>
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"ជ្រើសទាំងអស់"</string>
@@ -1154,13 +1152,13 @@
<string name="inputMethod" msgid="1653630062304567879">"វិធីសាស្ត្របញ្ចូល"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"សកម្មភាពអត្ថបទ"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"អស់ទំហំផ្ទុក"</string>
- <string name="low_internal_storage_view_text" msgid="6640505817617414371">"មុខងារប្រព័ន្ធមួយចំនួនអាចមិនដំណើរការ"</string>
+ <string name="low_internal_storage_view_text" msgid="6640505817617414371">"មុខងារប្រព័ន្ធមួយចំនួនអាចមិនដំណើរការ"</string>
<string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងដំណើរការ"</string>
<string name="app_running_notification_text" msgid="4653586947747330058">"ប៉ះ ដើម្បីមើលព័ត៌មានបន្ថែម ឬបញ្ឈប់កម្មវិធី។"</string>
- <string name="ok" msgid="5970060430562524910">"យល់ព្រម"</string>
- <string name="cancel" msgid="6442560571259935130">"បោះបង់"</string>
- <string name="yes" msgid="5362982303337969312">"យល់ព្រម"</string>
- <string name="no" msgid="5141531044935541497">"បោះបង់"</string>
+ <string name="ok" msgid="5970060430562524910">"យល់ព្រម"</string>
+ <string name="cancel" msgid="6442560571259935130">"បោះបង់"</string>
+ <string name="yes" msgid="5362982303337969312">"យល់ព្រម"</string>
+ <string name="no" msgid="5141531044935541497">"បោះបង់"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"ប្រយ័ត្ន"</string>
<string name="loading" msgid="7933681260296021180">"កំពុងផ្ទុក..."</string>
<string name="capital_on" msgid="1544682755514494298">"បើក"</string>
@@ -1169,7 +1167,7 @@
<string name="whichHomeApplication" msgid="4616420172727326782">"ជ្រើសកម្មវិធីដើម"</string>
<string name="alwaysUse" msgid="4583018368000610438">"ប្រើតាមលំនាំដើមសម្រាប់សកម្មភាពនេះ។"</string>
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"សម្អាតលំនាំដើមក្នុងការកំណត់ប្រព័ន្ធ > កម្មវិធី > ទាញយក។"</string>
- <string name="chooseActivity" msgid="7486876147751803333">"ជ្រើសសកម្មភាព"</string>
+ <string name="chooseActivity" msgid="7486876147751803333">"ជ្រើសសកម្មភាព"</string>
<string name="chooseUsbActivity" msgid="6894748416073583509">"ជ្រើសកម្មវិធីសម្រាប់ឧបករណ៍យូអេសប៊ី"</string>
<string name="noApplications" msgid="2991814273936504689">"គ្មានកម្មវិធីអាចអនុវត្តសកម្មភាពនេះ។"</string>
<string name="aerr_title" msgid="1905800560317137752"></string>
@@ -1180,7 +1178,7 @@
<string name="anr_activity_process" msgid="5776209883299089767">"សកម្មភាព <xliff:g id="ACTIVITY">%1$s</xliff:g> មិនឆ្លើយតប។\n\nតើអ្នកចង់បិទវា?"</string>
<string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> មិនឆ្លើយតប។ តើអ្នកចង់បិទវា?"</string>
<string name="anr_process" msgid="6513209874880517125">"ដំណើរការ <xliff:g id="PROCESS">%1$s</xliff:g> មិនឆ្លើយតប។ \n\nតើអ្នកចង់បិទវាឬ?"</string>
- <string name="force_close" msgid="8346072094521265605">"យល់ព្រម"</string>
+ <string name="force_close" msgid="8346072094521265605">"យល់ព្រម"</string>
<string name="report" msgid="4060218260984795706">"រាយការណ៍"</string>
<string name="wait" msgid="7147118217226317732">"រង់ចាំ"</string>
<string name="webpage_unresponsive" msgid="3272758351138122503">"ទំព័រក្លាយជាមិនឆ្លើយតប។\n\nតើអ្នកចង់បិទវា?"</string>
@@ -1262,19 +1260,19 @@
<string name="sms_short_code_details" msgid="3492025719868078457"><font fgcolor="#ffffb060">"នេះអាចកាត់លុយ"</font>" លើគណនីចល័តរបស់អ្នក។"</string>
<string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"វានឹងគិតថ្លៃសេវាកម្មលើគណនីចល័តរបស់អ្នក។"</font></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"ផ្ញើ"</string>
- <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"បោះបង់"</string>
+ <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"បោះបង់"</string>
<string name="sms_short_code_remember_choice" msgid="5289538592272218136">"ចងចាំជម្រើសរបស់ខ្ញុំ"</string>
<string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"អ្នកអាចប្ដូរវាពេលក្រោយក្នុងការកំណត់ > កម្មវិធី"</string>
<string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"អនុញ្ញាតជានិច្ច"</string>
<string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"កុំអនុញ្ញាត"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"បានដកស៊ីមកាតចេញ"</string>
- <string name="sim_removed_message" msgid="2333164559970958645">"បណ្ដាញចល័តនឹងប្រើលែងបានរហូតដល់អ្នកចាប់ផ្ដើមជាមួយស៊ីមកាតដែលបាបញ្ចូលត្រឹមត្រូវ។"</string>
+ <string name="sim_removed_message" msgid="2333164559970958645">"បណ្ដាញចល័តនឹងប្រើលែងបានរហូតដល់អ្នកចាប់ផ្ដើមជាមួយស៊ីមកាតដែលបាបញ្ចូលត្រឹមត្រូវ។"</string>
<string name="sim_done_button" msgid="827949989369963775">"រួចរាល់"</string>
<string name="sim_added_title" msgid="3719670512889674693">"បានបន្ថែមស៊ីមកាត"</string>
<string name="sim_added_message" msgid="6599945301141050216">"ចាប់ផ្ដើមឧបករណ៍របស់អ្នកឡើងវិញ ដើម្បីចូលដំណើរការបណ្ដាញចល័ត។"</string>
<string name="sim_restart_button" msgid="4722407842815232347">"ចាប់ផ្ដើមឡើងវិញ"</string>
- <string name="time_picker_dialog_title" msgid="8349362623068819295">"កំណត់ម៉ោង"</string>
- <string name="date_picker_dialog_title" msgid="5879450659453782278">"កំណត់កាលបរិច្ឆេទ"</string>
+ <string name="time_picker_dialog_title" msgid="8349362623068819295">"កំណត់ម៉ោង"</string>
+ <string name="date_picker_dialog_title" msgid="5879450659453782278">"កំណត់កាលបរិច្ឆេទ"</string>
<string name="date_time_set" msgid="5777075614321087758">"កំណត់"</string>
<string name="date_time_done" msgid="2507683751759308828">"រួចរាល់"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"ថ្មី៖ "</font></string>
@@ -1352,7 +1350,7 @@
<string name="permdesc_copyProtectedData" msgid="4390697124288317831">"ឲ្យកម្មវិធីដកសេវាកម្មនៃកម្មវិធីផ្ទុកលំនាំដើម ដើម្បីចម្លងមាតិកា។ មិនសម្រាប់ប្រើដោយកម្មវិធីលំនាំដើម។"</string>
<string name="permlab_route_media_output" msgid="1642024455750414694">"នាំផ្លូវលទ្ធផលមេឌៀ"</string>
<string name="permdesc_route_media_output" msgid="4932818749547244346">"ឲ្យកម្មវិធីនាំផ្លូវលទ្ធផលមេឌៀទៅឧបករណ៍ខាងក្រៅផ្សេង។"</string>
- <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"ចូលដំណើរការឧបករណ៍ផ្ទុកសុវត្ថិភាព"</string>
+ <string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"ចូលដំណើរការឧបករណ៍ផ្ទុកសុវត្ថិភាព"</string>
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"ឲ្យកម្មវិធីចូលការផ្ទុកមានសុវត្ថិភាព keguard ។"</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"ពិនិត្យការបង្ហាញ និងលាក់ការការពារ"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"ឲ្យកម្មវិធីគ្រប់គ្រង keguard ។"</string>
@@ -1367,7 +1365,7 @@
<string name="ime_action_go" msgid="8320845651737369027">"ទៅ"</string>
<string name="ime_action_search" msgid="658110271822807811">"ស្វែងរក"</string>
<string name="ime_action_send" msgid="2316166556349314424">"ផ្ញើ"</string>
- <string name="ime_action_next" msgid="3138843904009813834">"បន្ទាប់"</string>
+ <string name="ime_action_next" msgid="3138843904009813834">"បន្ទាប់"</string>
<string name="ime_action_done" msgid="8971516117910934605">"រួចរាល់"</string>
<string name="ime_action_previous" msgid="1443550039250105948">"មុន"</string>
<string name="ime_action_default" msgid="2840921885558045721">"អនុវត្ត"</string>
@@ -1376,7 +1374,7 @@
<string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"កម្មវិធីមួយ ឬច្រើនដូចខាងក្រោមស្នើសិទ្ធិ ដើម្បីចូលគណនីរបស់អ្នកឥឡូវ និងពេលអនាគត។"</string>
<string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"តើអ្នកចង់អនុញ្ញាតសំណើនេះ?"</string>
<string name="grant_permissions_header_text" msgid="6874497408201826708">"ស្នើចូល"</string>
- <string name="allow" msgid="7225948811296386551">"អនុញ្ញាត"</string>
+ <string name="allow" msgid="7225948811296386551">"អនុញ្ញាត"</string>
<string name="deny" msgid="2081879885755434506">"បដិសេធ"</string>
<string name="permission_request_notification_title" msgid="6486759795926237907">"បានស្នើសិទ្ធិ"</string>
<string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"បានស្នើសិទ្ធិ\nសម្រាប់គណនី <xliff:g id="ACCOUNT">%s</xliff:g> ។"</string>
@@ -1399,12 +1397,12 @@
<string name="no_file_chosen" msgid="6363648562170759465">"គ្មានឯកសារបានជ្រើស"</string>
<string name="reset" msgid="2448168080964209908">"កំណត់ឡើងវិញ"</string>
<string name="submit" msgid="1602335572089911941">"ដាក់ស្នើ"</string>
- <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"បានបើករបៀបរថយន្ត"</string>
+ <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"បានបើករបៀបរថយន្ត"</string>
<string name="car_mode_disable_notification_message" msgid="8035230537563503262">"ប៉ះ ដើម្បីចេញពីរបៀបរថយន្ត។"</string>
<string name="tethered_notification_title" msgid="3146694234398202601">"ភ្ជាប់ ឬហតស្ពតសកម្ម"</string>
<string name="tethered_notification_message" msgid="6857031760103062982">"ប៉ះ ដើម្បីរៀបចំ។"</string>
<string name="back_button_label" msgid="2300470004503343439">"ថយក្រោយ"</string>
- <string name="next_button_label" msgid="1080555104677992408">"បន្ទាប់"</string>
+ <string name="next_button_label" msgid="1080555104677992408">"បន្ទាប់"</string>
<string name="skip_button_label" msgid="1275362299471631819">"រំលង"</string>
<string name="throttle_warning_notification_title" msgid="4890894267454867276">"ការប្រើទិន្នន័យចល័តខ្ពស់"</string>
<string name="throttle_warning_notification_message" msgid="3340822228599337743">"ប៉ះ ដើម្បីស្វែងយល់បន្ថែមអំពីការប្រើទិន្នន័យចល័ត។"</string>
@@ -1430,7 +1428,7 @@
<string name="media_shared" product="nosdcard" msgid="5830814349250834225">"ឧបករណ៍ផ្ទុកយូអេសប៊ីបច្ចុប្បន្នកំពុងប្រើដោយកុំព្យូទ័រ។"</string>
<string name="media_shared" product="default" msgid="5706130568133540435">"បច្ចុប្បន្នកាតអេសឌីកំពុងប្រើដោយកុំព្យូទ័រ"</string>
<string name="media_unknown_state" msgid="729192782197290385">"មិនស្គាល់ស្ថានភាពមេឌៀខាងក្រៅ។"</string>
- <string name="share" msgid="1778686618230011964">"ចែករំលែក"</string>
+ <string name="share" msgid="1778686618230011964">"ចែករំលែក"</string>
<string name="find" msgid="4808270900322985960">"រក"</string>
<string name="websearch" msgid="4337157977400211589">"ស្វែងរកតាមបណ្ដាញ"</string>
<string name="find_next" msgid="5742124618942193978">"រកបន្ទាប់"</string>
@@ -1446,7 +1444,7 @@
<string name="sync_undo_deletes" msgid="2941317360600338602">"មិនធ្វើការលុបវិញ"</string>
<string name="sync_do_nothing" msgid="3743764740430821845">"មិនធ្វើអ្វីទេឥឡូវ"</string>
<string name="choose_account_label" msgid="5655203089746423927">"ជ្រើសគណនី"</string>
- <string name="add_account_label" msgid="2935267344849993553">"បន្ថែមគណនីថ្មី"</string>
+ <string name="add_account_label" msgid="2935267344849993553">"បន្ថែមគណនីថ្មី"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"បន្ថែមគណនី"</string>
<string name="number_picker_increment_button" msgid="2412072272832284313">"បង្កើន"</string>
<string name="number_picker_decrement_button" msgid="476050778386779067">"បន្ថយ"</string>
@@ -1465,15 +1463,15 @@
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"បង្កើនឆ្នាំ"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"បន្ថយឆ្នាំ"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
- <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"បោះបង់"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"បោះបង់"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"លុប"</string>
<string name="keyboardview_keycode_done" msgid="1992571118466679775">"រួចរាល់"</string>
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ប្ដូររបៀប"</string>
<string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
<string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
- <string name="activitychooserview_choose_application" msgid="2125168057199941199">"ជ្រើសកម្មវិធី"</string>
+ <string name="activitychooserview_choose_application" msgid="2125168057199941199">"ជ្រើសកម្មវិធី"</string>
<string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"មិនអាចចាប់ផ្ដើម <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
- <string name="shareactionprovider_share_with" msgid="806688056141131819">"ចែករំលែកជាមួយ"</string>
+ <string name="shareactionprovider_share_with" msgid="806688056141131819">"ចែករំលែកជាមួយ"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"ចែករំលែកជាមួយ <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"គ្រប់គ្រងការរុញ។ ប៉ះ & សង្កត់។"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"អូស ដើម្បីដោះសោ។"</string>
@@ -1487,7 +1485,7 @@
<string name="storage_internal" msgid="4891916833657929263">"ឧបករណ៍ផ្ទុកខាងក្នុង"</string>
<string name="storage_sd_card" msgid="3282948861378286745">"កាតអេសឌី"</string>
<string name="storage_usb" msgid="3017954059538517278">"ឧបករណ៍ផ្ទុកយូអេសប៊ី"</string>
- <string name="extract_edit_menu_button" msgid="8940478730496610137">"កែសម្រួល"</string>
+ <string name="extract_edit_menu_button" msgid="8940478730496610137">"កែសម្រួល"</string>
<string name="data_usage_warning_title" msgid="1955638862122232342">"ការព្រមានប្រើទិន្នន័យ"</string>
<string name="data_usage_warning_body" msgid="2814673551471969954">"ប៉ះ ដើម្បីមើលការប្រើ និងការកំណត់។"</string>
<string name="data_usage_3g_limit_title" msgid="7093334419518706686">"បានបិទទិន្នន័យ 2G-3G"</string>
@@ -1544,7 +1542,7 @@
<string name="media_route_status_available" msgid="6983258067194649391">"ទំនេរ"</string>
<string name="media_route_status_not_available" msgid="6739899962681886401">"មិនទំនេរ"</string>
<string name="media_route_status_in_use" msgid="4533786031090198063">"កំពុងប្រើ"</string>
- <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"អេក្រង់ជាប់"</string>
+ <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"អេក្រង់ជាប់"</string>
<string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"អេក្រង់ HDMI"</string>
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"#<xliff:g id="ID">%1$d</xliff:g> ត្រួតគ្នា"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
@@ -1576,7 +1574,7 @@
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ព្យាយាមលំនាំច្រើនពេក"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"ដើម្បីដោះសោ ចូលក្នុងគណនី Google ។"</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"ឈ្មោះអ្នកប្រើ (អ៊ីម៉ែល)"</string>
- <string name="kg_login_password_hint" msgid="9057289103827298549">"ពាក្យសម្ងាត់"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"ពាក្យសម្ងាត់"</string>
<string name="kg_login_submit_button" msgid="5355904582674054702">"ចូល"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"ឈ្មោះអ្នកប្រើ ឬពាក្យសម្ងាត់មិនត្រឹមត្រូវ។"</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ភ្លេចឈ្មោះអ្នកប្រើ ឬពាក្យសម្ងាត់របស់អ្នក?\nមើល "<b>"google.com/accounts/recovery"</b>" ។"</string>
@@ -1685,7 +1683,7 @@
<string name="mediasize_japanese_you4" msgid="2091777168747058008">"You4"</string>
<string name="mediasize_unknown_portrait" msgid="3088043641616409762">"មិនស្គាល់បញ្ឈរ"</string>
<string name="mediasize_unknown_landscape" msgid="4876995327029361552">"មិនស្គាល់ទេសភាព"</string>
- <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"បានបោះបង់"</string>
+ <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"បានបោះបង់"</string>
<string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"កំហុសក្នុងការសរសេរមាតិកា"</string>
<string name="reason_unknown" msgid="6048913880184628119">"មិនស្គាល់"</string>
<string name="reason_service_unavailable" msgid="7824008732243903268">"មិនបានបើកសេវាកម្មបោះពុម្ព"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 310b1f0..5a7f9b8 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g>일"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g>일 <xliff:g id="HOURS">%2$d</xliff:g>시간"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g>일 <xliff:g id="HOURS">%2$d</xliff:g>시간"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g>시간"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g>시간 <xliff:g id="MINUTES">%2$d</xliff:g>분"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g>시간 <xliff:g id="MINUTES">%2$d</xliff:g>분"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g>분"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g>분 <xliff:g id="SECONDS">%2$d</xliff:g>초"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g>분 <xliff:g id="SECONDS">%2$d</xliff:g>초"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g>초"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g>초"</string>
<string name="untitled" msgid="4638956954852782576">"<제목 없음>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"동기화"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g> 삭제가 너무 많습니다."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"태블릿 저장공간이 꽉 찼습니다. 일부 파일을 삭제하여 저장 여유 공간을 늘리세요."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"시계 저장공간이 가득 찼습니다. 일부 파일을 삭제하여 저장 여유 공간을 늘리세요."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"휴대전화 저장공간이 꽉 찼습니다. 일부 파일을 삭제하여 저장공간을 늘리세요."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"네트워크가 모니터링될 수 있음"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"알 수 없는 제3자의 모니터링"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"벨소리가 켜져 있습니다."</string>
<string name="shutdown_progress" msgid="2281079257329981203">"종료 중..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"태블릿이 종료됩니다."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"시계가 종료됩니다."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"휴대전화가 종료됩니다."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"종료하시겠습니까?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"안전 모드로 다시 부팅"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"비행기 모드"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"비행기 모드 사용중"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"비행기 모드 사용중이 아님"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"설정"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"요금이 부과되는 서비스"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"요금이 부과될 수 있는 작업을 수행할 수 있도록 합니다."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"메시지"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"바로가기 제거"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"애플리케이션이 사용자의 작업 없이 홈 화면 바로가기를 삭제할 수 있도록 허용합니다."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"발신전화 경로 전환"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"통화를 다른 번호로 리디렉션하거나 통화를 완전히 중단하는 옵션을 사용하여, 앱에서 발신 통화 중에 전화를 거는 번호를 볼 수 있게 허용합니다."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"앱이 발신 전화를 처리하고 전화를 걸 번호를 변경할 수 있도록 허용합니다. 이 권한을 사용하면 앱이 발신 전화를 모니터링, 리디렉션 또는 차단할 수도 있습니다."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"문자 메시지 받기(SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"앱이 SMS 메시지를 수신하고 처리할 수 있도록 허용합니다. 이는 앱이 사용자에게 표시하지 않고 기기로 전송된 메시지를 모니터링 또는 삭제할 수도 있다는 것을 의미합니다."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"문자 메시지 받기(MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"앱이 활성 창의 콘텐츠를 검색할 수 있도록 허용합니다. 이 경우 악성 앱이 전체 창의 콘텐츠를 검색하여 비밀번호를 제외한 모든 텍스트를 살펴볼 수 있습니다."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"일시적인 접근성 사용"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"애플리케이션이 기기에서 일시적으로 접근성을 사용하도록 허용합니다. 이 경우 악성 앱이 사용자의 동의 없이 접근성을 사용할 수 있습니다."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"창 토큰 검색"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"애플리케이션이 창 토큰을 검색하도록 허용합니다. 악성 앱이 시스템을 가장하여 애플리케이션 창과 무단으로 상호작용할 수 있습니다."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"프레임 통계 검색"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"애플리케이션이 프레임 통계를 수집하도록 허용합니다. 악성 앱이 다른 앱에서 창의 프레임 통계를 볼 수 있습니다."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"창 관련 정보 가져오기"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"애플리케이션이 Window Manager에서 창 관련 정보를 가져오도록 허용합니다. 이 경우 악성 앱이 내부 시스템에서만 사용하도록 되어 있는 정보를 가져올 수 있습니다."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"일정 필터링"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"애플리케이션에 입력 필터를 등록할 수 있도록 하여 모든 사용자 일정 스트림을 전달하기 전에 필터링합니다. 이 경우 사용자의 개입 없이 악성 앱이 시스템 UI를 제어할 수 있습니다."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"디스플레이 확대"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"앱이 표시된 콘텐츠를 확대하도록 허용합니다. 악성 앱은 표시된 콘텐츠를 변형시켜 기기를 사용할 수 없게 만들 수 있습니다."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"부분 종료"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"작업 관리자를 종료 상태로 설정합니다. 전체 종료를 수행하지는 않습니다."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"애플리케이션 전환 방지"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"앱이 SMS 메시지를 받았다는 알림을 브로드캐스트할 수 있도록 허용합니다. 이 경우 악성 앱이 수신된 SMS 메시지를 위조할 수 있습니다."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH-수신 브로드캐스트 보내기"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"앱이 WAP PUSH 메시지를 받았다는 알림을 브로드캐스트할 수 있도록 허용합니다. 이 경우 악성 앱이 MMS 메시지를 받은 것처럼 위장하거나 웹페이지의 콘텐츠를 악성 콘텐츠로 몰래 바꿀 수 있습니다."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"네트워크 점수화 브로드캐스트 전송"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"네트워크를 점수화할 필요가 있다는 알림을 앱이 브로드캐스트할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"실행 중인 프로세스 수 제한"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"앱이 실행할 최대 프로세스 수를 제어할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"백그라운드 앱 강제 종료"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"권한을 가진 프로그램이 VPN 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"배경화면 연결"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"권한을 가진 프로그램이 배경화면에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"음성 상호작용 서비스 사용"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"권한을 가진 프로그램이 음성 상호작용 서비스의 최상위 인터페이스를 사용하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"원격 디스플레이에 연결"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"권한을 가진 프로그램이 원격 디스플레이에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"위젯 서비스와 연결"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"권한을 가진 프로그램이 위젯 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"경로 제공업체 서비스 사용"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"권한을 가진 프로그램이 등록된 경로 제공업체를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"기기 관리자와 상호 작용"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"권한을 가진 프로그램이 기기 관리자에게 인텐트를 보낼 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"TV 입력 사용"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"권한을 가진 프로그램이 TV 입력에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"기기 관리자 추가 또는 삭제"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"권한을 가진 프로그램이 활성화된 기기의 관리자를 추가 또는 삭제하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"화면 방향 변경"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"애플리케이션에서 설치된 모든 미디어 디코더를 사용하여 재생하는 데 디코딩할 수 있도록 허용합니다."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"신뢰할 수 있는 자격증명 관리"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"앱에서 CA 인증서를 신뢰할 수 있는 자격증명으로 설치 및 제거하도록 허용합니다."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"유휴 시간 동안 애플리케이션 실행"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"이 권한을 부여하면 기기를 사용하지 않는 동안 Android 시스템이 백그라운드에서 애플리케이션을 실행할 수 있게 됩니다."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"유휴 서비스에 연결"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"이 권한을 부여하면 Android 시스템이 애플리케이션의 유휴 서비스에 연결할 수 있습니다."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"진단 그룹 소유의 리소스 읽기/쓰기"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"앱이 진단 그룹 소유의 리소스(예: /dev에 있는 파일)를 읽고 쓸 수 있도록 허용합니다. 이 기능은 시스템 안정성 및 보안에 영향을 미칠 수 있으므로 제조업체 또는 사업자가 하드웨어 관련 진단을 수행하는 경우에만 사용해야 합니다."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"앱 구성요소 사용 또는 사용 안함"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"앱이 기기에 저장된 개인 프로필 정보(예: 사용자 이름, 연락처 정보 등)를 읽을 수 있도록 허용합니다. 이는 앱이 사용자를 확인할 수 있으며 다른 사용자에게 해당 프로필 정보를 전송할 수도 있다는 것을 의미합니다."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"나만의 연락처 카드 수정"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"앱이 기기에 저장된 개인 프로필 정보(예: 사용자 이름, 연락처 정보 등)를 변경 또는 추가할 수 있도록 허용합니다. 이는 앱이 사용자를 확인하고 다른 사용자에게 해당 프로필 정보를 전송할 수 있다는 것을 의미합니다."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"신체 센서(예: 심박수 모니터)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"앱이 신체 변화(예: 심박수) 측정을 위해 사용하는 센서의 데이터에 액세스하도록 허용합니다."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"소셜 스트림 읽기"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"앱이 사용자와 친구의 최신 소셜 소식에 액세스하고 동기화할 수 있도록 허용합니다. 이 경우 앱이 비밀유지와 관계 없이 소셜 네트워크에서 사용자와 친구가 주고받는 내용을 읽을 수 있으므로, 정보를 공유할 때 주의해야 합니다. 참고: 이 권한이 적용되지 않는 소셜 네트워크도 있습니다."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"소셜 스트림에 쓰기"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"앱이 기기의 휴대전화 기능을 관리할 수 있도록 허용합니다. 이 권한을 갖는 앱은 사용자에게 알리지 않고 네트워크를 전환하거나 무선 기능을 켜고 끄는 등의 작업을 수행할 수 있습니다."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"휴대전화 상태 및 ID 읽기"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"앱이 기기의 휴대전화 기능에 액세스할 수 있도록 허용합니다. 이 권한을 사용하면 앱이 전화번호 및 기기의 ID, 활성 통화인지 여부, 통화가 연결된 원격 번호 등을 확인할 수 있습니다."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"정확한 전화 상태 읽기"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"앱이 정확한 전화 상태에 액세스할 수 있도록 허용합니다. 이 권한을 부여하면 앱이 실제 통화 상태, 활성 통화 또는 백그라운드 상태인지 여부, 통화 실패, 정확한 데이터 연결 상태 및 데이터 연결 실패 등을 판단합니다."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"태블릿이 절전 모드로 전환되지 않도록 설정"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"휴대전화가 절전 모드로 전환되지 않도록 설정"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"앱이 태블릿의 절전 모드 전환을 막도록 허용합니다."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX 상태 변경"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"앱이 태블릿을 WiMAX 네트워크에 연결하거나 연결을 끊을 수 있도록 허용합니다."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"앱이 휴대전화를 WiMAX 네트워크에 연결하거나 연결을 끊을 수 있도록 허용합니다."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"네트워크 점수화"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"앱이 네트워크 순위를 정하고 태블릿에서 어떤 네트워크를 선호할지 영향을 주도록 허용합니다."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"앱이 네트워크 순위를 정하고 휴대전화에서 어떤 네트워크를 선호할지 영향을 주도록 허용합니다."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"블루투스 기기와 페어링"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"앱이 태블릿의 블루투스 설정을 확인하고 페어링된 기기에 연결하며 연결을 수락할 수 있도록 허용합니다."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"앱이 휴대전화의 블루투스 설정을 확인하고 페어링된 기기에 연결하며 연결을 수락할 수 있도록 허용합니다."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"앱이 다른 앱에서 게시한 알림을 비롯하여 알림을 검색하고 살펴보며 삭제할 수 있도록 허용합니다."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"알림 수신기 서비스 사용"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"권한을 가진 프로그램이 알림 수신기 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"조건 제공자 서비스 사용"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"권한을 가진 프로그램이 조건 제공자 서비스의 최상위 인터페이스를 사용하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"이동통신사에서 제공한 구성 앱 호출"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"권한을 가진 프로그램이 이동통신사에서 제공한 구성 앱을 호출하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"네트워크 상태에 대한 관측 보고 수신"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"애플리케이션이 네트워크 상태에 대한 관측 보고를 수신하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"입력 기기 보정 변경"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"앱이 터치 스크린의 보정 매개변수를 수정할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM 인증서에 액세스"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"애플리케이션이 DRM 인증서를 프로비저닝하고 사용하도록 허용합니다. 일반 앱에서는 필요하지 않습니다."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"비밀번호 규칙 설정"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"화면 잠금해제 비밀번호에 허용되는 길이 및 문자 수를 제어합니다."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"화면 잠금해제 시도 모니터링"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"애플리케이션에서 키가드 보안 저장소에 액세스하도록 허용합니다."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"키가드 표시 및 숨기기 설정"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"애플리케이션에서 키가드를 제어하도록 허용합니다."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Trust 상태 변경사항 수신"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"애플리케이션이 Trust 상태에서의 변경사항을 수신할 수 있도록 허용합니다."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Trust Agent 서비스에 연결"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"애플리케이션이 Trust Agent 서비스에 바인딩할 수 있도록 허용합니다."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"업데이트 및 복구 시스템과 상호작용"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"애플리케이션이 복구 시스템 및 시스템 업데이트와 상호작용할 수 있도록 허용합니다."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"확대/축소하려면 두 번 터치하세요."</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"배경화면"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"배경화면 변경"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"알림 수신기"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"조건 제공자"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN이 활성화됨"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN이 <xliff:g id="APP">%s</xliff:g>에 의해 활성화됨"</string>
<string name="vpn_text" msgid="3011306607126450322">"네트워크를 관리하려면 터치하세요."</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 08ba7e1..80a7e1f 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> ມື້"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> ມື້ <xliff:g id="HOURS">%2$d</xliff:g> ຊມ"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> ມື້ <xliff:g id="HOURS">%2$d</xliff:g> ຊມ"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> ຊມ"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> ຊມ <xliff:g id="MINUTES">%2$d</xliff:g> ນທ"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> ຊມ <xliff:g id="MINUTES">%2$d</xliff:g> ນທ"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> ນທ"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> ນທ <xliff:g id="SECONDS">%2$d</xliff:g> ວິ"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> ນທ <xliff:g id="SECONDS">%2$d</xliff:g> ວິ"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> ວິ"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> ວິ"</string>
<string name="untitled" msgid="4638956954852782576">"<ບໍ່ມີຊື່>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"ຊິ້ງຂໍ້ມູນ"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"ມີການລຶບ <xliff:g id="CONTENT_TYPE">%s</xliff:g> ຫຼາຍເກີນໄປ."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"ພື້ນທີ່ຈັດເກັບຂໍ້ມູນໃນແທັບເລັດເຕັມ. ລຶບບາງໄຟລ໌ອອກເພື່ອເພີ່ມພື້ນທີ່ຫວ່າງ."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"ບ່ອນຈັດເກັບຂໍ້ມູນໃນໂມງເຕັມແລ້ວ. ໃຫ້ລຶບໄຟລ໌ບາງອັນທີ່ບໍ່ໄດ້ໃຊ້ອອກເພື່ອເພີ່ມເນື້ອທີ່ຫວ່າງ."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"ພື້ນທີ່ໃນໂທລະສັບເຕັມແລ້ວ. ກະລຸນາລຶບບາງໄຟລ໌ອອກເພື່ອເພີ່ມພື້ນທີ່ຫວ່າງ."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ການນຳໃຊ້ເຄືອຂ່າຍອາດມີການກວດສອບຕິດຕາມ"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ໂດຍບຸກຄົນທີສາມທີ່ບໍ່ຮູ້ຈັກ"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"ເປີດສຽງໂທເຂົ້າແລ້ວ"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"ກຳລັງປິດລະບົບລົງ..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"ແທັບເລັດຂອງທ່ານຈະຖືກປິດ."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"ໂມງຂອງທ່ານຈະຖືກປິດໄວ້."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"ໂທລະສັບຂອງທ່ານຈະຖືກປິດ."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"ທ່ານຕ້ອງການທີ່ຈະປິດບໍ່?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"ຣີບູດເຂົ້າ safe mode"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"ໂໝດໃນຍົນ"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ເປີດໂໝດຢູ່ໃນຍົນແລ້ວ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ປິດໂໝດໃນຍົນແລ້ວ"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"ການຕັ້ງຄ່າ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"ບໍລິການທີ່ເຮັດໃຫ້ທ່ານເສຍເງິນ"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ເຮັດສິ່ງທີ່ທ່ານຕ້ອງເສຍຄ່າໃຊ້ຈ່າຍ."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"ຂໍ້ຄວາມຂອງທ່ານ"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"ຖອນທາງລັດ"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນລຶບທາງລັດໃນໜ້າຫຼັກໄດ້ ໂດຍບໍ່ຕ້ອງຮັບການຢືນຢັນຈາກຜູ່ໃຊ້."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"ປ່ຽນເສັ້ນທາງການໂທອອກ"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"ອະນຸຍາດໃຫ້ແອັບຯເບິ່ງໝາຍເລກເບີໂທ ໃນລະຫວ່າງການໂທອອກ ພ້ອມທັງໂຕເລືອກໃນການປ່ຽນເສັ້ນທາງການໂທໄປຫາເບີອື່ນ ຫຼື ລາຍລະອຽດກ່ຽວກັບເບີໂທລະສັບ."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"ອະນຸຍາດໃຫ້ແອັບຯປະມວນຜົນສາຍທີ່ໂທອອກ ແລະປ່ຽນໝາຍເລກທີ່ຈະໂທອອກ. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດກວດສອບ, ໂອນສາຍ ຫຼືຂັດຂວາງບໍ່ໃຫ້ໂທອອກໄດ້."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"ຮັບຂໍ້ຄວາມສັ້ນ (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"ອະນຸຍາດໃຫ້ແອັບຯຮັບ ແລະປະມວນຜົນຂໍ້ຄວາມ SMS. ນີ້ໝາຍຄວາມວ່າແອັບຯສາມາດຕິດຕາມ ຫຼືລຶບຂໍ້ຄວາມທີ່ສົ່ງເຂົ້າອຸປະກອນຂອງທ່ານ ໂດຍທີ່ບໍ່ສະແດງພວກມັນໃຫ້ທ່ານເຫັນ."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"ຮັບຂໍ້ຄວາມ (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"ອະນຸຍາດໃຫ້ແອັບຯດຶງຂໍ້ມູນເນື້ອຫາຂອງໜ້າຈໍທີ່ໃຊ້ຢູ່ໄດ້. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດດຶງຂໍ້ມູນທັງໝົດໃນໜ້າຈໍ ແລະກວດສອບຂໍ້ຄວາມທັງໝົດໃນນັ້ນໄດ້ ຍົກເວັ້ນລະຫັດຜ່ານ."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"ປິດການຊ່ວຍການເຂົ້າເຖິງຊົ່ວຄາວ"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ເປີດໃຊ້ການຊ່ວຍເຂົ້າເຖິງແບບຊົ່ວຄາວໃນອຸປະກອນ. ແອັບຯທີ່ເປັນອັນຕະລາຍ ອາດເປີດໃຊ້ການຊ່ວຍເຂົ້າເຖິງ ໂດຍບໍ່ໄດ້ຮັບການຍິນຍອມຈາກຜູ່ໃຊ້."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"ດຶງຂໍ້ມູນໂທເຄນໜ້າຈໍ"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນດຶງຂໍ້ມູນໂທເຄນຂອງໜ້າຈໍໄດ້. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດດຳເນີນການຕິດຕໍ່ທີ່ບໍ່ໄດ້ຮັບອະນຸຍາດກັບໜ້າຈໍແອັບພລິເຄຊັນເພື່ອຮຽນແບບລະບົບ."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"ດຶງຂໍ້ມູນສະຖິຕິເຟຣມ"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນສາມາດສະສົມສະຖິຕິເຟຣມໄດ້. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດສັງເກດສະຖິຕິເຟຣມຂອງໜ້າຈໍຕ່າງໆຈາກແອັບຯອື່ນໄດ້."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"ດຶງເອົາຂໍ້ມູນໜ້າຈໍ"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ດຶງເອົາຂໍ້ມູນກ່ຽວກັບໜ້າຈໍຈາກໂຕຈັດການໜ້າຈໍ. ແອັບຯທີ່ບໍ່ປອດໄພອາດດຶງເອົາຂໍ້ມູນທີ່ໃຊ້ສຳລັບພາຍໃນລະບົບໄດ້."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"ກັ່ນຕອງເຫດການ"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ລົງທະບຽນການກັ່ນຕອງຂາເຂົ້າ ທີ່ກັ່ນຕອງການສົ່ງຂໍ້ມູນເຫດການຜູ່ໃຊ້ທັງໝົດ ກ່ອນທີ່ພວກມັນຈະຖືກເຜີຍແຜ່. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດຄວບຄຸມ UI ຂອງລະບົບໂດຍບໍ່ຕ້ອງໃຫ້ຜູ່ໃຊ້ຈັດການໄດ້."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"ຂະຫຍາຍການສະແດງຜົນ"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ສາມາດຂະຫຍາຍເນື້ອຫາທີ່ສະແດງຜົນໄດ້. ແອັບພລິເຄຊັນທີ່ເປັນອັນຕະລາຍ ອາດປ່ຽນເນື້ອຫາທີ່ສະແດງໃນລັກສະນະ ທີ່ເຮັດໃຫ້ບໍ່ສາມາດນຳໃຊ້ອຸປະກອນໄດ້."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"ປິດລົງບາງສ່ວນ"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"ກຳນົດໃຫ້ໂຕຈັດການກິດຈະກຳຢູ່ໃນສະຖານະປິດລະບົບ ໂດຍບໍ່ໄດ້ປິດລະບົບຢ່າງສົມບູນ."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ຂັດຂວາງການສະລັບແອັບຯ"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"ອະນຸຍາດໃຫ້ແອັບຯ ກະຈາຍສັນຍານການແຈ້ງເຕືອນວ່າຂໍ້ຄວາມ SMS ໄດ້ຮັບແລ້ວ. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດຈະໃຊ້ສິ່ງນີ້ໃນການປອມແປງຂໍ້ຄວາມ SMS ຂາເຂົ້າ."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ສົ່ງການກະຈາຍ WAP-PUSH ທີ່ໄດ້ຮັບ"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"ອະນຸຍາດໃຫ້ແອັບຯສົ່ງການແຈ້ງເຕືອນໃນເວລາທີ່ໄດ້ຮັບຂໍ້ມຄວາມ WAP PUSH. ແອັບຯທີ່ເປັນອັນຕະລາຍ ອາດໃຊ້ການກະທຳນີ້ເພື່ອປອມການໄດ້ຮັບຂໍ້ຄວາມ MMS ຫຼືລັກປ່ຽນເນື້ອຫາຂອງໜ້າເວັບຕ່າງໆ ດ້ວຍສິ່ງອັນຕະລາຍທັງຫຼາຍຢ່າງງຽບໆ."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ສົ່ງການກະຈາຍຄະແນນເຄືອຂ່າຍ"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"ອະນຸຍາດໃຫ້ແອັບຯກະຈາຍການແຈ້ງເຕືອນທີ່ເຄືອຂ່າຍຕ່າງໆຈຳເປັນຖືກໃຊ້ນັບຄະແນນ. ບໍ່ມີຄວາມຈຳເປັນໃນແອັບຯທົ່ວໄປ."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"ຈຳກັດຈຳນວນຂອງໂປຣເຊສທີ່ເຮັດວຽກຢູ່"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"ອະນຸຍາດໃຫ້ແອັບຯຄວບຄຸມຈຳນວນສູງສຸດ ຂອງໂປຣເຊສທີ່ຈະເຮັດວຽກ. ບໍ່ຄວນຖືກໃຊ້ກັບແອັບພລິເຄຊັນທົ່ວໄປ."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"ບັງຄັບໃຫ້ແອັບຯທີ່ເຮັດວຽກຢູ່ພື້ນຫຼັງປິດໂຕລົງ"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຊື່ອມໂຍງກັບສ່ວນຕິດຕໍ່ລະດັບເທິງສຸດ ຂອງບໍລິການ VPN. ແອັບຯທົ່ວໄປບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"ເຊື່ອມໂຍງກັບພາບພື້ນຫຼັງ"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ອະນຸຍາດໃຫ້ຜູ່ໃຊ້ເຊື່ອມໂຍງກັບສ່ວນຕິດຕໍ່ລະດັບສູງສຸດ ຂອງພາບພື້ນຫຼັງໃດນຶ່ງ. ແອັບຯທຳມະດາບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"ເຊື່ອມໂຍງກັບຕົວຕິດຕໍ່ດ້ວຍສຽງ"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຊື່ອມໂຍງສ່ວນຕິດຕໍ່ລະດັບສູງສຸດຂອງບໍລິການການຕິດຕໍ່ດ້ວຍສຽງ."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ຜູກກັນເພື່ອສະແດງຜົນທາງໄກ."</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ອະນຸຍາດໃຫ້ຜູ່ຖືຜູກກັບສ່ວນຕິດຕໍ່ລະດັບສູງສຸດ ຂອງການສະແດງຜົນທາງໄກ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ເຊື່ອມໂຍງໄປຫາບໍລິການວິດເຈັດ"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ອະນຸຍາດໃຫ້ຜູ່ຖືຜູກກັບອິນເຕີເຟດລະດັບສູງສຸດ ຂອງບໍລິການວິເຈັດ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"ເຊື່ອມໂຍງກັບການບໍລິການຂອງຜູ່ໃຫ້ບໍລິການເສັ້ນທາງ"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງສາມາດເຊື່ອມໂຍງກັບທຸກໆຜູ່ໃຫ້ບໍລິການເສັ້ນທາງທີ່ລົງທະບຽນ. ບໍ່ຄວນຈະໄດ້ໃຊ້ໃນແອັບຯທົ່ວໄປ."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ຕິດຕໍ່ກັບຜູ່ເບິ່ງແຍງອຸປະກອນ"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງສົ່ງເຈດຕະນາຫາຜູ່ເບິ່ງແຍງລະບົບອຸປະກອນ. ແອັບຯທົ່ວໄປບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"ຜູກກັບການປ້ອນຂໍ້ມູນເຂົ້າໂທລະທັດ"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ອະນຸຍາດໃຫ້ແອັບຯໃຊ້ທຸກຕົວຖອດລະຫັດສື່ທີ່ຕິດຕັ້ງໄວ້ແລ້ວ ເພື່ອການຖອດລະຫັດການຫຼິ້ນໄຟລ໌ຕ່າງໆ."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"ຈັດການໜັງສືຮັບຮອງທີ່ເຊື່ອຖືໄດ້."</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"ອະນຸຍາດໃຫ້ແອັບຯ ຕິດຕັ້ງ ແລະ ຖອນການຕິດຕັ້ງໃບຢັ້ງຢືນ CA ທີ່ເປັນໃບຮັບຮອງທີ່ເຊື່ອຖືໄດ້."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"ເປີດແອັບພລິເຄຊັນໃນເວລາທີ່ບໍ່ເຮັດວຽກ"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ນີ້ຈະເປັນການອະນຸຍາດໃຫ້ລະບົບ Android ສາມາດເປີດແອັບພລິເຄຊັນໃນພື້ນຫຼັງໄດ້ໃນຂະນະທີ່ອຸປະກອນບໍ່ຖືກນຳໃຊ້."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"ເຊື່ອມຫາບໍລິການທີ່ບໍ່ໄດ້ນໍາໃຊ້"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"ສິດນີ້ຈະອະນຸຍາດໃຫ້ລະບົບ Android ສາມາດຜູກກັບການບໍລິການຂອງແອັບພລິເຄຊັນທີ່ບໍ່ໄດ້ເຮັດວຽກຢູ່ໄດ້."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"ອ່ານ/ຂຽນ ໃສ່ຊັບພະຍາກອນທີ່ເປັນຂອງກຸ່ມວິໄຈ"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນອ່ານ ແລະຂຽນ ໃສ່ທຸກຊັບພະຍາກອນທີ່ເປັນຂອງກຸ່ມວິນິໄສ; ຕົວຢ່າງ: ໄຟລ໌ໃນ /dev. ສິ່ງນີ້ອາດສົ່ງຜົນກະທົບຕໍ່ຄວາມສະຖຽນ ແລະຄວາມປອດໄພຂອງລະບົບ. ສິ່ງນີ້ຄວນໃຊ້ສຳຫຼັບການວິເຄາະບັນຫາຈຳເພາະ ຂອງບາງຮາດແວໂດຍຜູ່ຜະລິດ ຫຼືຜູ່ປະຕິບັດການເທົ່ານັ້ນ."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"ເປີດ ຫຼືປິດນຳໃຊ້ອົງປະກອບຂອງແອັບຯ"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"ອະນຸຍາດໃຫ້ແອັບຯ ອ່ານຂໍ້ມູນໂປໄຟລ໌ສ່ວນໂຕໃນອຸປະກອນຂອງທ່ານເຊັ່ນ: ຊື່ຂອງທ່ານ ແລະຂໍ້ມູນການຕິດຕໍ່ຂອງທ່ານ. ນີ້ໝາຍຄວາມວ່າແອັບຯຈະສາມາດລະບຸໂຕຕົນຂອງທ່ານ ແລະສົ່ງຂໍ້ມູນໂປຣໄຟລ໌ຂອງທ່ານໃຫ້ຜູ່ອື່ນໄດ້."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"ແກ້ໄຂບັດລາຍຊື່ຜູ່ຕິດຕໍ່ຂອງທ່ານເອງ"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"ອະນຸຍາດໃຫ້ແອັບຯ ປ່ຽນແປງ ຫຼືເພີ່ມຂໍ້ມູນໃສ່ໂປຣໄຟລ໌ສ່ວນບຸກຄົນທີ່ເກັບໄວ້ໃນອຸປະກອນຂອງທ່ານ, ເຊັ່ນ: ຊື່ ແລະຂໍ້ມູນຕິດຕໍ່ທ່ານ. ນີ້ໝາຍຄວາມວ່າແອັບຯສາມາດບົ່ງບອກໂຕທ່ານ ແລະອາດສົ່ງຂໍ້ມູນໂປຣໄຟລ໌ຂອງທ່ານໃຫ້ຜູ່ອື່ນໄດ້."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"ເຊັນເຊີຮ່າງກາຍ (ເຊັ່ນ: ຕິດຕາມອັດຕາການເຕັ້ນຂອງຫົວໃຈ)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"ອະນຸຍາດໃຫ້ແອັບຯເຂົ້າເຖິງຂໍ້ມູນຈາກເຊັນເຊີທີ່ທ່ານໃຊ້ເພື່ອວັດແທກສິ່ງທີ່ເກີດຂຶ້ນໃນຮ່າງກາຍຂອງທ່ານ ເຊັ່ນ: ອັດຕາການເຕັ້ນຂອງຫົວໃຈ."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"ອ່ານການອັບເດດສັງຄົມອອນລາຍຂອງທ່ານ"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"ອະນຸຍາດໃຫ້ແອັບຯ ເຂົ້າເຖິງ ແລະຊິ້ງຂໍ້ມູນຂ່າວສານສັງຄົມຈາກທ່ານ ແລະໝູ່ຂອງທ່ານ. ຄວນລະມັດລະວັງໃນເວລາທີ່ແລກປ່ຽນຂໍ້ມູນ -- ນີ້ຈະເປັນການອະນຸຍາດໃຫ້ແອັບຯ ອ່ານການສື່ສານລະຫວ່າງທ່ານ ກັບໝູ່ຂອງທ່ານເທິງເຄືອຂ່າຍສັງຄົມ ໂດຍບໍ່ຄຳນຶງເຖິງຄວາມລັບ. ໝາຍເຫດ: ການກຳນົດສິດນີ້ອາດບໍ່ໄດ້ບັງຄັບໃຊ້ໃນທຸກເຄືອຂ່າຍສັງຄົມ."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"ຂຽນໃສ່ເຄືອຂ່າຍສັງຄົມຂອງທ່ານ"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"ອະນຸຍາດໃຫ້ແອັບຯຄວບຄຸມຄວາມສາມາດຂອງໂທລະສັບໃນອຸປະກອນ. ແອັບຯທີ່ມີການອະນຸຍາດນີ້ຈະສາມາດສະລັບເຄືອຂ່າຍ, ເປີດ ຫຼືປິດສັນຍານວິທະຍຸ ແລະຄວາມສາມາດອື່ນທີ່ຄ້າຍກັນ ໂດຍບໍ່ມີການແຈ້ງເຕືອນທ່ານ."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ອ່ານສະຖານະ ແລະຂໍ້ມູນລະບຸໂຕຕົນຂອງໂທລະສັບ"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"ອະນຸຍາດໃຫ້ແອັບຯ ເຂົ້າເຖິງຄວາມສາມາດການໂທລະສັບຂອງອຸປະກອນ. ການກຳນົດສິດນີ້ເຮັດໃຫ້ແອັບຯສາມາດກວດສອບເບີໂທລະສັບ ແລະ ID ຂອງອຸປະກອນ, ບໍ່ວ່າການໂທຈະຍັງດຳເນີນຢູ່ ແລະເບີປາຍທາງເຊື່ອມຕໍ່ຢູ່ຫຼືບໍ່ກໍຕາມ."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ອ່ານຄ່າສະຖານະລະອຽດຂອງໂທລະສັບ"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"ອະນຸຍາດໃຫ້ແອັບຯເຂົ້າເຖິງສະຖານະໂດຍລະອຽດຂອງໂທລະສັບ. ການອະນຸຍາດນີ້ຈະຍິນຍອມໃຫ້ແອັບຯກວດສອບສະຖານະການໂທແທ້ໆ ວ່າກຳລັງດຳເນີນຢູ່ ຫຼືຢູ່ໃນແບັກກຣາວ, ຄວາມລົ້ມເຫລວຂອງການໂທ, ສະຖານະການເຊື່ອມຕໍ່ຂໍ້ມູນແບບລະອຽດ ແລະຄວາມລົ້ມເຫລວຂອງການເຊື່ອມຕໍ່ຂໍ້ມູນ."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ຂັດຂວາງບໍ່ໃຫ້ປິດໜ້າຈໍແທັບເລັດ"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ຂັດຂວາງບໍ່ໃຫ້ໂທລະສັບປິດໜ້າຈໍ"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ອະນຸຍາດໃຫ້ແອັບຯ ປ້ອງກັນບໍ່ໃຫ້ປິດໜ້າຈໍແທັບເລັດ."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"ປ່ຽນສະຖານະ WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"ອະນຸຍາດໃຫ້ແອັບຯເຊື່ອມຕໍ່ ແລະຕັດການເຊື່ອມຕໍ່ແທັບເລັດຈາກເຄືອຂ່າຍ WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"ອະນຸຍາດໃຫ້ແອັບຯເຊື່ອມຕໍ່ ແລະຕັດການເຊື່ອມຕໍ່ຂອງໂທລະສັບຈາກເຄືອຂ່າຍ WiMax ໄດ້."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ຄະແນນເຄືອຂ່າຍ"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"ອະນຸຍາດໃຫ້ແອັບຯຈັດລຳດັບເຄືອຂ່າຍ ແລະ ຊ່ວຍຕັດສິນໃຈວ່າເຄືອຂ່າຍໃດທີ່ແທັບເລັດຄວນນຳໃຊ້."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"ອະນຸຍາດໃຫ້ແອັບຯຈັດລຳດັບເຄືອຂ່າຍ ແລະ ຊ່ວຍຕັດສິນໃຈວ່າເຄືອຂ່າຍໃດທີ່ໂທລະສັບຄວນນຳໃຊ້."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"ຈັບຄູ່ກັບອຸປະກອນ Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"ອະນຸຍາດໃຫ້ແອັບຯເບິ່ງການຕັ້ງຄ່າຂອງ Bluetooth ໃນແທັບເລັດ ຕະຫຼອດຈົນເຊື່ອມຕໍ່ ແລະຍອມຮັບການເຊື່ອມຕໍ່ກັບອຸປະກອນທີ່ຈັບຄູ່ກັນແລ້ວ."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"ອະນຸຍາດໃຫ້ແອັບຯເບິ່ງການຕັ້ງຄ່າຂອງ Bluetooth ໃນໂທລະສັບ, ຮວມທັງໃຫ້ສ້າງ ແລະຮັບການເຊື່ອມຕໍ່ຈາກອຸປະກອນທີ່ຈັບຄູ່ກັນ."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"ອະນຸຍາດໃຫ້ແອັບຯດຶງຂໍ້ມູນ, ກວດສອບ ແລະລຶບລ້າງການແຈ້ງເຕືອນ ຮວມທັງພວກທີ່ໂພສໂດຍແອັບຯອື່ນໆນຳ."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ເຊື່ອມໂຍງກັບບໍລິການໂຕຟັງການແຈ້ງເຕືອນ"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຊື່ອມໂຍງສ່ວນຕິດຕໍ່ລະດັບເທິງສຸດ ຂອງຜູ່ຟັງບໍລິການການແຈ້ງເຕືອນ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ເຊື່ອມໂຍງກັບບໍລິການຜູ່ສະໜອງເງື່ອນໄຂ"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຊື່ອມໂຍງສ່ວນຕິດຕໍ່ລະດັບສູງສຸດຂອງບໍລິການສະໜອງເງື່ອນໄຂ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ຮ້ອງຂໍແອັບຯປັບຄ່າທີ່ສະໜອງໂດຍຜູ່ໃຫ້ບໍລິການ"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງຮ້ອງຂໍແອັບຯປັບຄ່າທີ່ສະໜອງໂດຍຜູ່ໃຫ້ບໍລິການ. ບໍ່ໜ້າຈະຕ້ອງການສຳລັບແອັບຯທົ່ວໄປ."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ຕິດຕາມເພື່ອສັງເກດສະພາບຂອງເຄືອຂ່າຍ"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັ່ນຕິດຕາມເພື່ອສັງເກດສະພາບຂອງເຄືອຂ່າຍ. ປົກກະຕິແລ້ວແອັບຯທຳມະດາຈະບໍ່ຕ້ອງການໃຊ້."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"ປ່ຽນການວັດແທ້ອຸປະກອນປ້ອນຂໍ້ມູນ"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"ອະນຸຍາດໃຫ້ແອັບຯແກ້ໄຂຄ່າການວັດແທ້ໜ້າຈໍສຳຜັດ. ແອັບຯທຳມະດາບໍ່ຄວນໃຊ້."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"ເຂົ້າເຖິງໃບຮັບຮອງ DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນຈັດຫາ ແລະນຳໃຊ້ໃບຮັບຮອງ DRM. ແອັບຯທຳມະດາບໍ່ຄວນຕ້ອງການໃຊ້."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"ຕັ້ງຄ່າກົດຂອງລະຫັດຜ່ານ"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"ຄວບຄຸມຄວາມຍາວຂອງໂຕອັກສອນທີ່ສາມາດໃຊ້ກັບລະຫັດປົດລັອກໜ້າຈໍ"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"ຕິດຕາມການພະຍາຍາມປົດລັອກໜ້າຈໍ"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ເຂົ້າເຖິງບ່ອນຈັດເກັບຂໍ້ມູນຄວາມປອດໄພດ້ວຍຄີກາດ."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"ຄວບຄຸມການສະແດງ ແລະການເຊື່ອງໂຕລັອກປຸ່ມກົດ"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນສາມາດຄວບຄຸມຄີກາດໄດ້."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"ຕິດຕາມການປ່ຽນແປງສະຖານະການເຊື່ອຖືກ."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນຕິດຕາມການປ່ຽນແປງໃນສະຖານະການເຊື່ອຖື."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ເຊື່ອມໂຍງຫາບໍລິການຕົວແທນການເຊື່ອຖື"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນເຊື່ອມໂຍງກັບບໍລິການຕົວແທນທີ່ເຊື່ອຖືໄດ້."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"ຕິດຕໍ່ກັບລະບົບອັບເດດ ແລະລະບົບກູ້ຂໍ້ມູນ."</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນຕິດຕໍ່ກັບລະບົບກູ້ຂໍ້ມູນ ແລະການອັບເດດລະບົບ."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"ແຕະສອງເທື່ອສຳລັບການຄວບຄຸມການຊູມ"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"ພາບພື້ນຫຼັງ"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"ປ່ຽນພາບພື້ນຫຼັງ"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ໂຕຟັງການແຈ້ງເຕືອນ"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ຜູ່ສະໜອງເງື່ອນໄຂ"</string>
<string name="vpn_title" msgid="19615213552042827">"ເປີດນຳໃຊ້ VPN ແລ້ວ"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"ເປີດໃຊ້ VPN ໂດຍ <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"ແຕະເພື່ອຈັດການເຄືອຂ່າຍ."</string>
@@ -1697,7 +1657,7 @@
<string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"PIN ປະຈຸບັນ"</string>
<string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"ລະຫັດ PIN ໃໝ່"</string>
<string name="restr_pin_confirm_pin" msgid="8501523829633146239">"ຢືນຢັນລະຫັດ PIN ໃໝ່"</string>
- <string name="restr_pin_create_pin" msgid="8017600000263450337">"ສ້າງ PIN ສໍາລັບການປັບປຸງຂໍ້ຈໍາກັດ"</string>
+ <string name="restr_pin_create_pin" msgid="8017600000263450337">"ສ້າງ PIN ສໍາລັບການປັບປຸງຂໍ້ຈໍາກັດ"</string>
<string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN ບໍ່ກົງກັນ. ລອງໃໝ່ອີກຄັ້ງ."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN ສັ້ນເກີນໄປ. ຕ້ອງມີຢ່າງໜ້ອຍ 4 ຫຼັກ."</string>
<plurals name="restr_pin_countdown">
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 7250f02..c61b4e6 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> d."</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> d. <xliff:g id="HOURS">%2$d</xliff:g> val."</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> d. <xliff:g id="HOURS">%2$d</xliff:g> val."</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> val."</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> val. <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> val. <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min."</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min. <xliff:g id="SECONDS">%2$d</xliff:g> sek."</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min. <xliff:g id="SECONDS">%2$d</xliff:g> sek."</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sek."</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sek."</string>
<string name="untitled" msgid="4638956954852782576">"<Be pavadinimo>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinchronizuoti"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Per daug <xliff:g id="CONTENT_TYPE">%s</xliff:g> trynimo."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Planšetinio kompiuterio atmintis pilna. Kad atlaisvintumėte vietos, ištrinkite kelis failus."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Laikrodžio saugykla pilna. Ištrinkite kelis failus, kad atlaisvintumėte vietos."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefono atmintis pilna. Ištrinkite kai kuriuos failus, kad atlaisvintumėte vietos."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Tinklas gali būti stebimas"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Nežinoma trečioji šalis"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Skambutis įjungtas"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Išsijungia..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Planšetinio kompiuterio veikimas bus sustabdytas."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Laikrodis išsijungs."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefonas bus išjungtas."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Ar norite išjungti?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Iš naujo įkelti operacinę sistemą saugos režimu"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lėktuvo režimas"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ĮJUNGTAS lėktuvo režimas"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"lėktuvo režimas IŠJUNGTAS"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Nustatymai"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Paslaugos, už kurias mokėjote"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Atlikite mokamus veiksmus."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Jūsų pranešimai"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"pašalinti sparčiuosius klavišus"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Programai leidžiama pašalinti sparčiuosius klavišus iš pagrindinio ekrano be naudotojo įsikišimo."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"peradresuoti išsiunčiamuosius skambučius"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Leidžiama programai peržiūrėti renkamą numerį išsiunčiamojo skambučio metu suteikiant galimybę peradresuoti skambutį kitu numeriu arba visiškai nutraukti skambutį."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Leidžiama programai atlikti išsiunčiamuosius skambučius ir keisti renkamą numerį. Šis leidimas suteikia teisę programai stebėti, peradresuoti ar neleisti išsiunčiamųjų skambučių."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"gauti teksto pranešimus (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Leidžiama programai gauti ir apdoroti SMS pranešimus. Tai reiškia, kad programa gali stebėti ir ištrinti į jūsų įrenginį siunčiamus pranešimus jums jų neparodžiusi."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"gauti teksto pranešimus (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Leidžiama programai nuskaityti aktyvaus lango turinį. Kenkėjiškos programos gali bandyti išgauti viso lango turinį ir tirti visą jo tekstą, išskyrus slaptažodžius."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"laikinai įgalinti pritaikymą neįgaliesiems"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Leidžiama programai laikinai įgalinti pritaikymą neįgaliesiems įrenginyje. Kenkėjiškos programos pritaikymą neįgaliesiems gali įgalinti be naudotojo sutikimo."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"gauti lango prieigos raktą"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Programai leidžiama gauti lango prieigos raktą. Kenkėjiškos programos gali vykdyti neteisėtą sąveiką su programos langu mėgdžiodamos sistemą."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"gauti kadrų statistinius duomenis"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Programai leidžiama rinkti kadrų statistinius duomenis. Kenkėjiškos programos gali stebėti kadrų statistinius duomenis iš kitų programų langų."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"gauti lango informaciją"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Leidžiama programai iš langų tvarkytuvės gauti informaciją apie langus. Kenkėjiškos programos gali gauti informaciją, kuri skirta naudoti sistemos viduje."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtrų įvykiai"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Leidžiama programai registruoti įvesties filtrą, kuriuo filtruojamas visų naudotojo įvykių srautas prieš juos išsiunčiant. Kenkėjiška programa gali kontroliuoti sistemos naudotojo sąsają be naudotojo įsikišimo."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"didinti pateiktį"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Leidžiama programai didinti pateikties turinį. Kenkėjiškos programos gali pakeisti pateikties turinį taip, kad nebūtų galima naudoti įrenginio."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"dalinis išjungimas"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Veiklos tvarkyklę perjungia į išsijungimo būseną. Neišjungia visiškai."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"neleisti perjungti programų"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Leidžiama programai pateikti pranešimą, kad buvo gautas SMS pranešimas. Kenkėjiškos programos gali tai naudoti, kad klastotų gaunamuosius SMS pranešimus."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"siųsti „WAP-PUSH-received“ perdavimą"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Leidžiama programai pateikti pranešimą, kai gaunamas WAP PUSH pranešimas. Kenkėjiškos programos gali tai naudoti, kad klastotų MMS pranešimo gavimą ar kad nepastebimai pakeistų bet kurio tinklalapio turinį kenkėjiškais variantais."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"siųsti tinklų transliavimo įvertinimą"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Programai leidžiama transliuoti pranešimą, kad reikia įvertinti tinklus. Niekada nereikia įprastoms programoms."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"riboti vykdomų procesų skaičių"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Leidžiama programai valdyti didžiausią vykdomų procesų skaičių. Nereikalinga įprastoms programoms."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"priverstinai uždaryti fonines programas"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Leidžiama savininkui susisaistyti su aukščiausio lygio VPN paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"susaistyti su darbalaukio fonu"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Leidžiama savininką susaistyti su aukščiausio lygio darbalaukio fono sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"susaistyti su sąveikos balsu priemone"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Turėtojui leidžiama susaistyti programą su sąveikos balsu paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to niekada neturėtų prireikti."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"susisaistyti su nuotoliniu ekranu"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Leidžiama savininkui susisaistyti su aukščiausiojo lygio nuotolinio ekrano sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"susaistyti su valdiklio paslauga"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Leidžiama savininkui susisaistyti su aukščiausio lygio valdiklio paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"susisaistyti su maršruto parinkimo paslauga"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Savininkui leidžiama susisaistyti su bet kokiomis registruotomis maršrutų parinkimo paslaugomis. To niekada neturėtų prireikti naudojant įprastas programas."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"sąveikauti su įrenginio administratoriumi"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Leidžiama savininkui siųsti tikslus įrenginio administratoriui. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"susisaistyti su TV įvestimi"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Leidžiama programai naudoti bet kurį įdiegtą medijos dekoderį norint iššifruoti atkūrimą."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"tvarkyti patikimus prisijungimo duomenis"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Programoje galima įdiegti ir iš jos pašalinti CA sertifikatus kaip patikimus prisijungimo duomenis."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"paleisti programą, kai įrenginys yra neaktyvus"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Šiuo leidimu sistemai „Android“ leidžiama fone paleisti programą, kai įrenginys yra nenaudojamas."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"susaistyti su neaktyviomis paslaugomis"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Šiuo leidimu „Android“ sistemai leidžiama susaistyti su programos neaktyviomis paslaugomis."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"skaityti / rašyti ištekliuose, priklausančiuose diagnostikai"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Leidžiama programai skaityti ir rašyti visuose diagnostikos grupei priklausančiuose ištekliuose, pvz., failuose, esančiuose /dev. Tai gali paveikti sistemos stabilumą ir saugą. Tai turėtų būti naudojama TIK gamintojui ar operatoriui atliekant aparatinės įrangos diagnostiką."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"įgalinti programos komponentus arba jų neleisti"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Programai leidžiama skaityti įrenginyje saugomą asmeninę profilio informaciją, pvz., vardą, pavardę ir kontaktinę informaciją. Tai reiškia, kad programa gali nustatyti tapatybę ir siųsti profilio informaciją kitiems."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"keisti jūsų kontaktinę kortelę"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Leidžiama programai keisti įrenginyje saugomą asmeninę profilio informaciją, pvz., vardą, pavardę ir kontaktinę informaciją, arba jos pridėti. Tai reiškia, kad programa gali nustatyti tapatybę ir siųsti profilio informaciją kitiems."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"kūno jut. (pvz., pulso d. t.)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Programai leidžiama pasiekti naudojamų jutiklių duomenis, siekiant įvertinti, kas vyksta jūsų kūne, pvz., pulso dažnį."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"skaityti socialinį srautą"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Leidžiama programai pasiekti ir sinchronizuoti viešas naujienas iš jūsų ir jūsų draugų. Būkite atidūs bendrindami informaciją – programai leidžiama skaityti korespondenciją tarp jūsų ir draugų viešuosiuose tinkluose, neatsižvelgiant į konfidencialumą. Pastaba: šis leidimas negali būti taikomas visuose viešuosiuose tinkluose."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"rašyti į socialinį srautą"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Leidžiama programai valdyti įrenginio telefono funkcijas. Šį leidimą turinti programa gali perjungti tinklus, įjungti ir išjungti telefono radiją ir atlikti panašius veiksmus jūsų neįspėdama."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"skaityti telefono būseną ir tapatybę"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Leidžiama programai pasiekti telefono funkcijas įrenginyje. Šis leidimas suteikia teisę programai nustatyti telefono numerį ir įrenginio ID, tai, ar skambutis aktyvus, ir skambučiu prijungtą nuotolinį numerį."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"skaityti tikslias telefono būsenas"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Programai leidžiama pasiekti tikslias telefono būsenas. Šiuo leidimu programai leidžiama nustatyti tikrą skambučio būseną, ar skambutis yra aktyvus, ar vyksta fone, ar paskambinti nepavyksta, tikslią duomenų ryšio būseną ir ar nepavyksta užmegzti duomenų ryšio."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"neleisti planšetiniam kompiuteriui užmigti"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"neleisti telefonui snausti"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Leidžiama programai neleisti planšetiniam kompiuteriui užmigti."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Keisti „WiMAX“ būseną"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Leidžia programai prijungti planšetinį kompiuterį prie „WiMAX“ ryšio tinklų ir nuo jų atjungti."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Leidžia programai prijungti telefoną prie „WiMAX“ ryšio tinklų ir nuo jų atjungti."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"įvertinti tinklus"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Programai leidžiama įvertinti tinklus ir nustatyti, kuriems tinklams planšetiniame kompiuteryje turėtų būti taikoma pirmenybė."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Programai leidžiama įvertinti tinklus ir nustatyti, kuriems tinklams telefone turėtų būti taikoma pirmenybė."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"susieti su „Bluetooth“ įrenginiais"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Leidžiama programai peržiūrėti „Bluetooth“ konfigūraciją planšetiniame kompiuteryje ir užmegzti bei priimti ryšius iš susietų įrenginių."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Leidžiama programai peržiūrėti „Bluetooth“ konfigūraciją telefone ir užmegzti bei priimti ryšius iš susietų įrenginių."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Programai leidžiama gauti, patikrinti ir išvalyti pranešimus, įskaitant pranešimus, kuriuos paskelbė kitos programos."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"susisaistyti su pranešimų skaitymo priemonės paslauga"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Leidžiama turėtojui susisaistyti su pranešimų skaitymo priemonės paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"susaistyti su sąlygos teikėjo paslauga"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Turėtojui leidžiama susaistyti programą su sąlygos teikėjo paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to niekada neturėtų prireikti."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"iškviesti operatoriaus pateiktą konfigūravimo programą"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Turėtojui leidžiama iškviesti operatoriaus pateiktą konfigūravimo programą. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"vykdyti tinklo sąlygų stebėjimą"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Leidžiama programai vykdyti tinklo sąlygų stebėjimą. To niekada neturėtų prireikti naudojant įprastas programas."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"keisti įvesties įrenginio kalibravimą"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Leidžiama programai keisti jutiklinio ekrano kalibravimo parametrus. Neturėtų prireikti naudojant įprastas programas."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"gali pasiekti DRM sertifikatus"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Programai leidžiama pasiekti ir naudoti DRM sertifikatus. Neturėtų prireikti naudojant įprastas programas."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nustatyti slaptažodžio taisykles"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Valdyti leidžiamą ekrano atrakinimo slaptažodžių ilgį ir leidžiamus naudoti simbolius."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Stebėti bandymus atrakinti ekraną"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Programai leidžiama pasiekti „KeyGuard“ saugyklą."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Valdyti „KeyGuard“ rodymą ir slėpimą"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Programai leidžiama valdyti „KeyGuard“."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Atsižvelgti į patikimos būsenos pakeitimus."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Programai leidžiama atsižvelgti į patikimos būsenos pakeitimus."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Susisaistyti su „trust agent“ paslauga"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Programai leidžiama susisaistyti su „trust agent“ paslauga."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Sąveikauti su naujiniu ir atkūrimo sistema"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Programai leidžiama sąveikauti su atkūrimo sistema ir sistemos naujiniais."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dukart palieskite, kad valdytumėte mastelio keitimą"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Darbalaukio fonas"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Keisti darbalaukio foną"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Pranešimų skaitymo priemonė"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Sąlygos teikėjas"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN suaktyvintas"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN suaktyvino „<xliff:g id="APP">%s</xliff:g>“"</string>
<string name="vpn_text" msgid="3011306607126450322">"Palieskite, kad valdytumėte tinklą."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 4c48278..130b27e 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> d."</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> d. <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> d. <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> h"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
<string name="untitled" msgid="4638956954852782576">"<Bez nosaukuma>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinhronizācija"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Pārāk daudz <xliff:g id="CONTENT_TYPE">%s</xliff:g> dzēsto vienumu."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Planšetdatora atmiņa ir pilna. Dzēsiet dažus failus, lai atbrīvotu vietu."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Pulksteņa atmiņa ir pilna. Dzēsiet dažus failus, lai atbrīvotu vietu."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Tālruņa atmiņa ir pilna! Dzēsiet dažus failus, lai atbrīvotu vietu."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Iespējams, tīklā veiktās darbības tiek pārraudzītas."</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Nezināma trešā puse"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Zvanītājs ieslēgts"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Notiek izslēgšana..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Planšetdators tiks beidzēts."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Pulkstenis tiks izslēgts."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Tālrunis tiks izslēgts."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Vai vēlaties izslēgt?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Atsāknēšana drošajā režīmā"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lidojuma režīms"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lidojuma režīms ir IESLĒGTS."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lidojuma režīms ir IZSLĒGTS."</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Iestatījumi"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"Pārsniedz"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Maksas pakalpojumi"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Veikt darbības, par kurām, iespējams, būs jāmaksā."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Jūsu ziņojumi"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"atinstalēt saīsnes"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Ļauj lietojumprogrammai noņemt saīsnes no sākuma ekrāna, nejautājot lietotājam."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"pārmaršrutēt izejošos zvanus"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Ļauj lietotnei skatīt ievadīto tālruņa numuru izejošā zvana laikā un piedāvā iespēju šo zvanu pāradresēt uz citu numuru vai vispār pārtraukt zvanu."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Ļauj lietotnei apstrādāt izejošos zvanus un mainīt numuru, uz kuru tiks zvanīts. Ar šo atļauju lietotne var pārraudzīt, novirzīt vai neatļaut izejošos zvanus."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"saņemt īsziņas (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Ļauj lietotnei saņemt un apstrādāt īsziņas. Tas nozīmē, ka lietotne var pārraudzīt vai dzēst uz jūsu ierīci nosūtītos ziņojumus, neparādot tos jums."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"saņemt ziņojumus (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Ļauj lietotnei izgūt aktīva loga saturu. Ļaunprātīgas lietotnes var izgūt visu loga saturu un pārbaudīt visu tā tekstu, izņemot paroles."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"Īslaicīga pieejamības režīma iespējošana"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Ļauj lietojumprogrammai īslaicīgi ierīcē iespējot pieejamības režīmu. Ļaunprātīgas lietotnes var iespējot pieejamības režīmu bez lietotāja atļaujas."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"Loga marķiera izgūšana"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Ļauj lietojumprogrammai izgūt loga marķieri. Ļaunprātīgas lietotnes var veikt neautorizētas darbības ar lietojumprogrammas logu, izliekoties par attiecīgo sistēmu."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"Ietvaru statistikas izgūšana"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Ļauj lietojumprogrammai apkopot ietvaru statistiku. Ļaunprātīgas lietotnes var iegūt logu ietvaru statistiku no citām lietotnēm."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"Izgūt informāciju par logiem"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Ļauj lietojumprogrammai no logu pārvaldnieka izgūt informāciju par logiem. Ļaunprātīgas lietotnes var izgūt informāciju, kas ir paredzēta iekšējai izmantošanai sistēmā."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"Filtrēt notikumus"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Ļauj lietojumprogrammai reģistrēt ieejas filtru, kas filtrē visu lietotāja notikumu straumi, pirms notikumi tiek nosūtīti. Ļaunprātīga lietotne var kontrolēt sistēmas lietotāja saskarni, nejautājot lietotājam."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"displeja palielināšana"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Ļauj lietojumprogrammai palielināt displeja saturu. Ļaunprātīgas lietotnes var pārveidot displeja saturu tā, ka ierīce kļūst nelietojama."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"daļēja izslēgšana"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Liek darbību pārvaldniekam pāriet izslēgšanas stāvoklī. Neveic pilnīgu izslēgšanu."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"novērst lietojumprogrammu pārslēgšanu"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Ļauj lietotnei pārraidīt paziņojumu par saņemtu īsziņu. Ļaunprātīgas lietotnes to var izmantot, lai viltotu ienākošas īsziņas."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"sūtīt WAP-PUSH-saņemto apraidi"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Ļauj lietotnei pārraidīt paziņojumu par to, ka ir saņemts WAP PUSH ziņojums. Ļaunprātīgas lietotnes to var izmantot, lai viltotu multiziņas saņemšanu vai jebkuras tīmekļa lapas saturu nemanāmi nomainītu ar ļaunprātīgiem variantiem."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"apraidīt ziņojumu par tīklu vērtēšanu"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Ļauj lietotnei apraidīt paziņojumu, ka tīkli ir jānovērtē. Parastām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"ierobežot aktīvo procesu skaitu"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Ļauj lietotnei kontrolēt izpildāmo procesu maksimālo skaitu. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"veikt fonā darbojošos lietotņu piespiedu aizvēršanu"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Ļauj īpašniekam izveidot saiti ar VPN pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"saistīt ar tapeti"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ļauj īpašniekam piesaistīt tapetes augstākā līmeņa lietotāja saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"Saistīšana ar balss mijiedarbības elementu"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Ļauj īpašniekam izveidot savienojumu ar balss mijiedarbības pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"Saites izveide ar attālu displeju"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ļauj īpašniekam izveidot saiti ar attāla displeja augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"saistīt ar logrīka pakalpojumu"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ļauj īpašniekam izveidot saiti ar logrīka pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"Saistīšana ar maršruta nodrošinātāja pakalpojumu"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Ļauj īpašniekam saistīt jebkādus reģistrētus maršrutēšanas nodrošinātājus. Parastām lietotnēm šī atļauja nekad nav nepieciešama."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"mijiedarboties ar ierīces administratoru"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ļauj īpašniekam nosūtīt informāciju par nodomiem ierīces administratoram. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"Izveidot saiti ar TV ieeju"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ļauj lietotnei izmantot jebkuru instalētu multivides failu dekodētāju, lai dekodētu failus atskaņošanai."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Uzticamo akreditācijas datu pārvaldība"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ļauj lietotnei instalēt un atinstalēt CA sertifikātus kā uzticamus akreditācijas datus."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"Lietojumprogrammas darbība dīkstāves laikā"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ar šo atļauju Android sistēmā lietojumprogramma darbojas fonā, kad ierīce netiek lietota."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"saistīšana ar neaktīviem pakalpojumiem"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Pamatojoties uz šo atļauju, Android sistēma var izveidot saiti ar lietojumprogrammas neaktīvajiem pakalpojumiem."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lasīt grupas “diag” resursus un rakstīt tajos"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Ļauj lietotnei lasīt un rakstīt jebkurā resursā, kas pieder diagnostikas grupai, piemēram, failiem mapē /dev. Tas var ietekmēt sistēmas stabilitāti un drošību. Var izmantot ražotājs vai operators TIKAI konkrētas aparatūras diagnostikai."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"iespējot vai atspējot lietotnes komponentus"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Ļauj lietotnei lasīt ierīcē saglabāto personīgā profila informāciju, piemēram, jūsu vārdu un kontaktinformāciju. Tas nozīmē, ka lietotne var jūs identificēt un var nosūtīt jūsu profila informāciju citām personām."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"mainīt manu vizītkarti"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Ļauj lietotnei mainīt ierīcē saglabāto personīgā profila informāciju, piemēram, jūsu vārdu un kontaktinformāciju, vai pievienot tai citu informāciju. Tas nozīmē, ka lietotne var jūs identificēt un var nosūtīt jūsu profila informāciju citām personām."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"ķermeņa sensori (piemēram, sirdsdarbības monitori)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Ļauj lietotnei piekļūt to sensoru datiem, kurus izmantojat, lai novērtētu ķermeņa procesus, piemēram, sirdsdarbību."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"lasīt jūsu soc. tīklu straumi"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Ļauj lietotnei piekļūt sociālajiem atjauninājumiem no jums un jūsu draugiem un sinhronizēt tos. Esiet piesardzīgs, kad kopīgojat informāciju, — šādi lietotne var lasīt sociālajos tīklos ar draugiem veikto saziņu, neraugoties uz konfidencialitāti. Piezīme: šo atļauju nedrīkst piemērot visiem sociālajiem tīkliem."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"rakstīt sociālo tīklu straumē"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Ļauj lietotnei kontrolēt ierīces tālruņa funkcijas. Lietotne, kurai ir šī atļauja, var pārslēgt tīklus, ieslēgt un izslēgt tālruņa radio un veikt tamlīdzīgas darbības, nebrīdinot jūs."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lasīt tālruņa statusu un identitāti"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ļauj lietotnei piekļūt ierīces tālruņa funkcijām. Ar šo atļauju lietotne var noteikt tālruņa numuru un ierīču ID, zvana statusu un attālo numuru, ar ko ir izveidots savienojums, veicot zvanu."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"precīzu tālruņa statusa datu lasīšana"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Ļauj lietotnei piekļūt precīziem datiem par tālruņa statusu. Izmantojot šo atļauju, lietotne var noteikt zvana faktisko statusu, vai zvans ir aktīvs vai notiek fonā, vai zvans nav izdevies, kā arī precīzu datu savienojuma statusu un neizdevušos datu savienojumus."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"novērst planšetdatora pāriešanu miega režīmā"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"novērst tālruņa pāriešanu miega režīmā"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ļauj lietotnei novērst planšetdatora pāriešanu miega režīmā."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX statusa mainīšana"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Ļauj lietotnei izveidot un pārtraukt planšetdatora savienojumu ar WiMAX tīkliem."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Ļauj lietotnei izveidot un pārtraukt tālruņa savienojumu ar WiMAX tīkliem."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"vērtēt tīklus"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Ļauj lietotnei ranžēt tīklus un ietekmēt to, kuriem tīkliem planšetdators dos priekšroku."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Ļauj lietotnei ranžēt tīklus un ietekmēt to, kuriem tīkliem tālrunis dos priekšroku."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"savienot pārī ar Bluetooth ierīcēm"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Ļauj lietotnei skatīt Bluetooth konfigurāciju planšetdatorā, kā arī veidot un pieņemt savienojumus ar pārī savienotām ierīcēm."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Ļauj lietotnei skatīt Bluetooth konfigurāciju tālrunī, kā arī veidot un pieņemt savienojumus ar pārī savienotām ierīcēm."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Ļauj lietotnei izgūt, pārbaudīt un dzēst paziņojumus, tostarp lietotņu publicētos paziņojumus."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"saites izveidošana ar paziņojumu uztvērēja pakalpojumu"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ļauj īpašniekam izveidot saiti ar paziņojumu uztvērēja pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"Saistīšana ar nosacījumu sniedzēja pakalpojumu"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ļauj īpašniekam izveidot savienojumu ar drukas nosacījumu sniedzēja pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Operatora nodrošinātas konfigurācijas lietotnes izsaukšana"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ļauj īpašniekam izsaukt operatora nodrošināto konfigurācijas lietotni. Parastām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"iegūt informāciju par tīkla stāvokļa novērojumiem"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Ļauj lietojumprogrammai iegūt informāciju par tīkla stāvokļa novērojumiem. Parastām lietotnēm šī atļauja nekad nav nepieciešama."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"mainīt ievadierīces kalibrēšanu"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Ļauj lietotnei pārveidot skārienekrāna kalibrēšanas parametrus. Parastām lietotnēm šī atļauja nekad nav nepieciešama."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"Piekļuve digitālā satura tiesību pārvaldības sertifikātiem"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Ļauj lietojumprogrammai nodrošināt un izmantot digitālā satura tiesību pārvaldības sertifikātus. Parastām lietotnēm šī atļauja nekad nav nepieciešama."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Paroles kārtulu iestatīšana"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolē ekrāna atbloķēšanas parolē atļautās rakstzīmes un garumu."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Ekrāna atbloķēšanas mēģinājumu pārraudzīšana"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Ļauj lietojumprogrammai piekļūt krātuvei, kas aizsargāta ar atslēgu."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Pārvaldīt krātuves rādīšanu un paslēpšanu."</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Ļauj lietojumprogrammai pārvaldīt krātuvi."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Klausīties uzticamības statusa izmaiņas"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Ļauj lietojumprogrammai klausīties uzticamības statusa izmaiņas."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Izveidot savienojumu ar uzticamības pārbaudes pakalpojumu"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ļauj lietojumprogrammai izveidot savienojumu ar uzticamības pārbaudes pakalpojumu."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Mijiedarbošanās ar atjauninājumu un atkopšanas sistēmu"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Ļauj lietojumprogrammai mijiedarboties ar atkopšanas sistēmu un sistēmas atjauninājumiem."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Pieskarieties divreiz, lai kontrolētu tālummaiņu."</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fona tapete"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Tapetes maiņa"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Paziņojumu uztvērējs"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Nosacījumu sniedzējs"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN ir aktivizēts."</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Lietojumprogramma <xliff:g id="APP">%s</xliff:g> aktivizēja VPN."</string>
<string name="vpn_text" msgid="3011306607126450322">"Pieskarieties, lai pārvaldītu tīklu."</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index c609745..b35904b 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TБ"</string>
<string name="petabyteShort" msgid="5637816680144990219">"ПБ"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> өдөр"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> өдөр <xliff:g id="HOURS">%2$d</xliff:g> цаг"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> өдөр <xliff:g id="HOURS">%2$d</xliff:g> цаг"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> цаг"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> цаг <xliff:g id="MINUTES">%2$d</xliff:g> минут"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> цаг <xliff:g id="MINUTES">%2$d</xliff:g> мин"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> мин"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> мин <xliff:g id="SECONDS">%2$d</xliff:g> секунд"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> мин <xliff:g id="SECONDS">%2$d</xliff:g> сек"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> сек"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> сек"</string>
<string name="untitled" msgid="4638956954852782576">"<Гарчиггүй>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синк"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Хэт олон <xliff:g id="CONTENT_TYPE">%s</xliff:g> устгах."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Таблетийн сан дүүрсэн. Зай чөлөөлөх бол зарим файлыг устгана уу."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Цагны сан дүүрсэн. Зай чөлөөлөх бол зарим файлыг устгана уу."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Утасны сан дүүрсэн. Зай чөлөөлөх бол зарим файлыг устгана уу."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Сүлжээ хянагдаж байж болзошгүй"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Тодорхойгүй гуравдагч талаас"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Хонх ассан"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Унтрааж байна…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Таны таблет унтрах болно."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Таны цаг унтрах болно."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Таны утас унтрах болно."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Та унтраах уу?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Аюулгүй горимоор дахин асаах"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Нислэгийн горим"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Нислэгийн горим асав"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Нислэгийн горим унтарсан"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Тохиргоо"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Танаас төлбөр авдаг үйлчилгээнүүд"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Таны төлбөрт оруулах зүйлийг хийх."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Таны мессеж"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"товчлолыг устгах"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Аппликешн нь хэрэглэгчийн оролцоогүйгээр Нүүр дэлгэцний товчлолыг устгаж чадна."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"гарсан дуудлагыг чиглэлийг өөрчлөх"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Гадагш дуудлага хийх үед залгасан дугаарыг харах, дуудлагыг өөр дугаар руу шилжүүлэх, таслах боломжтой болгоно."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Апп нь дуудлага хийх болон залгаж байгаа дугаарыг өөрчлөх боломжтой. Энэ зөвшөөрөл нь апп-г залгасан дуудлагыг хаах, хянах болон дахин чиглүүлэх боломжтой болгодог."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"текст мессеж(SMS) хүлээж авах"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Апп нь SMS мессежийг хүлээн авах болон гүйцэтгэх боломжтой. Ингэснээр апп нь таны төхөөрөмжрүү илгээсэн мессежийг танд үзүүлэхгүйгээр хянах болон устгаж чадна."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"текст мессеж(МMS) хүлээж авах"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Апп нь идэвхтэй цонхны контентыг авах боломжтой. Хортой апп нь цонхны контентыг бүхэлд авах болон нууц үгнээс бусад бүх текстийг шалгаж болзошгүй"</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"Хялбар байдлыг түр идэвхтэй болгох"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Аппликешн нь төхөөрөмжийн хялбар байдлыг түр зуур идэвхжүүлэх боломжтой. Хортой апп нь хэрэглэгчийн зөвшөөрөлгүйгээр хялбар байдлыг идэвхжүүлж болзошгүй."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"цонхны токен авах"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Аппликешнд цонхны токен авах боломж олгоно. Хорлонтой апп-ууд системийн өмнөөс аппликешны цонхтой зөвшөөрөлгүйгээр харилцах боломжтой."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"фреймын статистик авах"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Аппликешнд фреймын статистикыг цуглуулах боломж олгоно. Хорлонтой апп-ууд виндовсын фреймын статистикыг өөр апп-с хянах боломжтой."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"цонхны мэдээллийг унших"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Аппликешн нь цонхны менежерээс цонхны талаар мэдээллийг дуудах боломжтой. Хортой апп нь дотоод системийн хэрэглээнд зориулагдсан мэдээллийг дуудаж болзошгүй."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"үйл явдлыг шүүх"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Аппликешн нь хэрэглэгчийн бүх үйл явдалын илгээгдэхээс өмнөх урсгалыг шүүж байгаа оролтын шүүлтйиг бүртгэх боломжтой. Хортой апп нь хэрэглэгчийн интервэшнгүйгээр системийн UI-г удирдах боломжтой."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"дэлгэц томруулах"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Аппликешн нь дэлгэцний контентийг өсгөх боломжтой. Хортой апп нь дэлгэцийн контентыг төхөөрөмжнөөс ашиглаж болохгүй болгон хувиргах боломжтой."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"хэсэгчилсэн унтраалт"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Активити менежерийг унтраана. Бүрэн унтраалтыг хийхгүй."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"апп шилжүүлэхийг хориглох"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Апп нь SMS мессеж хүлээн авсан талаарх мэдэгдлийг өргөн дамжуулах боломжтой. Хортой апп энийг ашиглан ирсэн SMS мессежийг хуурамчаар хийх боломжтой."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH-хүлээн авав өргөн дамжууллыг илгээх"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Аппликешн нь WAP PUSH мессеж хүлээж авсан мэдэгдлийг өргөн дамжуулах боломжтой. Хортой апп нь энийг ашиглан MMS мессеж хүлээн авсан гэж хуурамчаар мэдэгдэх эсвэл хортой хувьсагч агуулсан веб хуудасны контентыг чимээгүй орлуулах боломжтой."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"бүртгэгдсэн сүлжээнүүд рүү түгээх"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Апп-д сүлжээнүүдэд бүртгэгдсэн байх шаардлагатай мэдэгдлийг түгээх боломжийг олгоно. Энгийн апп-д хэзээ ч шаардагдахгүй."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"ажиллаж байгаа процессийн тоог хязгаарлах"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Апп нь нэг зэрэг ажиллах процессийн тооны дээд утгыг удирдах боломжтой. Энгийн апп-д хэзээ ч ашиглагдахгүй."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"арын апп-г хүчээр хаах"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Эзэмшигч нь VPN үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"ханын зурагтай холбох"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Эзэмшигч нь ханын зурагны дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-уудад шаардлагагүй."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"дуугаар харьцагчтай холбох"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Эзэмшигчид дуугаар харьцах үйлчилгээний дээд-түвшний интерфейстэй холбох боломж олгоно. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"алсын дэлгэцтэй холбогдох"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Эзэмшигчид алсын дэлгэц дэх дээд давхаргын интерфэйстэй холбогдох боломж олгоно. Энгийн апп-д шаардагдахгүй."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"виджет үйлчилгээтэй холбох"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Эзэмшигч нь виджет үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"маршрут нийлүүлэгчийн үйлчилгээтэй холбогдох"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Эзэмшигчид бүртгэгдсэн маршрут нийлүүлэгчтэй холбогдох боломж олгоно. Энгийн апп-уудад хэзээ ч шаардагдахгүй."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"төхөөрөмжийн админтай харилцан үйлчлэх"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Эзэмшигч нь төхөөрөмжийн админруу интент илгээх боломжтой. Энгийн апп-д шаардлагагүй."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"ТВ оролт холбох"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Апп нь тоглуулах үедээ код тайлахдаа суулгагдсан ямарч медиа код тайлагчийг ашиглах боломжтой."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"итгэмжлэгдсэн жуухуудыг удирдах"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Апп-д CA сертификатуудыг итгэмжлэгдсэн жуух байдлаар суулгах болон устгахыг зөвшөөрнө."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"Сул зогсолтын хугацаанд аппликешнийг ажиллуулна"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Энэ зөвшөөрөл нь Андройд системд төхөөрөмжийг ашиглахгүй байгаа үед аппликешныг далд ажиллуулах боломж олгоно."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"идэвхгүй үйлчилгээнүүдтэй холбогдох"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Энэ зөвшөөрөл Андройд системд аппликешний идэвхгүй үйлчилгээтэй холбогдох боломж олгоно."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"оношлох грүпийн эзэмшдэг нөөцрүү унших/бичих"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Апп нь оношлох грүпийн эзэмшдэг, жишээ нь /dev доторх файлууд, дурын нөөцийг унших бичих боломжтой.Энэ нь системийн тогвортой байдал болон аюулгүй байдалд бодитоор нөлөөлнө. Энэ нь үйлдвэрлэгч болон операторын хардверт-зориулсан оношлогоонд ашиглагдана."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"апп компонентыг идэвхжүүлэх эсвэл идэвхгүй болгох"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Апп нь таны нэр болон холбоо барих мэдээлэл зэрэг таны утсан дээр хадгалагдсан хувийн профайл мэдээллийг унших боломжтой. Ингэснээр апп нь танийг таньж чадах ба таны профайл мэдээллийг бусдад илгээх боломжтой."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"та өөрийн харилцагчийн картыг өөрчлөх"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Апп нь таны нэр болон холбоо барих мэдээлэл зэрэг таны төхөөрөмж дээр хадгалагдсан хувийн профайл мэдээллийг солих эсвэл нэмэх боломжтой. Ингэснээр апп нь танийг таньж чадах ба таны профайл мэдээллийг бусдад илгээх боломжтой."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"биеийн сенсор (зүрхний цохилт хянагч гэх мэт)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Зүрхний цохилт гэх мэт биеийн үзүүлэлт хэмждэг сенсоруудын дата-д хандалт хийх боломжийг апп-д олгоно."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"таны нийтийн урсгалаас унших"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Апп нь та болон таны найзуудын нийтийн шинэчлэлтэд хандах болон синк хийх боломжтой. Мэдээлэл хуваалцахдаа болгоомжтой байна уу - энэ нь апп-д нийтийн сүлжээндэх та болон таны найзууд хоорондын холбоог нууц эсэхээс үл хамааран унших боломжтой. Анхаар: энэ зөвшөөрөл нь бүх нийтийн сүлжээнд ашиглаж боломжгүй."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"Таны нийтийн урсгалруу бичих"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Апп-н төхөөрөмжийн утасны функцийг удирдах боломжтой. Энэ зөвшөөрөлтэй апп нь танд анхааруулахгүйгээр сүлжээг сэлгэх, утасны радиог асаах, унтраах боломжтой."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"утасны статус ба таниулбарыг унших"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Апп нь төхөөрөмжийн утасны функцд хандах боломжтой. Энэ зөвшөөрөл нь апп-д утасны дугаар болон төхөөрөмжийн ID-г, дуудлага идэвхтэй эсэх, холын дугаар дуудлагаар холбогдсон байгаа эсэхийг тогтоох боломжийг олгоно,"</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"утасны байдлыг нарийн унших"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Апп-д утасны тодорхой байдалд хандах боломжийг олгодог. Энэ зөвшөөрөл апп-д дуудлагын бодит статус, дуудлага идэвхтэй эсхүл ар талд тавигдсан эсэх, амжилтгүй дуудлага болон дата холболтын нарийн статус болон дата холболтын алдааг тодорхойлох боломж олгоно."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"таблетыг унтуулахгүй байлгах"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"утсыг унтуулахгүй байлгах"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Апп нь таблетыг унтахаас сэргийлэх боломжтой"</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX статусыг өөрчлөх"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Апп нь WiMAX сүлжээнд таблетыг холбох болон салгах боломжтой."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Апп нь WiMAX сүлжээнд утсыг холбох болон салгах боломжтой."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"бүртгэгдсэн сүлжээ"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Апп-д сүлжээнүүдийг эрэмбэлж, аль сүлжээнд таблетыг холбоход нөлөөлөх боломж олгоно."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Апп-д сүлжээнүүдийг эрэмбэлж, аль сүлжээнд утсыг холбоход нөлөөлөх боломж олгоно."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Блютүүт төхөөрөмжтэй хос үүсгэх"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Апп нь таблет дээрх блютүүт тохиргоог харах боломжтой ба хос болох төхөөрөмжтэй холболтыг зөвшөөрөх болон хийх боломжтой."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Апп нь утсан дээрх Блютүүт тохиргоог харах боломжтой ба хос болох төхөөрөмжтэй холболтыг зөвшөөрөх болон хийх боломжтой."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Апп нь бусад апп-уудын илгээсэн мэдэгдлүүдийг дуудах, шалгах, болон цэвэрлэх боломжтой."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"мэдэгдэл сонсогч үйлчилгээтэй холбох"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Эзэмшигч нь мэдэгдэл сонсох үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"нөхцөл нийлүүлэгч үйлчилгээнд холбох"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Эзэмшигчид нөхцөл нийлүүлэгч үйлчилгээний дээд-түвшний интерфейстэй холбох боломж олгоно. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"үүрэн компанийн нийлүүлсэн тохируулгын апп-г өдөөх"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Эзэмшигчид үүрэн компанийн нийлүүлсэн тохируулах апп-г өдөөх боломж олгоно. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Сүлжээний байдлын талаар ажиглалтуудыг хүлээн авах"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Аппликешнд сүлжээний байдлын талаар ажиглалтуудыг хүлээн авахыг зөвшөөрнө. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"оролтын төхөөрөмжийн калибрешныг өөрчлөх"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Мэдрэгчтэй дэлгэцний калибрешн параметрийг өөрчлөхийг апп-д зөвшөөрнө. Энгийн апп-д шаардлагагүй."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"хандалтын DRM сертификат"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Аппликешнд DRM сертификатыг ашиглах болон нийлүүлэхийг зөвшөөрнө. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Нууц үгний дүрмийг тохируулах"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Дэлгэц түгжих нууц үгэнд зөвшөөрөгдсөн тэмдэгт болон уртыг удирдах"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Дэлгэц тайлах оролдлогыг хянах"</string>
@@ -998,7 +963,7 @@
<string name="permlab_setAlarm" msgid="1379294556362091814">"сэрүүлэг тохируулах"</string>
<string name="permdesc_setAlarm" msgid="316392039157473848">"Апп нь суулгагдсан сэрүүлэгний апп дээр сэрүүлэг тохируулах боломжтой. Зарим сэрүүлэгний апп нь энэ функцийг дэмжихгүй байж болзошгүй."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"дуут шуудан нэмэх"</string>
- <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Таны дуут шуудангийн ирсэн мэйлд зурвас нэмэхийг апп-д зөвшөөрөх."</string>
+ <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Апп нь таны дуут шуудангийн ирсэн мэйлд мессеж нэмэх боломжтой."</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Хөтчийн геобайршлын зөвшөөрлийг өөрчлөх"</string>
<string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Апп нь Хөтчийн гео байршлын зөвшөөрлийг өөрчлөх боломжтой. Хортой апп нь энийг ашиглан дурын веб хуудасруу байршлын мэдээллийг илгээх боломжтой."</string>
<string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"багцийг тулгах"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Аппликешн нь хамгаалалттай аюулгүй санд хандах боломжтой."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Түлхүүр хамгаалалтын харуулах болон далдлахыг удирдах"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Аппликешн нь түлхүүр хамгаалагчыг удирдах боломжтой."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Итгэмжлэлд орж буй өөрчлөлтийг мэдэх."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Итгэмжлэлд орж буй өөрчлөлтийг мэдэх боломжийг аппликешнд олгоно."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Итгэмжлэгдсэн төлөөлөгчийн үйлчилгээтэй холбогдох"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Аппликешнд итгэмжлэгдсэн төлөөлөгчтэй холбогдох боломж олгоно."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Шинэчлэлт болон сэргээх системтэй харилцах"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Аппликешнд сэргээх систем болон системийн шинэчлэлтэй харилцах боломж олгоно."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Өсгөх контрол дээр хоёр удаа товшино уу"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Ханын зураг"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ханын зураг солих"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Мэдэгдэл сонсогч"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Нөхцөл нийлүүлэгч"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN идэвхтэй болов"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN-г <xliff:g id="APP">%s</xliff:g> идэвхтэй болгов"</string>
<string name="vpn_text" msgid="3011306607126450322">"Сүлжээг удирдах бол хүрнэ үү."</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 751327b..6ebdfe1 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> hari"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> hari <xliff:g id="HOURS">%2$d</xliff:g> jam"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> hari <xliff:g id="HOURS">%2$d</xliff:g> jam"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> jam"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> jam <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> jam <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> minit"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> saat"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> saat"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> saat"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> saat"</string>
<string name="untitled" msgid="4638956954852782576">"<Tidak bertajuk>"</string>
<string name="ellipsis" msgid="7899829516048813237">"..."</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Penyegerakan"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Terlalu banyak pemadaman <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Storan tablet penuh. Padamkan beberapa fail untuk mengosongkan ruang."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Storan tontonan penuh. Padamkan beberapa fail untuk mengosongkan ruang."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Storan telefon penuh. Padamkan beberapa fail untuk mengosongkan ruang."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Rangkaian mungkin dipantau"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Oleh pihak ketiga yang tidak diketahui"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Pendering dihidupkan"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Mematikan..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablet anda akan dimatikan."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Tontonan anda akan dimatikan."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefon anda akan dimatikan."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Adakah anda mahu menutup?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"But semula ke mod selamat"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mod pesawat"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mod Pesawat DIHIDUPKAN"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mod Pesawat DIMATIKAN"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Tetapan"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Perkhidmatan yang anda perlu bayar"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Melakukan perkara yang boleh mengenakan bayaran kepada anda."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Mesej anda"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"nyahpasang pintasan"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Membenarkan aplikasi mengalih keluar pintasan Skrin Laman Utama tanpa campur tangan pengguna."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"tukar laluan panggilan keluar"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Membenarkan apl melihat nombor yang didail semasa panggilan keluar dengan pilihan untuk mengubah hala panggilan ke nombor lain atau membatalkan terus panggilan."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Membenarkan apl memproses panggilan keluar dan menukar nombor yang perlu didail. Kebenaran ini membolehkan apl memantau, mengalih atau menghalang panggilan keluar."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"terima mesej teks (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Membenarkan apl menerima dan memproses mesej SMS. Ini bermakna apl boleh memantau atau memadam mesej yang dihantar ke peranti anda tanpa menunjukkannya kepada anda."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"terima mesej teks (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Membenarkan apl untuk mendapatkan kandungan tetingkap aktif. Apl hasad boleh mengambil keseluruhan kandungan tetingkap dan memeriksa semua teks kecuali kata laluan."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"dayakan kebolehcapaian untuk sementara"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Membenarkan aplikasi untuk mendayakan kebolehcapaian untuk sementara pada peranti. Apl hasad mungkin mendayakan kebolehcapaian tanpa izin pengguna."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"dapatkan kembali token tetingkap"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Membenarkan apl mendapatkan kembali token tetingkap. Apl hasad mungkin meniru sistem dan menjalankan interaksi yang tidak dibenarkan dengan tetingkap aplikasi."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"dapatkan kembali statistik bingkai"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Membenarkan aplikasi mengumpul statistik bingkai. Apl hasad mungkin memerhatikan statistik bingkai tetingkap dari apl lain."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"dapatkan maklumat tetingkap"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Membolehkan aplikasi mendapatkan maklumat tentang tetingkap dari pengurus tetingkap. Apl hasad boleh mendapatkan maklumat yang bertujuan untuk penggunaan sistem dalaman."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"tapis acara"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Membenarkan aplikasi mendaftarkan penapis input yang menapis strim semua acara pengguna sebelum dihantar. Apl hasad mungkin mengawal UI sistem tanpa campur tangan pengguna."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"besarkan paparan"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Membenarkan aplikasi membesarkan kandungan paparan. Apl hasad mungkin mengubah kandungan paparan yang akan membuatkan peranti tidak boleh digunakan."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"penutupan separa"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Meletakkan pengurus aktiviti dalam keadaan tutup. Tidak melaksanakan penutupan lengkap."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"halang pertukaran apl"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Membenarkan apl untuk menyiarkan pemberitahuan bahawa mesej SMS telah diterima. Apl hasad boleh menggunakannya untuk memalsukan mesej SMS masuk."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"hantar siaran WAP-TOLAK-diterima"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Membenarkan apl untuk menyiarkan pemberitahuan bahawa mesej WAP PUSH telah diterima. Apl hasad boleh menggunakannya untuk memalsukan penerimaan mesej MMS atau secara diam-diam menggantikan kandungan mana-mana laman web dengan varian hasad."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"hantar siaran markah rangkaian"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Membenarkan apl menyiarkan pemberitahuan bahawa rangkaian perlu diberi markah. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"hadkan bilangan proses yang dijalankan"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Membenarkan apl untuk mengawal bilangan maksimum proses yang akan berlangsung. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"memaksa apl latar belakang untuk menutup"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan Vpn. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"terikat pada kertas dinding"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi kertas dinding. Tidak sekali-kali diperlukan untuk apl biasa."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"terikat kepada interaksi suara"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan interaksi suara. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"terikat kepada paparan jauh"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi paparan jauh. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"terikat kepada perkhidmatan widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan widget. Tidak sekali-kali diperlukan untuk apl biasa."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"terikat kepada perkhidmatan pembekal laluan"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Membenarkan pemegang untuk terikat kepada mana-mana pembekal laluan yang berdaftar. Tidak sekali-kali diperlukan untuk apl normal."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan pentadbir peranti"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Membenarkan pemegang menghantar tujuan kepada pentadbir peranti. Tidak sekali-kali diperlukan untuk apl biasa."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"ikat kepada input TV"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi input TV. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"tambah atau alih keluar pentadbir peranti"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Membenarkan pemegang menambah atau mengalih keluar pentadbir peranti aktif. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"tukar orientasi skrin"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Membenarkan apl untuk menggunakan sebarang penyahkod media yang dipasangkan untuk menyahkod main semula."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"urus bukti kelayakan yang dipercayai"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Membenarkan apl memasang dan menyahpasang sijil CA sebagai bukti kelayakan yang dipercayai."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"jalankan aplikasi pada masa melahu"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Kebenaran ini membolehkan sistem Android menjalankan aplikasi di latar belakang semasa peranti tidak digunakan."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"diikat ke perkhidmatan melahu"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Kebenaran ini membolehkan sistem Android mengikat kepada perkhidmatan melahu aplikasi."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"baca/tulis ke sumber yang dimiliki oleh diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Membenarkan apl membaca dan menulis ke sebarang sumber yang dimiliki oleh kumpulan diag; contohnya, fail dalam /dev. Hal ini berpotensi menjejaskan kestabilan dan keselamatan sistem. Perkara ini seharusnya HANYA digunakan untuk diagnosis khusus perkakasan oleh pengilang atau pengendali."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"dayakan atau lumpuhkan komponen apl"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Membenarkan apl membaca maklumat profil peribadi yang disimpan dalam peranti anda, seperti nama dan maklumat kenalan anda. Ini bermakna apl lain boleh mengenal pasti anda dan menghantar maklumat profil anda kepada orang lain."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"ubah suai kad kenalan sendiri"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Membenarkan apl menukar atau menambah maklumat profil peribadi yang disimpan pada peranti anda, seperti nama dan maklumat kenalan anda. Ini bermakna apl boleh mengenal pasti anda dan menghantar maklumat profil anda kepada orang lain."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"penderia (spt. denyut jantung)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Membenarkan apl mengakses data dari penderia yang anda gunakan untuk mengukur perkara yang berlaku dalam tubuh anda, seperti kadar denyutan jantung."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"baca aliran sosial anda"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Membenarkan apl mengakses dan menyegerakkan kemas kini sosial daripada anda dan rakan anda. Berhati-hati semasa berkongsi maklumat - ini membenarkan apl untuk membaca komunikasi di antara anda dan rakan anda pada rangkaian sosial tanpa mengira kerahsiaan. Nota: kebenaran ini tidak boleh dikuatkuasakan pada semua rangkaian sosial."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"tulis ke aliran sosial anda"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Membenarkan apl untuk mengawal ciri-ciri telefon peranti. Apl dengan kebenaran ini boleh menukar rangkaian, menghidupkan dan mematikan radio telefon dan sebagainya tanpa memberitahu anda."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"baca status dan identiti telefon"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Membenarkan apl mengakses ciri telefon pada peranti. Kebenaran ini membolehkan apl menentukan nombor telefon dan ID peranti, sama ada panggilan aktif dan nombor jauh yang dihubungkan dengan panggilan."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"baca keadaan telefon yang tepat"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Membenarkan apl mengakses keadaan telefon yang tepat. Kebenaran ini membolehkan apl menentukan status panggilan sebenar, sama ada panggilan aktif atau di latar belakang, kegagalan panggilan, status sambungan data yang tepat dan kegagalan sambungan data."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"menghalang tablet daripada tidur"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"halang telefon daripada tidur"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Membenarkan apl menghalang tablet daripada tidur."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Tukar keadaan WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Membenarkan apl untuk menyambungkan tablet ke dan menyahsambungkan tablet dari rangkaian WiMaX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Membenarkan apl untuk menyambungkan telefon ke dan menyahsambung telefon dari rangkaian WiMaX."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"beri markah kepada rangkaian"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Membenarkan apl menilai rangkaian dan mempengaruhi rangkaian yang harus dipilih oleh tablet."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Membenarkan apl menilai rangkaian dan mempengaruhi rangkaian yang harus dipilih oleh telefon."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"berpasangan dengan peranti Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Membenarkan apl melihat konfigurasi Bluetooth pada tablet dan untuk membuat serta menerima sambungan dengan peranti yang dipasangkan."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Membenarkan apl melihat konfigurasi Bluetooth pada telefon dan membuat serta menerima sambungan dengan peranti yang dipasangkan."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Membenarkan apl untuk mendapatkan semula, memeriksa dan memadam bersih pemberitahuan, termasuk yang disiarkan oleh apl lain."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ikat kepada perkhidmatan pendengar pemberitahuan"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan pendengar pemberitahuan. Tidak sekali-kali diperlukan untuk apl biasa."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"terikat kepada perkhidmatan pembekal keadaan"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan pembekal keadaan. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"gunakan apl konfigurasi yang disediakan oleh pembawa"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Membenarkan pemegang menggunakan apl konfigurasi yang diberikan oleh pembawa. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"dengar pemerhatian mengenai keadaan rangkaian"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Membenarkan aplikasi mendengar pemerhatian tentang keadaan rangkaian. Tidak sekali-kali diperlukan untuk apl biasa."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"tukar penentukuran peranti input"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Membenarkan apl mengubah suai parameter penentukuran skrin sentuh. Ini tidak sekali-kali diperlukan untuk apl biasa."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"akses sijil DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Membenarkan aplikasi memperuntuk dan menggunakan sijil DRM. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Tetapkan peraturan kata laluan"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan buka kunci skrin."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Memantau percubaan buka kunci skrin"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Membenarkan aplikasi mengakses storan selamat pengawal kekunci."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Kawal paparkan dan sembunyikan pengawal kekunci"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Membenarkan aplikasi untuk mengawal pengawal kekunci."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Dengar perubahan keadaan amanah."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Membenarkan aplikasi mendengar perubahan dalam keadaan amanah."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Mengikat kepada perkhidmatan ejen amanah"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Membenarkan aplikasi terikat kepada perkhidmatan ejen amanah."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Berinteraksi dengan kemas kini dan sistem pemulihan"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Membenarkan aplikasi berinteraksi dengan sistem pemulihan dan kemas kini sistem."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Sentuh dua kali untuk mendapatkan kawalan zum"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Kertas dinding"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Tukar kertas dinding"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Pendengar pemberitahuan"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Pembekal keadaan"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN diaktifkan"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Sentuh untuk mengurus rangkaian."</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 16c5352..26b27fb 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> dager"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> dag <xliff:g id="HOURS">%2$d</xliff:g> t"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> dag <xliff:g id="HOURS">%2$d</xliff:g> t"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> t"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> t <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> t <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> sek"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> sek"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sek"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sek"</string>
<string name="untitled" msgid="4638956954852782576">"<Uten navn>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkronisering"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"For mange slettinger av <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Nettbrettlageret er fullt. Slett noen filer for å frigjøre lagringsplass."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Klokkens lagringsplass er full. Slett filer for å frigjøre plass."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefonlageret er fullt. Slett noen filer for å frigjøre lagringsplass."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Nettverket blir muligens overvåket"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Av en ukjent tredjepart"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Ringelyd på"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Avslutter…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Nettbrettet slås av."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Klokken slås av."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefonen kommer til å slås av."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Vil du slå av?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Start på nytt i sikker modus"</string>
@@ -177,19 +164,16 @@
<string name="global_action_power_off" msgid="4471879440839879722">"Slå av"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Feilrapport"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Utfør feilrapport"</string>
- <string name="bugreport_message" msgid="398447048750350456">"Informasjon om tilstanden til enheten din samles inn og sendes som en e-post. Det tar litt tid fra du starter feilrapporten til e-posten er klar, så vær tålmodig."</string>
+ <string name="bugreport_message" msgid="398447048750350456">"Informasjon om den nåværende tilstanden til enheten din samles inn og sendes som en e-post. Det tar litt tid fra du starter feilrapporten til e-posten er klar, så vær tålmodig."</string>
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Stillemodus"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Lyden er av"</string>
<string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Lyden er på"</string>
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flymodus"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flymodus er på"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flymodus er av"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Innstillinger"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Betaltjenester"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Gjøre ting som kan koste deg penger."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Meldinger"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"avinstallere snarveier"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Lar appen fjerne snarveier på startsiden uten å involvere brukeren."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"omdirigere utgående anrop"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Lar appen se nummeret det ringes til under en utgående samtale, med mulighet for å omdirigere anropet til et annet nummer eller avbryte samtalen fullstendig."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Lar appen behandle utgående anrop og endre nummeret som skal ringes opp. Denne tillatelsen lar appen overvåke, viderekoble eller hindre utgående anrop."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"motta tekstmeldinger (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Lar appen motta og behandle tekstmeldinger. Dette betyr at appen kan overvåke eller slette meldinger som er sendt til enheten din uten at du har sett dem."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"motta tekstmeldinger (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Lar appen hente ut innholdet i det aktive vinduet. Ondsinnede apper kan hente ut hele vindusinnholdet og undersøke all teksten, med unntak av passord."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"aktivere tilgjengelighet midlertidig"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Lar en app midlertidig aktivere tilgjengelighet på enheten. Skadelige apper kan aktivere tilgjengelighet uten bekreftelse fra brukeren."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"hente vindustoken"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Gir appen tillatelse til å hente vindustokenet. Skadelige apper kan sette igang uautorisert samhandling med appvinduet ved å imitere systemet."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"hente bildestatistikk"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Gir appen tillatelse til å samle inn bildestatistikk. Skadelige apper kan observere bildestatistikken til vinduer i andre apper."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"hente vindusinformasjon"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Lar appen hente informasjon om vinduene fra vindusbehandleren. Skadelige apper kan hente informasjon som ikke er ment for intern systembruk."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtrere hendelser"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Lar appen registrere et inndatafilter som filtrerer strømmen for alle brukerhendelser før de sendes ut. Skadelige apper kan kontrollere brukergrensesnittet for systemet uten at brukeren gjør noe."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"forstørre visningen"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Lar apper forstørre innholdet på en skjerm. Skadelige apper kan endre skjerminnhold på en måte som gjør at enheten blir ubrukelig."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"delvis avslutning"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Lar appen sette aktivitetshåndtereren i avslutningstilstand. Slår ikke systemet helt av."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"forhindre bytte mellom apper"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Lar appen kringkaste et varsel om at en SMS-melding er mottatt. Ondsinnede apper kan bruke dette til å forfalske innkommende SMS-meldinger."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"kringkaste melding om mottatt WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Lar appen kringkaste et varsel om at en WAP-PUSH-melding er mottatt. Ondsinnede apper kan bruke dette til å forfalske MMS-meldingskvitteringer, eller ubemerket erstatte innholdet av alle slags nettsider med ondsinnede varianter."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"sende kringkasting om nettverksvurdering"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Gir appen tillatelse til å kringkaste et varsel om at nettverk må vurderes. Denne tillatelsen bør aldri være nødvendig for vanlige apper."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"begrense antallet kjørende prosesser"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Lar appen kontrollere det maksimale antallet prosesser som kjører. Aldri nødvendig for vanlige apper."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"tvinge bakgrunnsapper til å lukkes"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Lar innehaveren binde seg til det øverste nivået av grensesnittet for en VPN-tjeneste. Skal aldri være nødvendig for vanlige apper."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"binde til bakgrunnsbilde"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lar innehaveren binde det øverste nivået av grensesnittet til en bakgrunn. Skal aldri være nødvendig for vanlige apper."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"binde seg til en tjeneste for talehandlinger"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Gir innehaveren tillatelse til å binde til toppnivået av brukergrensesnittet for en tjeneste for talehandlinger. Dette skal ikke være nødvendig for vanlige apper."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"binde til ekstern skjerm"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lar innehaveren binde seg til det øverste grensesnittnivået for ekstern skjerm. Skal aldri være nødvendig for vanlige apper."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"binde til modultjenste"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lar innehaveren binde seg til det øverste nivået av grensesnittet for en modultjeneste. Skal aldri være nødvendig for vanlige apper."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"binde seg til en ruteleverandørtjeneste"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Innehaveren av tillatelsen kan binde seg til ruteleverandører. Dette er ikke nødvendig for vanlige apper."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunisere med enhetsadministrator"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Lar innehaveren sende hensikter til en enhetsadministrator. Skal aldri være nødvendig for normale apper."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"binde appen til en TV-inngang"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Lar innehaveren binde appen til det øverste grensesnittnivået for en TV-inngang. Dette skal aldri være nødvendig for vanlige apper."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"legge til eller fjerne en enhetsadministrator"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Tillater innehaveren å legge til eller fjerne aktive enhetsadministratorer. Dette skal aldri være nødvendig for vanlige apper."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"snu skjermen"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Lar appen bruke en hvilken som helst installert mediedekoder for å dekode for avspilling."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrer pålitelig legitimasjon"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lar appen installere og avinstallere CA-sertifikater som pålitelig legitimasjon."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"kjør appen når den ikke er i bruk"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Denne tillatelsen gjør at Android-systemet kan kjøre appen i bakgrunnen mens enheten ikke er i bruk."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"knytt til inaktive tjenester"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Denne tillatelsen gjør at Android-systemet kan binde seg til appers inaktive tjenester."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lese/skrive ressurser eid av diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Lar appen lese og skrive til alle ressurser som eies av gruppen «diag», som for eksempel filer i /dev. Dette kan potensielt påvirke systemets sikkerhet og stabilitet. Dette bør BARE brukes av produsenten eller operatøren til maskinvarespesifikk diagnostikk."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivere eller deaktivere appkomponenter"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Lar appen lese personlig profilinformasjon som er lagret på enheten, som for eksempel navn og kontaktinformasjon. Dette betyr at appen kan identifisere deg og sende profilinformasjonen din til andre."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"endre ditt eget kontaktkort"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Lar appen endre eller legge til personlig profilinformasjon som er lagret på enheten din, som for eksempel navn og kontaktinformasjon. Dette betyr at appen kan identifisere deg og sende profilinformasjonen din til andre."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"kroppssensorer (som pulsmålere)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Gir appen tillatelse til å bruke data fra sensorer du bruker til å måle det som skjer i kroppen din, som f.eks. pulsen."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"lese din sosiale strøm"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Lar appen lese og synkronisere sosiale oppdateringer fra deg selv og vennene dine. Vær forsiktig når du deler informasjon - med denne tillatelsen kan appen lese kommunikasjon mellom deg og vennene dine på sosiale nettverk, uavhengig av konfidensialitet. Vær oppmerksom på at denne tillatelsen kanskje ikke gjelder for alle sosiale nettverk."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"skrive i din sosiale strøm"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Lar appen kontrollere telefonfunksjonene til enheten. En app som har denne tillatelsen kan bytte nettverk, slå telefonens radio på og av og lignende, uten å varsle deg i det hele tatt."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lese telefonstatus og -identitet"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Lar appen bruke enhetens telefonfunksjoner. Med denne tillatelsen kan appen finne telefonnummer og enhets-ID-er, registrere om en samtale pågår, og se det eksterne nummeret det opprettes en forbindelse med via oppringing."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"lese nøyaktige telefontilstander"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Gir appen tilgang til nøyaktige telefontilstander. Denne tillatelsen gjør at appen kan fastslå den faktiske anropstatusen, om et anrop er aktivt eller i bakgrunnen, anropsfeil, nøyaktig status for datatilkobling og datatilkoblingsfeil."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"hindre nettbrettet fra å gå over til sovemodus"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"forhindre telefonen fra å sove"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Lar appen hindre nettbrettet fra å gå over i sovemodus."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Endre WiMAX-status"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Lar appen koble nettbrettet til og fra WiMAX-nettverk."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Lar appen koble telefonen til og fra WiMAX-nettverk."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"vurdere nettverk"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Gir appen tillatelse til å rangere nettverk, og påvirke hvilket nettverk nettbrettet skal foretrekke."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Gir appen tillatelse til å rangere nettverk, og påvirke hvilket nettverk telefonen skal foretrekke."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"koble til Bluetooth-enheter"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Lar appen se Bluetooth-konfigurasjonen på nettbrettet, samt opprette og godta tilkoblinger med sammenkoblede enheter."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Lar appen se Bluetooth-konfigurasjonen på telefonen, samt opprette og godta tilkoblinger med sammenkoblede enheter."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Lar appen hente, gjennomgå og fjerne varsler, inkludert de som sendes fra andre apper."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"binding til en varsellyttertjeneste"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lar innehaveren binde seg til det øverste grensesnittnivået for en varsellyttertjeneste. Skal aldri være nødvendig for vanlige apper."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"binde seg til en leverandørtjeneste for betingelser"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Gir innehaveren tillatelse til å binde til toppnivået av brukergrensesnittet for en leverandørtjeneste for betingelser. Dette skal ikke være nødvendig for vanlige apper."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"starte konfigurasjonsappen som ble levert av operatøren"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Gir innehaveren tillatelse til å kalle opp den konfigurasjonsappen som ble levert av operatøren. Dette skal ikke være nødvendig for vanlige apper."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"lytte etter observasjoner om nettverksforhold"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Gir appen tillatelse til å lytte etter observasjoner om nettverksforhold. Dette skal ikke være nødvendig for vanlige apper."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"endre kalibreringen av inndataenheter"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Lar appen endre kalibrasjonsparametrene for berøringsskjermen. Denne tillatelsen bør aldri være nødvendig for vanlige apper."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"tilgang til DRM-sertifikater"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Tillater at en app klargjøre og bruke DRM-sertifikater. Denne tillatelsen bør aldri være nødvendig for vanlige apper."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Angi passordregler"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller tillatt lengde og tillatte tegn i passord for opplåsing av skjerm."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Overvåk forsøk på opplåsing av skjerm"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Lar en app bruke sikker lagring via keyguard."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Kontrollér om tastelåsen er skjult eller vist"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Tillater at en app kontrollerer tastelåsen."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Oppdag endringer i tillitsstatusen."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Gir appen tillatelse til å oppdage endringer i tillitsstatusen."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Tilknytt en tillitsagent-tjeneste."</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Gir appen tillatelse til å knyttes til en tillitsagent-tjeneste."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Samhandling med oppdateringer og gjenopprettingssystem"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Tillater en app å samhandle med gjenopprettingsssystemet og systemoppdateringer."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Trykk to ganger for zoomkontroll"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Bakgrunnsbilde"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Velg bakgrunnsbilde"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Varsellytteren"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Betingelsesleverandør"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN er aktivert"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN er aktivert av <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Trykk for å administrere nettverket."</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index c19adf2..b8a7122 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> dagen"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> dag <xliff:g id="HOURS">%2$d</xliff:g> uur"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> dag <xliff:g id="HOURS">%2$d</xliff:g> uur"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> uur"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> uur <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> uur <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> minuten"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> sec"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> sec"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> seconden"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> seconde"</string>
<string name="untitled" msgid="4638956954852782576">"<Zonder titel>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchroniseren"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Te veel verwijderen voor <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tabletgeheugen is vol. Verwijder enkele bestanden om ruimte vrij te maken."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Horlogegeheugen is vol. Verwijder enkele bestanden om ruimte vrij te maken."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefoongeheugen is vol. Verwijder enkele bestanden om ruimte vrij te maken."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netwerk kan worden gecontroleerd"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Door een onbekende derde partij"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Belsoftware aan"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Uitschakelen..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Uw tablet wordt uitgeschakeld."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Uw horloge wordt uitgeschakeld."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Uw telefoon wordt uitgeschakeld."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Wilt u afsluiten?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Opnieuw opstarten in veilige modus"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Vliegmodus"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegmodus is AAN"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegmodus is UIT"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Instellingen"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Services waarvoor u moet betalen"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Activiteiten uitvoeren waarvoor kosten in rekening kunnen worden gebracht."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Uw berichten"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"snelkoppelingen verwijderen"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"De app toestaan snelkoppelingen van het startscherm te verwijderen zonder tussenkomst van de gebruiker."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"uitgaande oproepen doorschakelen"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"De app toestaan het nummer te bekijken dat wordt gekozen voor een uitgaande oproep, met de mogelijkheid de oproep om te leiden naar een ander nummer of de oproep helemaal af te breken."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Hiermee kan de app uitgaande oproepen verwerken en het nummer wijzigen dat wordt gebeld. De app kan uitgaande oproepen bijhouden, omleiden of blokkeren."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"tekstberichten (SMS) ontvangen"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Hiermee kan de app sms-berichten ontvangen en verwerken. Dit betekent dat de app berichten die naar uw apparaat zijn verzonden, kan bijhouden of verwijderen zonder deze aan u weer te geven."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"tekstberichten (MMS) ontvangen"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Hiermee kan de app de inhoud van het actieve venster ophalen. Schadelijke apps kunnen de volledige inhoud van het venster ophalen en alle tekst bekijken, behalve wachtwoorden."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"toegankelijkheid tijdelijk inschakelen"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Een app toestaan toegankelijkheid tijdelijk in te schakelen op het apparaat. Schadelijke apps kunnen toegankelijkheid inschakelen zonder toestemming van de gebruiker."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"venstertoken ophalen"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Hiermee kan een app de venstertoken ophalen. Schadelijke apps kunnen niet-geautoriseerde interactie met het appvenster uitvoeren en het systeem nabootsen."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"framestatistieken ophalen"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Hiermee kan een app framestatistieken verzamelen. Schadelijke apps kunnen de framestatistieken voor vensters van andere apps bekijken."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"venstergegevens ophalen"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Toestaan dat een app gegevens over vensters kan ophalen uit vensterbeheer. Schadelijke apps kunnen gegevens ophalen die zijn bedoeld voor interne systeemfunctionaliteit."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"evenementen filteren"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Toestaan dat een app een invoerfilter registreert waarmee de streams van alle gebruikersgebeurtenissen worden gefilterd voordat deze worden verzonden. Schadelijke apps kunnen de gebruikersinterface van het systeem beheren zonder tussenkomst van de gebruiker."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"display vergroten"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Een app toestaan de inhoud van een display te vergroten. Schadelijke apps kunnen de display-inhoud transformeren op een manier waardoor het apparaat onbruikbaar wordt."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"gedeeltelijke uitschakeling"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Hiermee wordt activiteitenbeheer uitgeschakeld. Er wordt geen volledige uitschakeling uitgevoerd."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"schakelen tussen apps voorkomen"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Hiermee kan de app een melding verzenden dat een sms\'je is ontvangen. Schadelijke apps kunnen dit gebruiken om inkomende sms\'jes te vervalsen."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"melding over ontvangen WAP-PUSH-bericht verzenden"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Hiermee kan de app een melding verzenden dat een WAP PUSH-bericht is ontvangen. Schadelijke apps kunnen dit gebruiken om de ontvangst van MMS-berichten te vervalsen of de inhoud van een webpagina ongemerkt te vervangen door schadelijke varianten."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"melding verzenden dat netwerken een score moeten krijgen"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Hiermee kan de app een melding uitzenden dat netwerken een score moeten krijgen. Nooit vereist voor normale apps."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"aantal actieve processen beperken"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Hiermee kan de app het maximale aantal processen beheren dat kan worden uitgevoerd. Nooit nodig voor normale apps."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"achtergrondapps gedwongen stoppen"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Staat de houder toe verbinding te maken met de hoofdinterface van een VPN-service. Nooit vereist voor normale apps."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"verbinden met een achtergrond"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Hiermee wordt de houder toegestaan zich te verbinden met de hoofdinterface van een achtergrond. Nooit vereist voor normale apps."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"binden aan een service voor spraakinteractie"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Hiermee kan de houder binden aan de hoofdinterface van een service voor spraakinteractie. Nooit vereist voor normale apps."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"verbinding maken met een extern display"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een extern display. Nooit vereist voor normale apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"verbinden met een widgetservice"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een widgetservice. Nooit vereist voor normale apps."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"binden aan de service van een routeprovider"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Hiermee kan de houder binden aan geregistreerde routeproviders. Nooit gebruikt voor normale apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactie met apparaatbeheer"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Hiermee kan de houder intenties verzenden naar een apparaatbeheerder. Nooit vereist voor normale apps."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"binden aan een tv-ingang"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Hiermee wordt de houder toegestaan te binden aan de hoofdinterface van een tv-ingang. Nooit vereist voor normale apps."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"een apparaatbeheerder toevoegen of verwijderen"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Hiermee kan de rechtenhouder actieve apparaatbeheerders toevoegen of verwijderen. Nooit vereist voor normale apps."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"schermstand wijzigen"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Hiermee kan de app alle geïnstalleerde mediadecoders gebruiken om te decoderen voor het afspelen."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"vertrouwde inloggegevens beheren"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Hiermee kan de app CA-certificaten installeren en verwijderen als vertrouwde inloggegevens."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"app uitvoeren tijdens inactiviteit"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Met dit recht kan het Android-systeem de app op de achtergrond uitvoeren terwijl het apparaat niet wordt gebruikt."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"koppelen aan inactieve services"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Met deze toestemming kan het Android-systeem koppelen aan de inactieve services van een app."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lezen/schrijven naar bronnen van diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Hiermee kan de app lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of provider."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"componenten van apps in- of uitschakelen"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Hiermee kan de app persoonlijke profielgegevens lezen die op uw apparaat zijn opgeslagen, zoals uw naam en contactgegevens. Dit betekent dat de app u kan identificeren en uw profielgegevens naar anderen kan verzenden."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"uw eigen contactkaart aanpassen"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Hiermee kan de app persoonlijke profielgegevens wijzigen of toevoegen die op uw apparaat zijn opgeslagen, zoals uw naam en contactgegevens. Dit betekent dat de app u kan identificeren en uw profielgegevens naar anderen kan verzenden."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"lichaamssensoren (zoals hartslagmeters)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Toestaan dat de app toegang krijgt tot gegevens van sensoren die u gebruikt om te meten wat er gebeurt in uw lichaam, zoals de hartslag."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"uw sociale stream lezen"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Hiermee kan de app toegang krijgen tot sociale updates van u en uw vrienden en deze synchroniseren. Wees voorzichtig bij het delen van informatie: hiermee kan de app communicatie lezen tussen u en uw vrienden op sociale netwerken, ongeacht de vertrouwelijkheid. Opmerking: deze toestemming kan niet worden afgedwongen voor alle sociale netwerken."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"schrijven naar sociale streams"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Hiermee kan de app de telefoonfuncties van het apparaat beheren. Een app met deze toestemming kan schakelen tussen netwerken, kan de radio van de telefoon in- en uitschakelen en dergelijke acties uitvoeren zonder dat u hiervan op de hoogte wordt gesteld."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"telefoonstatus en -identiteit lezen"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Hiermee kan de app toegang krijgen tot de telefoonfuncties van het apparaat, Met deze toestemming kan de app het telefoonnummer en de apparaat-ID\'s bepalen, of een oproep actief is, en het andere telefoonnummer waarmee wordt gebeld."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"exacte telefoonstatus lezen"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Toestaan dat de app toegang krijgt tot de exacte telefoonstatus. Hiermee kan de app bepalen wat de echte oproepstatus is, of een oproep actief is of zich op de achtergrond bevindt, of er mislukte oproepen zijn, wat de exacte status van de gegevensverbinding is en of er mislukte gegevensverbindingen zijn."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"voorkomen dat tablet overschakelt naar slaapmodus"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"voorkomen dat telefoon overschakelt naar slaapmodus"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Hiermee kan de app voorkomen dat de tablet overschakelt naar de slaapmodus."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX-status wijzigen"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Hiermee kan de app de tablet verbinden met WiMAX-netwerken en de verbinding daarmee verbreken."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Hiermee kan de app de telefoon verbinden met WiMAX-netwerken en de verbinding daarmee verbreken."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"score toekennen aan netwerken"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Hiermee kan de app netwerken rangschikken en beïnvloeden aan welke netwerken de tablet de voorkeur moet geven."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Hiermee kan de app netwerken rangschikken en beïnvloeden aan welke netwerken de telefoon de voorkeur moet geven."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"koppelen met Bluetooth-apparaten"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Hiermee kan de app de Bluetooth-configuratie van de tablet bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Hiermee kan de app de Bluetooth-configuratie van de telefoon bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Hiermee kan de app meldingen ophalen, onderzoeken en wissen, waaronder meldingen die zijn verzonden door andere apps."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"koppelen aan een listener-service voor meldingen"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Hiermee kan de houder koppelen aan de hoofdinterface van een listener-service voor meldingen. Nooit vereist voor normale apps."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"binden aan de service van een provider van voorwaarden"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Hiermee kan de houder binden aan de hoofdinterface van de service van een provider van voorwaarden. Nooit vereist voor normale apps."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"de door de provider geleverde configuratie-app aanroepen"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Hiermee kan de houder de door de provider geleverde configuratie-app aanroepen. Nooit vereist voor normale apps."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"controleren op waarnemingen met betrekking tot netwerkomstandigheden"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Hiermee kan een app controleren op waarnemingen met betrekking tot netwerkomstandigheden. Nooit vereist voor normale apps."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"kalibratie van invoerapparaat wijzigen"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Hiermee kan de app de kalibratieparameters van het aanraakscherm aanpassen. Nooit vereist voor normale apps."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"toegang tot DRM-certificaten"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Toestaan dat een app DRM-certificaten registreert en gebruikt. Nooit vereist voor normale apps."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Wachtwoordregels instellen"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"De lengte en tekens beheren die zijn toegestaan in wachtwoorden voor schermontgrendeling."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Pogingen voor schermontgrendeling bijhouden"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Hiermee krijgt een app toegang tot opslag met toetsbeveiliging."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Weergeven en verbergen van toetsbeveiliging beheren"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Staat toe dat een app de toetsbeveiliging beheert."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Controleren op wijzigingen in de trust-status."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Toestaan dat een app controleert op wijzigingen in de trust-status."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Binden aan een trust-agentservice"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Toestaan dat een app wordt gebonden aan een trust-agentservice."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interactie met update- en herstelsysteem"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Hiermee kan een app interactie hebben met het herstelsysteem en systeemupdates."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Raak twee keer aan voor zoomregeling"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Achtergrond"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Achtergrond wijzigen"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Listener voor meldingen"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provider van voorwaarden"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN is geactiveerd"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN wordt geactiveerd door <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Raak aan om het netwerk te beheren."</string>
@@ -1549,9 +1507,9 @@
<string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay <xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", beveiligd"</string>
- <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Scherm casten"</string>
+ <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Scherm sturen"</string>
<string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Verbinden met <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Scherm casten"</string>
+ <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Scherm sturen"</string>
<string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Verbonden met <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Verbinding verbreken"</string>
<string name="kg_emergency_call_label" msgid="684946192523830531">"Noodoproep"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 949fea8..8aa847f 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> dni"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> dzień <xliff:g id="HOURS">%2$d</xliff:g> godz."</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> dzień <xliff:g id="HOURS">%2$d</xliff:g> godz."</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> godz."</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> godz. <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> godz. <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
<string name="untitled" msgid="4638956954852782576">"<Bez nazwy>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,10 +135,9 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronizuj"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Zbyt wiele usuwanych <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Pamięć tabletu jest pełna. Usuń niektóre pliki, aby zwolnić miejsce."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Pamięć w zegarku jest pełna. Usuń niektóre pliki, by zwolnić miejsce."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Pamięć telefonu jest pełna. Usuń niektóre pliki, aby zwolnić miejsce."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Sieć może być monitorowana"</string>
- <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Przez nieznany podmiot zewnętrzny"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Przez nieznaną firmę zewnętrzną"</string>
<string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Przez <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opcje tabletu"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Dzwonek włączony"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Wyłączanie..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablet zostanie wyłączony."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Zegarek zostanie wyłączony."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefon zostanie wyłączony"</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Czy chcesz wyłączyć?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Uruchom w trybie awaryjnym"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Tryb samolotowy"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Tryb samolotowy jest włączony"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Tryb samolotowy jest wyłączony"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Ustawienia"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Usługi płatne"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Wykonywanie czynności, za które pobierana jest opłata."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Twoje wiadomości"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"odinstalowywanie skrótów"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Pozwala aplikacji usuwać skróty z ekranu głównego bez interwencji użytkownika."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"przekierowywanie połączeń wychodzących"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Pozwala aplikacji na sprawdzenie numeru wybieranego w trakcie połączenia wychodzącego, a także umożliwia przerwanie połączenia lub przekierowanie go pod inny numer."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Pozwala aplikacji na przetwarzanie połączeń wychodzących i zmianę wybieranego numeru. Aplikacje z tym uprawnieniem mogą monitorować, przekierowywać lub blokować połączenia wychodzące."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"odbieranie wiadomości tekstowych (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Pozwala aplikacji na odbieranie i przetwarzanie SMS-ów. To oznacza, że aplikacja będzie mogła bez Twojej wiedzy monitorować i usuwać wiadomości wysyłane do Twojego urządzenia."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"odbieranie wiadomości tekstowych (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Pozwala aplikacji na pobieranie zawartości aktywnego okna. Złośliwe aplikacje mogą pobrać całą zawartość okna i przeanalizować znajdujący się w nim tekst z wyjątkiem haseł."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"tymczasowo włącz ułatwienia dostępu"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Umożliwia aplikacji tymczasowe włączanie ułatwień dostępu na urządzeniu. Złośliwe aplikacje mogą je włączać bez zgody użytkownika."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"pobieranie tokenu okna"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Zezwala aplikacji na pobieranie tokenu okna. Złośliwe aplikacje mogą podszywać się pod system i bez autoryzacji wchodzić w interakcję z oknem aplikacji."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"pobieranie statystyk klatek"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Zezwala aplikacji na zbieranie statystyk klatek. Złośliwe aplikacje mogą śledzić statystyki klatek wyświetlanych w oknach innych aplikacji."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"pobieranie informacji o oknach"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Zezwala aplikacji na pobieranie informacji o oknach z menedżera okien. Złośliwe aplikacje mogą pobierać informacje przeznaczone do użytku wewnętrznego w systemie."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtrowanie zdarzeń"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Zezwala aplikacji na zarejestrowanie filtra wejściowego, który filtruje strumień wszystkich zdarzeń z udziałem użytkownika przed ich rozesłaniem. Złośliwe aplikacje mogą kontrolować interfejs systemu niezależnie od działań użytkownika."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"powiększanie ekranu"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Zezwala aplikacji na powiększenie zawartości ekranu. Szkodliwe aplikacje mogą przekształcić zawartość ekranu tak, by urządzenie stało się bezużyteczne."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"częściowe wyłączenie"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Przełącza menedżera aktywności w stan wyłączenia. Nie wykonuje pełnego wyłączenia."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zapobieganie przełączaniu aplikacji"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Pozwala aplikacji na wysyłanie powiadomienia, że została odebrana wiadomość SMS. Złośliwe aplikacje mogą to wykorzystać do fałszowania przychodzących wiadomości SMS."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"wysyłanie transmisji informującej o otrzymaniu wiadomości WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Pozwala aplikacji na nadanie powiadomienia o odebraniu wiadomości WAP PUSH. Złośliwe aplikacje mogą to wykorzystać do fałszowania potwierdzenia odbioru wiadomości MMS lub do niezauważalnego podmieniania zawartości dowolnej strony internetowej jej szkodliwymi wariantami."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"rozsyłanie informacji o ocenie sieci"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Pozwala aplikacji na wysłanie powiadomienia, że sieci wymagają oceny. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"ograniczanie liczby uruchomionych procesów"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Pozwala aplikacji na kontrolowanie maksymalnej liczby uruchamianych procesów. Nigdy niewykorzystywane przez normalne aplikacje."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"wymuszanie zamknięcia aplikacji w tle"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi VPN. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"powiązanie z tapetą"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu tapety. Nieprzeznaczone dla zwykłych aplikacji."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"powiąż z interaktorem głosowym"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi interakcji głosowej. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"powiązanie z wyświetlaczem zdalnym"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu wyświetlacza zdalnego. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"powiązanie z usługą widżetów"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi widżetów. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"powiązanie z usługą dostawcy tras"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Umożliwia właścicielowi powiązanie z dowolnymi zarejestrowanymi dostawcami tras. Nie powinno być nigdy potrzebne w normalnych aplikacjach."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcja z administratorem urządzenia"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Zezwala na wysyłanie intencji do administratora urządzenia. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"powiązanie z wejściem TV"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Zezwala na utworzenie powiązania z głównym interfejsem wejścia TV. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodaj lub usuń administratora urządzenia"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Umożliwia właścicielowi dodawanie i usuwanie aktywnych administratorów urządzenia. Ta opcja nie jest wykorzystywana w przypadku standardowych aplikacji."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"zmienianie orientacji ekranu"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Pozwala aplikacji na użycie dowolnego zainstalowanego dekodera multimediów do odtwarzania."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"zarządzanie zaufanymi danymi uwierzytelniającymi"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Zezwala aplikacji na instalowanie i odinstalowywanie certyfikatów CA jako zaufanych danych uwierzytelniających."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"uruchom aplikację w czasie bezczynności"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"To uprawnienie pozwala systemowi Android uruchomić aplikację w tle, gdy urządzenie nie jest używane."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"powiązanie z nieaktywnymi usługami"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"To uprawnienie umożliwia powiązanie systemu Android z nieaktywnymi usługami aplikacji."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"czytanie/zapisywanie w zasobach należących do diagnostyki"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Pozwala aplikacji na czytanie i zapisywanie wszystkich zasobów należących do grupy diagnostyki, na przykład plików w katalogu /dev. Może to potencjalnie wpłynąć na stabilność i bezpieczeństwo systemu. Powinno być wykorzystywane WYŁĄCZNIE do diagnozowania sprzętu przez producenta lub operatora."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"włączanie lub wyłączanie składników aplikacji"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Pozwala aplikacji na odczyt osobistych informacji przechowywanych w Twoim profilu na urządzeniu (np. imienia i nazwiska lub adresu). Oznacza to, że aplikacja może Cię zidentyfikować i wysłać informacje z Twojego profilu do innych osób."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"zmiana własnej karty kontaktu"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Pozwala aplikacji na zmianę lub dodanie osobistych informacji przechowywanych w Twoim profilu na urządzeniu (np. imienia i nazwiska lub adresu). Oznacza to, że aplikacja może Cię zidentyfikować i wysłać informacje z Twojego profilu do innych osób."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"czujniki ciała (np. monitorujące tętno)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Zezwala aplikacji na dostęp do danych z czujników mierzących procesy zachodzące w ciele, np. bicie serca (tętno)."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"odczyt sieci społecznościowych"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Pozwala aplikacji na odczyt i synchronizację informacji publikowanych przez Ciebie i Twoich znajomych w sieciach społecznościowych. Zachowaj ostrożność, udostępniając informacje. Aplikacja z tym uprawnieniem może odczytać całą komunikację, którą prowadzisz ze swoimi znajomymi w sieciach społecznościowych, niezależnie od jej poufności. Uwaga: to uprawnienie może nie być egzekwowane we wszystkich sieciach społecznościowych."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"zapis sieci społecznościowych"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Pozwala aplikacji na kontrolowanie funkcji telefonu w urządzeniu. Aplikacja z tymi uprawnieniami może zmieniać, włączać i wyłączać sieci bezprzewodowe itp. bez informowania użytkownika."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"odczytywanie stanu i informacji o telefonie"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Pozwala aplikacji na dostęp do funkcji telefonicznych urządzenia. Aplikacja z tym uprawnieniem może odczytać numer telefonu i identyfikator urządzenia, sprawdzić, czy połączenie jest aktywne, oraz poznać numer, z którym jest nawiązane połączenie."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"dokładne rozpoznawanie stanów telefonu"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Pozwala aplikacji dokładnie rozpoznawać stany telefonu. Aplikacja z tym uprawnieniem może określić rzeczywisty stan połączenia, ustalić, czy jest ono aktywne czy znajduje się w tle, odczytać informacje o nieudanych połączeniach, precyzyjnie określić stan połączenia transmisji danych oraz odczytać informacje o błędach transmisji danych."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zapobieganie przechodzeniu tabletu do trybu uśpienia"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zapobieganie przejściu telefonu w stan uśpienia"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Pozwala aplikacji na zapobieganie przechodzeniu tabletu do trybu uśpienia."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"zmienianie stanu WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Pozwala aplikacji na nawiązywanie i kończenie połączeń z sieciami WiMAX w tablecie."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Pozwala aplikacji na nawiązywanie i kończenie połączeń z sieciami WiMAX w telefonie."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ocenianie sieci"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Pozwala aplikacji na ocenę sieci i wybieranie sieci preferowanych przez tablet."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Pozwala aplikacji na ocenę sieci i wybieranie sieci preferowanych przez telefon."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"parowanie z urządzeniami Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Pozwala aplikacji na dostęp do konfiguracji Bluetooth na tablecie oraz na nawiązywanie i akceptowanie połączeń ze sparowanych urządzeń."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Pozwala aplikacji na dostęp do konfiguracji Bluetooth na telefonie oraz na nawiązywanie i akceptowanie połączeń ze sparowanych urządzeń."</string>
@@ -714,21 +683,15 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Umożliwia aplikacji pobieranie, sprawdzanie i usuwanie powiadomień, także tych, które pochodzą z innych aplikacji."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"utwórz połączenie z usługą odbiornika powiadomień"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi odbiornika powiadomień. Nie powinno być nigdy potrzebne dla zwykłych aplikacji."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"powiąż z usługą dostawcy warunków"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi dostawcy warunków. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"wywoływanie aplikacji konfiguracyjnej udostępnionej przez operatora"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Zezwala na wywoływanie aplikacji konfiguracyjnej udostępnionej przez operatora. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"śledź stan sieci"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Pozwala aplikacji śledzić stan sieci. Nieprzeznaczone dla zwykłych aplikacji."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"zmiana kalibracji urządzenia wejściwego"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Zezwala aplikacji na modyfikowanie parametrów kalibracji ekranu dotykowego. Nieprzeznaczone dla zwykłych aplikacji."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"dostęp do certyfikatów DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Zezwala aplikacji na dodanie i używanie certyfikatów DRM. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Określ reguły hasła"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolowanie długości haseł odblokowania ekranu i dozwolonych w nich znaków"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitoruj próby odblokowania ekranu"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Przy odblokowywaniu ekranu monitoruj, ile razy wpisano nieprawidłowe hasło i blokuj tablet lub usuń z niego wszystkie dane, jeśli nieprawidłowe hasło podano zbyt wiele razy."</string>
- <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Przy odblokowywaniu ekranu monitoruje, ile razy wpisano nieprawidłowe hasło, i blokuje telefon lub usuwa z niego wszystkie dane, jeśli nieprawidłowe hasło podano zbyt wiele razy"</string>
+ <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Przy odblokowywaniu ekranu monitoruje, ile razy wpisano nieprawidłowe hasło i blokuje telefon lub usuwa z niego wszystkie dane, jeśli nieprawidłowe hasło podano zbyt wiele razy."</string>
<string name="policylab_resetPassword" msgid="2620077191242688955">"Zmień hasło odblokowania ekranu"</string>
<string name="policydesc_resetPassword" msgid="605963962301904458">"Zmienianie hasła odblokowania ekranu"</string>
<string name="policylab_forceLock" msgid="2274085384704248431">"Zablokuj ekran"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Zezwala aplikacji na dostęp do bezpiecznego magazynu kluczy."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Kontroluj wyświetlanie i ukrywanie zabezpieczenia kluczami"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Umożliwia aplikacji kontrolowanie zabezpieczenia kluczami."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Monitoruj zmiany w stanie zaufania."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Zezwala aplikacji na monitorowanie zmian w stanie zaufania."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Powiąż z usługą agenta zaufania"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Zezwala aplikacji na powiązanie z usługą agenta zaufania."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interakcja z systemem odzyskiwania i aktualizacjami"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Zezwala aplikacji na interakcję z systemem odzyskiwania i aktualizacjami systemu."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dotknij dwukrotnie, aby sterować powiększeniem."</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Zmień tapetę"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Odbiornik powiadomień"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Dostawca warunków"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN aktywny"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Obsługa sieci VPN została włączona przez aplikację <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dotknij, aby zarządzać siecią."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index f9b9fd2..f566881 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> dias"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> dia <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> dia <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> horas"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> seg"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> seg"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> seg"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> seg"</string>
<string name="untitled" msgid="4638956954852782576">"<Sem nome>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronização"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminações de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"O armazenamento do tablet está cheio. Elimine alguns ficheiros para libertar espaço."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"O armazenamento de visualizações está cheio. Elimine alguns ficheiros para libertar espaço."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"O armazenamento do telemóvel está cheio. Elimine alguns ficheiros para libertar espaço."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"A rede pode ser monitorizada"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Por um terceiro desconhecido"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Campainha ativada"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"A encerrar..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"O seu tablet irá encerrar."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"As suas visualizações vão ser encerradas."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"O seu telefone será encerrado."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Pretende encerrar?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reiniciar no modo de segurança"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo de avião"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"O modo de voo está ativado"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"O modo de voo está desativado"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Definições"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Serviços que implicam pagamento"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Efetuar ações que implicam pagamento."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"As suas mensagens"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"desinstalar atalhos"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permite que a aplicação remova atalhos do Ecrã principal sem a intervenção do utilizador."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"redirecionar as chamadas efetuadas"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permite que a aplicação veja o número que é marcado durante uma chamada efetuada, com a opção de redirecionar a chamada para um número diferente ou terminar a chamada."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Permite que a aplicação processe chamadas efetuadas e mude o número a marcar. Esta autorização permite que a aplicação monitorize, redirecione ou impeça a realização de chamadas."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"receber mensagens de texto (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Permite que a aplicação receba e processe mensagens SMS. Isto significa que a aplicação poderá monitorizar ou eliminar mensagens enviadas para o seu dispositivo sem as apresentar."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"receber mensagens de texto (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permite que a aplicação obtenha o conteúdo da janela ativa. As aplicações maliciosas podem obter todo o conteúdo da janela e examinar todo o texto, exceto as palavras-passe."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"acessibilidade ativada temporariamente"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permite que uma aplicação ative temporariamente a acessibilidade no dispositivo. As aplicações maliciosas podem ativar a acessibilidade sem o consentimento do utilizador."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"obter token da janela"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Permite que uma aplicação obtenha o token da janela. As aplicações maliciosas podem interagir de forma não autorizada com a janela da aplicação, roubando a identidade do sistema."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"obter estatísticas de fotograma"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Permite que uma aplicação recolha estatísticas de fotograma. As aplicações maliciosas podem observar as estatísticas de fotograma de janelas de outras aplicações."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"obter informações da janela"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permite que uma aplicação obtenha informações sobre as janelas a partir do gestor de janelas. Aplicações maliciosas podem obter informações que se destinam à utilização interna do sistema."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtrar eventos"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Permite que uma aplicação registe um filtro de entrada que filtra a transmissão em fluxo contínuo para todos os eventos de utilizador antes de serem entregues. Uma aplicação maliciosa pode controlar a IU do sistema sem intervenção do utilizador."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"ampliar o visor"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Permite que uma aplicação amplie o conteúdo de um visor. As aplicações maliciosas poderão transformar o conteúdo do visor de um modo que torne o dispositivo inutilizável."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"encerramento parcial"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Coloca o gestor de actividade num estado de encerramento. Não executa um encerramento completo."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"impedir trocas de aplicações"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permite que a aplicação difunda uma notificação de que foi recebida uma mensagem SMS. As aplicações maliciosas podem utilizar este recurso para forjar mensagens SMS recebidas."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar difusão recebida através de PUSH WAP"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permite que a aplicação difunda uma notificação de que foi recebida uma mensagens PUSH WAP. As aplicações maliciosas podem utilizar isto para forjar um recibo de mensagem MMS ou substituir, de forma silenciosa, o conteúdo de qualquer página Web por variantes maliciosas."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"enviar transmissão de pontuação de redes"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permite à aplicação transmitir uma notificação de que é necessário pontuar as redes. Nunca é necessário para aplicações normais."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"número limite de processos em execução"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permite a uma aplicação controlar o número máximo de processos que será executado. Nunca é necessário para aplicações normais."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forçar as aplicações em segundo plano a fechar"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite que o titular se vincule à interface de nível superior de um serviço de VPN. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"vincular a uma imagem de fundo"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite ao titular vincular-se à interface de nível superior de uma imagem de fundo. Nunca deverá ser necessário para aplicações normais."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"vincular a um interlocutor de voz"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite que o titular vincule a interface de nível superior de um serviço de interação de voz. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"associar a um ecrã remoto"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite ao detentor associar a interface de nível superior a um ecrã remoto. Nunca deve ser necessário para aplicações normais."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincular a um serviço de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o titular vincule a interface de nível superior de um serviço de widget. Nunca deverá ser necessário para aplicações normais."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"vincular a serviço de fornecedor de trajeto"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permite ao titular vincular a quaisquer fornecedores de trajeto registado. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com um administrador do dispositivo"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite ao titular enviar intenções para um administrador do aparelho. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"vincular a uma entrada de TV"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que a aplicação utilize qualquer descodificador de multimédia instalado para descodificar a reprodução."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gerir credenciais fidedignas"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que a aplicação instale e desinstale certificados da AC (Autoridade de certificação) como credenciais fidedignas."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"executar aplicação durante o tempo de inatividade"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Esta autorização permite ao sistema Android executar a aplicação em segundo plano enquanto o dispositivo não estiver a ser utilizado."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"associar a serviços inativos"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Esta autorização permite que o sistema Android seja vinculado aos serviços inativos de uma aplicação."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"ler/escrever em recursos propriedade de diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite à aplicação ler e escrever em qualquer recurso que seja propriedade do grupo diag; por exemplo, ficheiros em /dev. Isto pode potencialmente afetar a estabilidade e a segurança do sistema e deve ser utilizado APENAS para diagnósticos específicos do hardware pelo fabricante ou pelo operador."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"ativar ou desativar componentes da aplicação"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Permite que a aplicação leia dados de perfil pessoais guardados no dispositivo, tais como o seu nome e informações de contacto. Isto significa que outras aplicações podem identificá-lo e enviar os seus dados de perfil a terceiros."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"modificar o próprio cartão de contacto"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Permite que a aplicação altere ou adicione dados de perfil pessoais guardados no dispositivo, tais como o seu nome e informações de contacto. Isto significa que outras aplicações podem identificá-lo e enviar os seus dados de perfil a terceiros."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"sensores corporais (como monitores do ritmo cardíaco)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Permite à aplicação aceder a dados de sensores que o utilizador usa para medir o que está a acontecer no seu corpo, por exemplo o ritmo cardíaco."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"ler o seu fluxo social"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Permite que a aplicação aceda e sincronize atualizações de redes sociais suas e dos seus amigos. Tenha cuidado ao partilhar informações, pois esta ação permite que a aplicação leia comunicações entre si e os seus amigos nas redes sociais, independentemente do grau de confidencialidade. Nota: esta autorização pode não ser aplicada a todas as redes sociais."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"escrever para o seu fluxo social"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite que a aplicação controle as funcionalidades de telefone do aparelho. Uma aplicação com esta permissão pode alternar entre redes, ligar/desligar o rádio do telefone e outras coisas semelhantes sem sequer o notificar."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ler o estado e a identidade do telemóvel"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que a aplicação aceda às funcionalidades de telefone do dispositivo. Esta autorização permite que a aplicação determine o número de telefone e IDs do dispositivo, se alguma chamada está ativa e qual o número remoto ligado por uma chamada."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ler os estados precisos do telemóvel"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permite que a aplicação aceda ao estados precisos do telemóvel. Esta autorização permite que a aplicação determine o estado real da chamada, se uma chamada está ativa ou em segundo plano, falhas em chamadas, o estado preciso da ligação de dados e falhas de ligação de dados."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir que o tablet entre em inactividade"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir modo de inactividade do telefone"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que a aplicação impeça o tablet de entrar no modo de suspensão."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Alterar estado do WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite que a aplicação ligue e desligue o tablet de redes WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite que a aplicação ligue e desligue o telemóvel de redes WiMAX."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"pontuar redes"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permite à aplicação classificar redes e influenciar as redes que o tablet deve preferir."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permite à aplicação classificar redes e influenciar as redes que o telemóvel deve preferir."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"sincronizar com dispositivos Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite que a aplicação visualize a configuração do Bluetooth no tablet e que estabeleça e aceite ligações com dispositivos emparelhados."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite que a aplicação visualize a configuração do Bluetooth no telemóvel e que estabeleça e aceite ligações com dispositivos emparelhados."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que a aplicação obtenha, examine e limpe notificações, incluindo as que foram publicadas por outras aplicações."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"vincular a um serviço de escuta de notificações"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite que o titular vincule a interface de nível superior de um serviço de escuta de notificações. Nunca deverá ser necessário para aplicações normais."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"vincular a um serviço de fornecedor de condição"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite que o titular vincule a interface de nível superior de um serviço de fornecedor de condição. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invocar a aplicação de configuração fornecida pela operadora"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite que o titular invoque a aplicação de configuração fornecida pela operadora. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ouvir observações sobre as condições da rede"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que uma aplicação ouça observações sobre as condições da rede. Nunca deverá ser necessário para aplicações normais."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"alterar a calibragem de entrada do dispositivo"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite à aplicação modificar os parâmetros de calibragem do ecrã tátil. Esta funcionalidade nunca deverá ser necessária para aplicações normais."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"Aceder a certificados DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permite que uma aplicação forneça e utilize certificados DRM. Nunca deverá ser necessário para aplicações normais."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras de palavra-passe"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar o comprimento e os caracteres permitidos nas palavras-passe de desbloqueio do ecrã."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizar tentativas de desbloqueio do ecrã"</string>
@@ -1140,7 +1105,7 @@
<string name="Midnight" msgid="5630806906897892201">"Meia-noite"</string>
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="6876518925844129331">"Selecionar tudo"</string>
+ <string name="selectAll" msgid="6876518925844129331">"Seleccionar tudo"</string>
<string name="cut" msgid="3092569408438626261">"Cortar"</string>
<string name="copy" msgid="2681946229533511987">"Copiar"</string>
<string name="paste" msgid="5629880836805036433">"Colar"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permite a uma aplicação aceder ao armazenamento seguro de proteção de teclado."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Controlar apresentação e ocultação de proteção de teclado"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite que uma aplicação controle a proteção de teclado."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Registar alterações no estado trust."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que uma aplicação registe alterações no trust state."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Vincular a um serviço de trust agent"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que uma aplicação fique vinculada a um serviço de trust agent."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interagir com o sistema de recuperação e de atualização"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Permite que uma aplicação interaja com o sistema de recuperação e as atualizações do sistema."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toque duas vezes para controlar o zoom"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Imagem de fundo"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Alterar imagem de fundo"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Serviço de escuta de notificações"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Fornecedor de condição"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN ativada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"A VPN foi ativada pelo <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toque para gerir a rede."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index be2ed29..2cfad8f 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> dias"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> dia <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> dia <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> horas"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
<string name="untitled" msgid="4638956954852782576">"<Sem título>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizar"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Muitas exclusões de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"O armazenamento do tablet está cheio. Exclua alguns arquivos para liberar espaço."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Armazenamento do relógio cheio. Exclua alguns arquivos para liberar espaço."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"O armazenamento do telefone está cheio. Exclua alguns arquivos para liberar espaço."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"A rede pode ser monitorada"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Por terceiros desconhecidos"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Campainha ligada"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Encerrando…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Seu tablet será desligado."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Seu relógio será desligado."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"O seu telefone será desligado."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Deseja desligar?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reiniciar no modo de segurança"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avião"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avião ATIVADO"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avião DESATIVADO"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Configurações"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Serviços que geram gastos"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Faça coisas que podem custar dinheiro."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Suas mensagens"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"desinstalar atalhos"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permite que o aplicativo remova atalhos da tela inicial sem a intervenção do usuário."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"redirecionar as chamadas efetuadas"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permite que o aplicativo veja o número discado ao realizar uma chamada, com a opção de redirecionar a chamada para outro número ou abortá-la."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Permite que o aplicativo processe as chamadas de saída e altere o número a ser discado. Esta permissão autoriza o aplicativo a monitorar, redirecionar ou evitar chamadas de saída."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"receber mensagens de texto (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Permite que o aplicativo receba e processe mensagens SMS. Isso significa que o aplicativo pode monitorar ou excluir mensagens enviadas para o dispositivo sem mostrá-las para você."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"receber mensagens de texto (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permite que o aplicativo recupere o conteúdo da janela ativa. Aplicativos maliciosos podem recuperar o conteúdo da janela inteira e examinar todo o texto, exceto as senhas."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"ativar temporariamente a acessibilidade"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permite que um aplicativo ative temporariamente a acessibilidade no dispositivo. Aplicativos maliciosos podem ativar a acessibilidade sem o consentimento do usuário."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"recuperar token da janela"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Permite que o aplicativo recupere o token da janela. Aplicativos maliciosos podem realizar interações não autorizadas com a janela do aplicativo em nome do sistema."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"recuperar estatísticas de quadros"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Permite que o aplicativo colete estatísticas de quadros. Aplicativos maliciosos podem observar as estatísticas de quadros de janelas de outros aplicativos."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"recuperar informações de janelas"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permite que o aplicativo recupere informações sobre as janelas do gerenciador de janelas. Aplicativos mal-intencionados podem recuperar informações destinadas ao uso interno do sistema."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtrar eventos"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Permite que o aplicativo registre um filtro de entrada que filtra o fluxo de todos os eventos do usuário antes que sejam enviados. Aplicativos mal-intencionados podem controlar a interface do sistema sem a intervenção do usuário."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"ampliar monitor"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Permite que o aplicativo amplie o conteúdo de um monitor. Aplicativos maliciosos podem manipular o conteúdo do monitor de modo a tornar o dispositivo inutilizável."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"desligamento parcial"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Coloca o gerenciador de atividades em um estado de desligamento. Não executa o desligamento completo."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"evitar trocas de aplicativo"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permite que o aplicativo transmita uma notificação quando uma mensagem SMS foi recebida. Aplicativos maliciosos podem usar esse recurso para forjar mensagens SMS recebidas."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar transmissão WAP-PUSH recebida"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permite que o aplicativo transmita uma notificação quando uma mensagem WAP PUSH for recebida. Aplicativos maliciosos podem usar esse recurso para forjar o recebimento de mensagens MMS ou substituir o conteúdo de qualquer página da web com variantes maliciosas."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"enviar transmissão de avaliação de redes"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permite que o aplicativo transmita uma notificação informando que as redes devem ser avaliadas. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar número de processos em execução"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permite que o aplicativo controle o máximo de processos que serão executados. Nunca é necessário para aplicativos normais."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forçar encerramento de aplicativos em segundo plano"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite que seu proprietário sujeite a interface de alto nível de um serviço de VPN. Nunca deve ser necessário para aplicativos normais."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"sujeitar-se a um plano de fundo"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite que o proprietário utilize interface de nível superior de um plano de fundo. Nunca deve ser necessário para aplicativos normais."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"associar a um interagente de voz"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite que o proprietário use a interface de nível superior de um serviço de interação de voz. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"usar uma tela remota"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite que o proprietário use a interface de nível superior de uma tela remota. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sujeitar-se a um serviço de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o proprietário utilize a interface de nível superior de um serviço de widget. Nunca deve ser necessário para aplicativos normais."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"usar um serviço provedor de rotas"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permite que o proprietário use qualquer provedor de rotas registrado. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com o administrador de um dispositivo"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite que o proprietário envie tentativas ao administrador de um aparelho. Nunca deve ser necessário para aplicativos normais."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"associar a uma entrada de TV"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Permite que o proprietário use a interface de nível superior de uma entrada de TV. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adicionar ou remover um administrador do dispositivo"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite que o proprietário adicione ou remova administradores do dispositivo ativos. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"alterar orientação da tela"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que o aplicativo use qualquer decodificador de mídia instalado para reprodução."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gerenciar credenciais confiáveis"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que o aplicativo instale e desinstale certificados CA como credenciais confiáveis."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"executar o aplicativo durante o tempo ocioso"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Permite que o sistema Android execute o aplicativo em segundo plano enquanto o dispositivo não está em uso."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"associar a serviços inativos"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Permite que o sistema Android seja associado aos serviços inativos de um aplicativo."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"ler/gravar em recursos pertencentes ao diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que um aplicativo leia e grave em qualquer recurso que pertença ao grupo de diagnósticos, por exemplo, arquivos in/dev. Isso pode afetar a estabilidade e a segurança do sistema. Esse recurso deve ser usado APENAS para diagnósticos específicos do hardware realizados pelo fabricante ou pela operadora."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"ativar ou desativar os componentes do aplicativo"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Permite que o aplicativo leia informações de perfil pessoal armazenadas no dispositivo, como seu nome e dados de contato. Isso significa que o aplicativo poderá identificá-lo e enviar suas informações de perfil para terceiros."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"mod. próprio cartão contato"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Permite que o aplicativo altere ou adicione informações pessoais de perfil armazenadas em seu dispositivo, como seu nome e informações de contato. Isso significa que o aplicativo pode identificá-lo e enviar as informações de seus perfil para terceiros."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"sensores corporais"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Permite que o aplicativo acesse dados de sensores usados para medir o que acontece em seu corpo, como seus batimentos cardíacos."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"ler suas transmissões sociais"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Permite que o aplicativo acesse e sincronize suas atualizações sociais e as de seus amigos. Tenha cuidado ao compartilhar informações: isto permite que o aplicativo leia as mensagens trocadas por você e seus amigos em redes sociais, independentemente de sua confidencialidade. Obsservaç: pode não ser aplicável a todas as redes sociais."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"escrever p/ suas transm. soc."</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite que o aplicativo controle os recursos de telefone do dispositivo. Um aplicativo com essa permissão pode alternar entre redes, ligar e desligar o rádio do telefone e assim por diante, sem nunca notificá-lo."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ler status e identidade do telefone"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que o aplicativo acesse os recursos de telefonia do dispositivo. Esta permissão autoriza o aplicativo a determinar o número de telefone e IDs de dispositivo, quando uma chamada está ativa, e o número remoto conectado a uma chamada."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ler estados precisos do telefone"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permite que o aplicativo acesse estados precisos do telefone. Permite que o aplicativo determine o status real da chamada, se uma chamada está ativa em segundo plano, falhas em chamadas, o status preciso da conexão de dados e falhas na conexão de dados."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir modo de inatividade do tablet"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir modo de inatividade do telefone"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que o aplicativo impeça o tablet de entrar no modo de inatividade."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Alterar estado do WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite que o aplicativo conecte e desconecte o tablet de redes WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite que o aplicativo conecte e desconecte o telefone de redes WiMAX."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"avaliar redes"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permite que o aplicativo classifique as redes e influencie a escolha de redes pelo tablet."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permite que o aplicativo classifique as redes e influencie a escolha de redes pelo smartphone."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"parear com dispositivos Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite que o aplicativo acesse a configuração do Bluetooth no tablet, além de fazer e aceitar conexões com dispositivos pareados."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite que o aplicativo acesse a configuração do Bluetooth no telefone, além de fazer e aceitar conexões com dispositivos pareados."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que o aplicativo recupere, examine e limpe notificações, inclusive as postadas por outros aplicativos."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"sujeitar a um serviço ouvinte de notificações"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite que o proprietário sujeite a interface de nível superior a um serviço ouvinte de notificações. Não deve ser necessário para aplicativos comuns."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"associar a um serviço provedor de condições"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite que o proprietário use a interface de nível superior de um serviço provedor de condições. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"invocar o aplicativo de configuração fornecido pela operadora"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite que o proprietário invoque o aplicativo de configuração fornecido pela operadora. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"detectar observações nas condições da rede"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que o aplicativo detecte observações nas condições da rede. Não deve ser necessário para aplicativos comuns."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"alterar calibragem do dispositivo de entrada"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite que o aplicativo modifique os parâmetros de calibragem da tela sensível ao toque. Não deve ser necessário para aplicativos normais."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"acessar certificados de DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permite que o aplicativo provisione e use certificados de DRM. Não deve ser necessário para aplicativos comuns."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras para senha"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar o tamanho e os caracteres permitidos nas senhas de desbloqueio de tela."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitorar tentativas de desbloqueio da tela"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permite que o aplicativo acesse o armazenamento seguro do bloqueio de teclado."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Controlar a exibição e ocultação do bloqueio de tela"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite que o aplicativo controle o bloqueio de teclado."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Detectar alterações no estado de confiança."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que o aplicativo detecte alterações no estado de confiança."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Associar a um serviço de agente de confiança"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que o aplicativo se associe a um serviço de agente de confiança."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interagir com o sistema de atualizações e recuperação"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Permite que um aplicativo interaja com o sistema de recuperação e as atualizações do sistema."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Toque duas vezes para controlar o zoom"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Plano de fundo"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Alterar plano de fundo"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Ouvinte de notificações"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provedor de condições"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN ativada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"A VPN está ativada por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toque para gerenciar a rede."</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 6bdaee5..407f6ed 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -28,28 +28,6 @@
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<!-- no translation found for fileSizeSuffix (9164292791500531949) -->
<skip />
- <!-- no translation found for durationDays (6652371460511178259) -->
- <skip />
- <!-- no translation found for durationDayHours (2713107458736744435) -->
- <skip />
- <!-- no translation found for durationDayHour (7293789639090958917) -->
- <skip />
- <!-- no translation found for durationHours (4266858287167358988) -->
- <skip />
- <!-- no translation found for durationHourMinutes (9029176248692041549) -->
- <skip />
- <!-- no translation found for durationHourMinute (2741677355177402539) -->
- <skip />
- <!-- no translation found for durationMinutes (3134226679883579347) -->
- <skip />
- <!-- no translation found for durationMinuteSeconds (1424656185379003751) -->
- <skip />
- <!-- no translation found for durationMinuteSecond (3989228718067466680) -->
- <skip />
- <!-- no translation found for durationSeconds (8050088505238241405) -->
- <skip />
- <!-- no translation found for durationSecond (985669622276420331) -->
- <skip />
<!-- no translation found for untitled (4638956954852782576) -->
<skip />
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
@@ -182,8 +160,6 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Memia blers cuntegns stizzads (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
<!-- no translation found for low_memory (6494019234102154896) -->
<skip />
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
<!-- no translation found for low_memory (3475999286680000541) -->
<skip />
<!-- no translation found for ssl_ca_cert_warning (5848402127455021714) -->
@@ -210,8 +186,6 @@
<string name="shutdown_progress" msgid="2281079257329981203">"Vegn serrà..."</string>
<!-- no translation found for shutdown_confirm (3385745179555731470) -->
<skip />
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
<!-- no translation found for shutdown_confirm (649792175242821353) -->
<skip />
<!-- no translation found for shutdown_confirm_question (2906544768881136183) -->
@@ -240,16 +214,10 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modus d\'aviun"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Il modus d\'aviun è activà"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Il modus d\'aviun è deactivà."</string>
- <!-- no translation found for global_action_settings (1756531602592545966) -->
- <skip />
<!-- no translation found for status_bar_notification_info_overflow (5301981741705354993) -->
<skip />
<string name="safeMode" msgid="2788228061547930246">"Modus segirà"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
- <!-- no translation found for user_owner_label (2804351898001038951) -->
- <skip />
- <!-- no translation found for managed_profile_label (6260850669674791528) -->
- <skip />
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servetschs che custan"</string>
<!-- no translation found for permgroupdesc_costMoney (3293301903409869495) -->
<skip />
@@ -395,7 +363,7 @@
<skip />
<!-- no translation found for permlab_processOutgoingCalls (3906007831192990946) -->
<skip />
- <!-- no translation found for permdesc_processOutgoingCalls (5156385005547315876) -->
+ <!-- no translation found for permdesc_processOutgoingCalls (5331318931937402040) -->
<skip />
<!-- no translation found for permlab_receiveSms (8673471768947895082) -->
<skip />
@@ -510,18 +478,18 @@
<skip />
<!-- no translation found for permdesc_temporary_enable_accessibility (8079456293182975464) -->
<skip />
- <!-- no translation found for permlab_retrieveWindowToken (7154762602367758602) -->
+ <!-- no translation found for permlab_retrieve_window_info (8532295199112519378) -->
<skip />
- <!-- no translation found for permdesc_retrieveWindowToken (668173747687795074) -->
- <skip />
- <!-- no translation found for permlab_frameStats (7056374987314361639) -->
- <skip />
- <!-- no translation found for permdesc_frameStats (4758001089491284919) -->
+ <!-- no translation found for permdesc_retrieve_window_info (4998836370424186849) -->
<skip />
<!-- no translation found for permlab_filter_events (8675535648807427389) -->
<skip />
<!-- no translation found for permdesc_filter_events (8006236315888347680) -->
<skip />
+ <!-- no translation found for permlab_magnify_display (5973626738170618775) -->
+ <skip />
+ <!-- no translation found for permdesc_magnify_display (7121235684515003792) -->
+ <skip />
<string name="permlab_shutdown" msgid="7185747824038909016">"serrar parzialmain"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Metta l\'administratur dad activitads en in stadi da pausa. El na vegn betg serrà dal tut."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"evitar il midar tranter applicaziuns"</string>
@@ -544,10 +512,6 @@
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"trametter in broadcast retschavì da WAP-PUSH"</string>
<!-- no translation found for permdesc_broadcastWapPush (4783402525039442729) -->
<skip />
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar il dumber maximal da process exequids"</string>
<!-- no translation found for permdesc_setProcessLimit (7318061314040879542) -->
<skip />
@@ -634,10 +598,6 @@
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"sa fixar vid in fund davos"</string>
<!-- no translation found for permdesc_bindWallpaper (7108428692595491668) -->
<skip />
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
<!-- no translation found for permlab_bindRemoteDisplay (1782923938029941960) -->
<skip />
<!-- no translation found for permdesc_bindRemoteDisplay (1261242718727295981) -->
@@ -646,17 +606,9 @@
<skip />
<!-- no translation found for permdesc_bindRemoteViews (4717987810137692572) -->
<skip />
- <!-- no translation found for permlab_bindRouteProvider (4869394607915096847) -->
- <skip />
- <!-- no translation found for permdesc_bindRouteProvider (4703804520859960329) -->
- <skip />
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacziun cun in administratur dad apparats"</string>
<!-- no translation found for permdesc_bindDeviceAdmin (569715419543907930) -->
<skip />
- <!-- no translation found for permlab_bindTvInput (5601264742478168987) -->
- <skip />
- <!-- no translation found for permdesc_bindTvInput (2371008331852001924) -->
- <skip />
<!-- no translation found for permlab_manageDeviceAdmins (4248828900045808722) -->
<skip />
<!-- no translation found for permdesc_manageDeviceAdmins (5025608167709942485) -->
@@ -726,9 +678,9 @@
<skip />
<!-- no translation found for permdesc_manageCaCertificates (4015644047196937014) -->
<skip />
- <!-- no translation found for permlab_bindIdleService (816311765497613780) -->
+ <!-- no translation found for permlab_bindIdleService (7521398788076342815) -->
<skip />
- <!-- no translation found for permdesc_bindIdleService (1767538493214100612) -->
+ <!-- no translation found for permdesc_bindIdleService (7747505810143356528) -->
<skip />
<string name="permlab_diagnostic" msgid="8076743953908000342">"leger/scriver en resursas che appartegnan a diagnostics"</string>
<!-- no translation found for permdesc_diagnostic (6608295692002452283) -->
@@ -800,10 +752,6 @@
<skip />
<!-- no translation found for permdesc_writeProfile (5552084294598465899) -->
<skip />
- <!-- no translation found for permlab_bodySensors (4871091374767171066) -->
- <skip />
- <!-- no translation found for permdesc_bodySensors (2998865085124153531) -->
- <skip />
<!-- no translation found for permlab_readSocialStream (1268920956152419170) -->
<skip />
<!-- no translation found for permdesc_readSocialStream (4255706027172050872) -->
@@ -987,10 +935,6 @@
<skip />
<!-- no translation found for permdesc_readPhoneState (1639212771826125528) -->
<skip />
- <!-- no translation found for permlab_readPrecisePhoneState (5476483020282007597) -->
- <skip />
- <!-- no translation found for permdesc_readPrecisePhoneState (6648009074263855418) -->
- <skip />
<!-- no translation found for permlab_wakeLock (1531731435011495015) -->
<skip />
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"evitar ch\'il telefon midia en il modus stand-by"</string>
@@ -1113,12 +1057,6 @@
<skip />
<!-- no translation found for permdesc_changeWimaxState (697025043004923798) -->
<skip />
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
<!-- no translation found for permlab_bluetooth (6127769336339276828) -->
<skip />
<!-- no translation found for permdesc_bluetooth (3480722181852438628) -->
@@ -1220,10 +1158,6 @@
<skip />
<!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
<skip />
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
<!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) -->
<skip />
<!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) -->
@@ -1232,14 +1166,6 @@
<skip />
<!-- no translation found for permdesc_accessNetworkConditions (6899102075825272211) -->
<skip />
- <!-- no translation found for permlab_setInputCalibration (4902620118878467615) -->
- <skip />
- <!-- no translation found for permdesc_setInputCalibration (4527511047549456929) -->
- <skip />
- <!-- no translation found for permlab_accessDrmCertificates (7436886640723203615) -->
- <skip />
- <!-- no translation found for permdesc_accessDrmCertificates (8073288354426159089) -->
- <skip />
<!-- no translation found for policylab_limitPassword (4497420728857585791) -->
<skip />
<!-- no translation found for policydesc_limitPassword (3252114203919510394) -->
@@ -2178,14 +2104,6 @@
<skip />
<!-- no translation found for permdesc_control_keyguard (3043732290518629061) -->
<skip />
- <!-- no translation found for permlab_trust_listener (1765718054003704476) -->
- <skip />
- <!-- no translation found for permdesc_trust_listener (8233895334214716864) -->
- <skip />
- <!-- no translation found for permlab_bind_trust_agent_service (8242093169457695334) -->
- <skip />
- <!-- no translation found for permdesc_bind_trust_agent_service (7041930026024507515) -->
- <skip />
<!-- no translation found for permlab_recovery (3157024487744125846) -->
<skip />
<!-- no translation found for permdesc_recovery (8511774533266359571) -->
@@ -2222,8 +2140,6 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Midar il fund davos"</string>
<!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
<skip />
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
<!-- no translation found for vpn_title (19615213552042827) -->
<skip />
<!-- no translation found for vpn_title_long (6400714798049252294) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 33a5a81..21c8a11 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TO"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PO"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> (de) zile"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> zile <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> zi <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> h"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> (de) min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> sec"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> sec"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sec"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sec"</string>
<string name="untitled" msgid="4638956954852782576">"<Fără titlu>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizare"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Prea multe ştergeri <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Stocarea pe tabletă este plină. Ștergeţi câteva fişiere pentru a elibera spaţiu."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Spațiul de stocare de pe ceas este plin! Ștergeți câteva fișiere pentru a elibera spațiu."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Stocarea pe telefon este plină. Ștergeţi câteva fişiere pentru a elibera spaţiu."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Rețeaua poate fi monitorizată"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"De o terță parte necunoscută"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Sonerie activată"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Se închide..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Computerul dvs. tablet PC se va închide."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ceasul dvs. se va închide."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefonul dvs. se va închide."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Doriţi să închideţi?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reporniţi în modul sigur"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mod Avion"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modul Avion este ACTIVAT"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modul avion este DEZACTIVAT"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Setări"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"˃999"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Servicii cu plată"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Efectuează acţiuni care sunt cu plată."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Mesajele dvs."</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"dezinstalează comenzi rapide"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permite aplicației să elimine comenzi rapide de pe ecranul de pornire, fără intervenția utilizatorului."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"redirecţionează apelurile efectuate"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permite aplicației să vadă numărul format în timpul unui apel de ieșire, cu opțiunea de a redirecționa apelul către un alt număr sau de a întrerupe apelul."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Permite aplicaţiei să proceseze apelurile efectuate şi să schimbe numărul care trebuie format. Cu această permisiune aplicaţia poate monitoriza, redirecţiona sau împiedica apelurile efectuate."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"primeşte mesaje text (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Permite aplicaţiei să primească şi să proceseze mesaje SMS. Acest lucru înseamnă că aplicaţia ar putea monitoriza sau şterge mesajele trimise pe dispozitivul dvs. fără a vi le arăta."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"primeşte mesaje text (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Permite aplicaţiei să preia conţinutul ferestrei active. Aplicaţiile rău intenţionate pot să preia întregul conţinut al ferestrei şi să examineze integral textul acesteia, cu excepţia parolelor."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"activare temporară a accesibilității"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Permite unei aplicaţii să activeze temporar accesibilitatea pe gadget. Aplicaţiile rău intenţionate o pot activa fără consimţământul utilizatorului."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"preluarea indicativului ferestrei"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Permite unei aplicații să preia indicativul ferestrei. Aplicațiile dăunătoare pot interacționa neautorizat cu fereastra aplicației substituindu-se sistemului."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"preluarea statisticilor de referință"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Permite unei aplicații să culeagă statistici de referință. Aplicațiile dăunătoare ar putea urmări statisticile de referință ale ferestrelor din alte aplicații."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"preluare informaţii despre ferestre"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Permite unei aplicaţii să preia informaţii despre ferestrele din managerul de ferestre. Aplicaţiile rău intenţionate pot prelua informaţii care sunt destinate utilizării sistemului intern."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtrare evenimente"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Permite unei aplicaţii să înregistreze un filtru de intrare, care filtrează transmiterea în flux a tuturor evenimentelor utilizatorilor înainte ca acestea să fie expediate. Aplicaţiile rău intenţionate pot controla interfaţa de utilizare a sistemului fără intervenţia utilizatorului."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"măreşte afişajul"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Permite unei aplicaţii să mărească conţinutul unui afişaj. Aplicaţiile rău intenţionate pot transforma conţinutul afişajului într-un mod care ar face inutilizabil dispozitivul."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"închidere parţială"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Plasează Managerul de activităţi într-o stare de închidere. Nu efectuează o închidere completă."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"împiedicare comutare între aplicaţii"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permite aplicaţiei să difuzeze o notificare de primire a unui mesaj SMS. Aplicaţiile rău intenţionate pot să utilizeze această permisiune pentru a deturna primirea mesajelor SMS."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"trimitere mesaj difuzat primit prin WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permite aplicaţiei să difuzeze o notificare de primire a unui mesaj WAP PUSH. Aplicaţiile rău intenţionate pot să utilizeze această permisiune pentru a deturna primirea mesajelor MMS sau pentru a înlocui fără a vă înştiinţa conţinutul oricărei pagini web cu variante rău intenţionate."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"trimiteți transmisia cu rețelele punctate"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permite aplicației să transmită o notificare de care rețelele au nevoie pentru a fi punctate. Nu este necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitare număr de procese în derulare"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permite aplicaţiei să controleze numărul maxim de procese care vor rula. Nu este niciodată necesară pentru aplicaţiile obişnuite."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forţează închiderea aplicaţiilor de fundal"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unui serviciu VPN. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"conectare la o imagine de fundal"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unei imagini de fundal. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"conectare la un serviciu de interacțiune vocală"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de interacțiune vocală. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"conectare la un ecran la distanță"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite proprietarului să se conecteze la interfața de nivel superior a unui ecran la distanță. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"conectare la un serviciu widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unui serviciu widget. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"se conectează la un serviciu de furnizare a traseelor"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permite titularului să se conecteze la furnizorii de trasee înregistrați. Nu este necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacţionare cu administratorul unui dispozitiv"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite proprietarului să trimită intenţii către un administrator al dispozitivului. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"se conectează la o intrare TV"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Permite proprietarului să se conecteze la interfața de nivel superior a unei intrări TV. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"adăugarea sau eliminarea unui administrator de dispozitiv"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Permite proprietarului să adauge sau să elimine administratorii activi ai dispozitivului. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"modificare orientare ecran"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite aplicaţiei să utilizeze orice decodor media instalat pentru a decodifica redarea."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestionarea acreditărilor de încredere"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite aplicației să instaleze și să dezinstaleze certificate CA ca acreditări de încredere."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"rulează aplicația în timp ce dispozitivul este inactiv"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Cu această permisiune, sistemul Android poate rula aplicația în fundal în timp ce dispozitivul nu este utilizat."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"asociați cu serviciile inactive"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Această autorizare permite sistemului Android să se conecteze la serviciile inactive ale unei aplicații."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"citire/scriere în resursele deţinute de diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite aplicaţiei să citească şi să scrie în orice resursă deţinută de grupul diag, de ex., fişierele din /dev. Această permisiune ar putea să afecteze stabilitatea şi securitatea sistemului. Permisiunea trebuie utilizată NUMAI de producător sau de operator pentru diagnostice specifice pentru hardware."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"activare sau dezactivare a componentelor aplicaţiei"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Permite aplicaţiei să citească informaţiile personale din profil stocate pe dispozitiv, cum ar fi numele şi informaţiile de contact, ceea ce înseamnă că aplicaţia vă poate identifica şi poate trimite informaţiile dvs. de profil altor utilizatori."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"modifică cartea dvs. de vizită"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Permite aplicaţiei să schimbe sau să adauge conţinut în informaţiile personale din profil stocate pe dispozitivul dvs., cum ar fi numele şi informaţiile dvs. de contact. Aceasta înseamnă că aplicaţia vă poate identifica şi poate trimite informaţiile din profilul dvs. altor persoane."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"senzori (ex.: senzori de ritm cardiac)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Permite aplicației să acceseze datele de la senzorii pe care îi utilizați pentru a măsura funcțiile corpului, cum ar fi ritmul cardiac."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"citeşte fluxul social"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Permite aplicaţiei să acceseze şi să sincronizeze actualizările sociale de la dvs. şi de la prietenii dvs. Daţi dovadă de precauţie când distribuiţi informaţii - cu această permisiune aplicaţia citeşte comunicările realizate între dvs. şi prietenii dvs. în reţelele sociale, indiferent de gradul de confidenţialitate a acestora. Notă: această permisiune nu poate fi aplicată pentru toate reţelele sociale."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"scrie în fluxul social"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite aplicaţiei să controleze funcţiile de telefon ale dispozitivului. O aplicaţie cu această permisiune poate să schimbe reţeaua, să închidă şi să deschidă radioul şi să efectueze alte acţiuni similare, fără să vă înştiinţeze."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"citeşte starea şi identitatea telefonului"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite aplicaţiei să acceseze funcţiile de telefon ale dispozitivului. Cu această permisiune aplicaţia stabileşte numărul de telefon şi ID-urile de dispozitiv, dacă un apel este activ, precum şi numărul de la distanţă conectat printr-un apel."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"accesați stările exacte ale telefonului"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permite aplicației să acceseze stările exacte ale telefonului. Cu această permisiune, aplicația poate să determine starea reală a apelului, dacă apelul este activ sau în fundal, dacă apelul eșuează, starea exactă și întreruperile conexiunii de date."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"împiedicarea computerului tablet PC să intre în repaus"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"împiedicare intrare telefon în repaus"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite aplicaţiei să împiedice intrarea tabletei în stare de repaus."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Schimbaţi starea WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite aplicaţiei să conecteze şi să deconecteze tableta la şi de la reţelele WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite aplicaţiei să conecteze şi să deconecteze telefonul la şi de la reţelele WiMAX."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"rețele punctate"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permite aplicației să clasifice rețelele și să stabilească ce rețele preferă tableta."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permite aplicației să clasifice rețelele și să stabilească ce rețele preferă telefonul."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"conectează dispozitive Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite aplicaţiei să vadă configuraţia tabletei Bluetooth, să efectueze şi să accepte conexiuni cu dispozitive împerecheate."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite aplicaţiei să vadă configuraţia telefonului Bluetooth, să efectueze şi să accepte conexiuni cu dispozitive împerecheate."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite aplicației să recupereze, să examineze și să șteargă notificări, inclusiv pe cele postate de alte aplicații."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"conectare la un serviciu de citire a notificărilor"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de citire a notificărilor. În mod normal aplicațiile nu ar trebui să aibă nevoie de această permisiune."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"conectare la un serviciu furnizor de condiții"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu furnizor de condiții. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"apelarea aplicației de configurare furnizată de operator"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite proprietarului să apeleze aplicația de configurare furnizată de operator. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ascultă observații despre starea rețelei"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite unei aplicații să asculte observații despre starea rețelei. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"schimbați calibrarea dispozitivului de intrare"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite aplicației să modifice parametrii de calibrare a ecranului tactil. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"accesează certificatele DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Permite unei aplicații să furnizeze și să utilizeze certificate DRM. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Stabiliţi lungimea şi tipul de caractere permise în parolele pentru deblocarea ecranului."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizaţi încercările de deblocare a ecranului"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Permite unei aplicații să acceseze stocarea securizată când tastatura este blocată."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Stabilește afișarea și ascunderea blocării tastaturii"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite unei aplicații să controleze blocarea tastaturii."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Detectarea modificărilor în starea de încredere."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite unei aplicații să detecteze modificările în starea de încredere."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Asocierea la un serviciu „agenți de încredere”."</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite unei aplicații să se asocieze la un serviciu „agent de încredere”."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interacțiune cu sistemul de recuperare și de actualizare"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Permite unei aplicații să interacționeze cu sistemul de recuperare și cu actualizările de sistem."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Atingeţi de două ori pentru a mări/micşora"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Imagine de fundal"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Modificaţi imaginea de fundal"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Serviciu de citire a notificărilor"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Furnizor de condiții"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activat"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN este activată de <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Atingeţi pentru a gestiona reţeaua."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index c7c5a08..9bc6bcd 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TБ"</string>
<string name="petabyteShort" msgid="5637816680144990219">"ПБ"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> дн."</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> день <xliff:g id="HOURS">%2$d</xliff:g> ч."</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> день <xliff:g id="HOURS">%2$d</xliff:g> ч."</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> ч."</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> ч. <xliff:g id="MINUTES">%2$d</xliff:g> мин."</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> ч. <xliff:g id="MINUTES">%2$d</xliff:g> мин."</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> мин."</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> мин. <xliff:g id="SECONDS">%2$d</xliff:g> с"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> мин. <xliff:g id="SECONDS">%2$d</xliff:g> с"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> с"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> с"</string>
<string name="untitled" msgid="4638956954852782576">"<Без названия>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"..."</string>
@@ -146,9 +135,8 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синхр."</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Слишком много удалений <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Память планшетного ПК заполнена. Удалите какие-нибудь файлы, чтобы освободить место."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Память устройства заполнена. Удалите файлы, чтобы освободить место."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Память телефона заполнена. Удалите какие-нибудь файлы, чтобы освободить место."</string>
- <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Сеть может отслеживаться"</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Действия в сети могут отслеживаться"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"администратором"</string>
<string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"администратором домена <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Я"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Звонок включен"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Выключение..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Планшетный ПК будет отключен."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Устройство будет отключено."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Телефон будет выключен."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Завершить работу?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Переход в безопасный режим"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Режим полета"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Выключить"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Включить"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Настройки"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Платные услуги"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Приложение сможет использовать платные услуги."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Сообщения"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"Удаление ярлыков"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Приложение сможет удалять ярлыки с главного экрана без вмешательства пользователя."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"Перенаправление исходящих вызовов"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Приложение сможет видеть набранный номер во время исходящего вызова и при необходимости перенаправлять вызов или завершать его."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Приложение сможет обрабатывать исходящие вызовы и изменять набираемые номера, а также отслеживать, перенаправлять или блокировать исходящие вызовы."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"Прием SMS-сообщений"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Приложение сможет получать и обрабатывать SMS. Это значит, что оно сможет отслеживать и удалять отправленные на ваше устройство сообщения, не показывая их."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"Прием MMS-сообщений"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Приложение сможет получать контент активного окна. Вредоносные программы смогут перехватывать такой контент и анализировать любой текст, кроме паролей."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"Включение специальных возможностей"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Приложение сможет временно включать на устройстве специальные возможности. Вредоносные приложения смогут включать их без вашего ведома."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"получение токена окна"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Приложение может получать токен окна. Вредоносные программы могут взаимодействовать с окном приложения под видом системы."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"получение статистики по фреймам"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Приложение может собирать статистику по фреймам. Вредоносные приложения могут получать доступ к такой статистике у других программ."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"Доступ к информации в окне"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Открывает приложению доступ к информации из диспетчера окон. Обратите внимание, что вредоносное ПО может получить доступ к некоторой системной информации устройства."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"Фильтрация событий"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Разрешает приложению зарегистрировать входной фильтр, который анализирует весь поток пользовательских событий. Обратите внимание, что вредоносное ПО может получить доступ к управлению интерфейсом без ведома пользователя."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"Увеличение изображений"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Приложение сможет увеличивать содержимое экрана. Вредоносные программы смогут изменять изображение таким образом, что устройством нельзя будет пользоваться."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"Частичное завершение работы"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Завершает работу диспетчера активности. Не выполняет полное завершение работы."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"Защита от переключения приложений"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Приложение сможет уведомлять о получении SMS. Вредоносные программы смогут таким образом подделывать входящие SMS."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"Отправка уведомлений о доставке SMS с ссылкой на WAP-страницу"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Приложение сможет уведомлять о получении сообщений WAP PUSH. Вредоносные программы смогут таким образом фальсифицировать получение MMS или незаметно подменять содержание любой страницы вредоносными данными."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"Отправка уведомлений о рейтинге сетей"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Приложение сможет отправлять уведомления о том, что сети необходимо присвоить рейтинг. Это разрешение обычно используется только специальными приложениями."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"Ограничение количества запущенных процессов"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Приложение сможет управлять максимальным количеством процессов, которые могут быть запущены. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"Закрытие фоновых приложений"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Приложение сможет подключаться к базовому интерфейсу службы VPN. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"Привязка к фоновому рисунку"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Приложение сможет подключаться к базовому интерфейсу службы обоев. Это разрешение не используется обычными приложениями."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"Подключение к службам голосового взаимодействия"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Приложение сможет подключаться к базовому интерфейсу служб голосового взаимодействия. Это разрешение обычно используется только специальными приложениями."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"Подключение к удаленному дисплею"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Приложение сможет подключаться к базовому интерфейсу удаленного дисплея. Это разрешение обычно используется только специальными приложениями."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"Подключение к службе виджетов"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Приложение сможет подключаться к базовому интерфейсу службы виджетов. Это разрешение не используется обычными приложениями."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"Подключение к серверам поставщиков маршрутов"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Приложение сможет подключаться к серверам зарегистрированных поставщиков маршрутов. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Взаимодействие с администратором устройства"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Приложение сможет отправлять объекты intent администратору устройства. Это разрешение не используется обычными приложениями."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"Подключение к ТВ-входу"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Приложение сможет подключаться к базовому интерфейсу ТВ-входа. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"Добавление/удаление администратора устройства"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Владелец сможет добавлять и удалять администраторов устройства (используется лишь в некоторых приложениях)."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"Изменение ориентации экрана"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Приложение сможет использовать любой установленный дешифратор."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Управление учетными данными"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Приложение сможет устанавливать сертификаты ЦС в качестве надежных учетных данных, а также удалять их."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"выполнение приложения в спящем режиме"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Система Android сможет выполнять приложение в фоновом режиме, когда устройство не используется."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"привязка неактивных сервисов"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Android сможет подключаться к неактивным сервисам."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"Чтение/запись данных в системы диагностики"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Приложение сможет считывать и записывать данные системы диагностики (например, файлы в каталоге /dev). Это может повлиять на стабильность и безопасность системы. Это разрешение должно использоваться ТОЛЬКО производителем или оператором для диагностики аппаратного обеспечения."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"Включение/отключение компонентов приложения"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Приложение сможет просматривать вашу личную информацию (например, имя и контактные данные), сохраненную на устройстве. Получив эти данные, приложение сможет отправить их другим пользователям."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"Изменение ваших контактных данных"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Приложение сможет изменять вашу личную информацию (например, имя и контактные данные), сохраненную на устройстве. Получив эти данные, приложение сможет отправить их другим пользователям."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"датчики (например, пульсометр)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Приложение получит доступ к данным приборов, используемых для измерения ваших физиологических показателей (например, пульса)."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"Просмотр записей в вашей социальной ленте"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Приложение сможет просматривать и синхронизировать записи, публикуемые вами и вашими друзьями в социальных сетях. Будьте осторожны при передаче информации! С этим разрешением приложение сможет просматривать вашу переписку с друзьями в социальных сетях независимо от настроек конфиденциальности. Примечание. Это разрешение может применяться не во всех социальных сетях."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"Добавление записей в вашу социальную ленту"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Приложение сможет управлять на устройстве функциями телефона: переключать сети, включать и выключать приемопередатчик, а также выполнять другие подобные действия без уведомления."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"Получение данных о статусе телефона"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Приложение получит доступ к функциям телефона на устройстве. Кроме того, оно сможет определять номера телефонов и серийные номера моделей, состояние активности вызова, а также удаленные номера, с которыми установлено соединение."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"Доступ к точным статусам телефона"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Приложение сможет определять точный статус вызовов (активный, в фоновом режиме или сбой), а также статус интернет-соединения (в том числе, если подключиться не удалось)."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Отключение спящего режима"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Отключение спящего режима"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Приложение сможет запрещать перевод планшетного ПК в спящий режим."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Изменение статуса WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Приложение сможет подключать устройство к сетям WiMAX и отключать его от них."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Приложение сможет подключать устройство к сетям WiMAX и отключать его от них."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"Определение рейтинга сетей"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Приложение сможет присваивать сетям рейтинг и решать, к каким из них устройство должно подключаться в первую очередь."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Приложение сможет присваивать сетям рейтинг и решать, к каким из них устройство должно подключаться в первую очередь."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Установление связи с устройствами Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Приложение сможет просматривать конфигурацию Bluetooth на планшетном ПК, а также запрашивать и подтверждать соединение с другими устройствами."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Приложение сможет просматривать конфигурацию Bluetooth на телефоне, а также запрашивать и подтверждать соединение с другими устройствами."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Приложение сможет получать, проверять и удалять уведомления, включая те, что опубликованы другими приложениями."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Подключение к службе просмотра уведомлений"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Приложение сможет подключаться к базовому интерфейсу службы просмотра уведомлений. Это разрешение не используется обычными приложениями."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"Подключение к серверам поставщиков условий"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Приложение сможет подключаться к базовому интерфейсу поставщиков условий. Это разрешение обычно используется только специальными приложениями."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Запуск приложения настроек, предоставленного оператором"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Владелец сможет запускать приложение настроек, предоставленное оператором. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Использование данных о состоянии сети"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Приложение сможет использовать данные о состоянии сети. Это разрешение обычно используется только специальными приложениями."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"изменение параметров калибровки экрана"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Приложение сможет изменять параметры калибровки сенсорного экрана. Это разрешение обычно используется только специальными приложениями."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"Доступ к сертификатам DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Приложение сможет синхронизировать и использовать сертификаты DRM (разрешение актуально только для специальных приложений)."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Правила выбора паролей"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролировать длину и символы при вводе паролей для снятия блокировки экрана."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Отслеживать попытки снятия блокировки экрана"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Приложение сможет получить доступ к хранилищу ключей."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Управлять отображением хранилища ключей"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Приложение сможет управлять хранилищем ключей."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Отслеживание изменений статуса доверия"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Приложение сможет отслеживать изменения в статусе доверия."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Подключение к службе Trust Agents"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Приложение сможет подключаться к службе Trust Agents."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Взаимодействовать с системой восстановления и обновлениями"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Приложение сможет взаимодействовать с системой восстановления и обновлениями системы."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Нажмите дважды для изменения масштаба"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновый рисунок"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Сменить обои"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба просмотра уведомлений"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Поставщик условий"</string>
<string name="vpn_title" msgid="19615213552042827">"Сеть VPN активна"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Сеть VPN активирована приложением <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Нажмите, чтобы открыть настройки."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 08e4c08..5fc592c 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> d."</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> d. <xliff:g id="HOURS">%2$d</xliff:g> hod."</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> d. <xliff:g id="HOURS">%2$d</xliff:g> hod."</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> hod."</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> hod. <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> hod. <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min."</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min. <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min. <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
<string name="untitled" msgid="4638956954852782576">"<Bez mena>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -49,7 +38,7 @@
<string name="mmiFdnError" msgid="5224398216385316471">"Operácia je obmedzená len na režim čísla pevného vytáčania."</string>
<string name="serviceEnabled" msgid="8147278346414714315">"Služba bola povolená."</string>
<string name="serviceEnabledFor" msgid="6856228140453471041">"Služba bola povolená pre:"</string>
- <string name="serviceDisabled" msgid="1937553226592516411">"Služba bola vypnutá."</string>
+ <string name="serviceDisabled" msgid="1937553226592516411">"Služba bola zakázaná."</string>
<string name="serviceRegistered" msgid="6275019082598102493">"Registrácia prebehla úspešne."</string>
<string name="serviceErased" msgid="1288584695297200972">"Vymazanie prebehlo úspešne."</string>
<string name="passwordIncorrect" msgid="7612208839450128715">"Nesprávne heslo."</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronizovať"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Príliš veľa odstránených položiek služby <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Ukladací priestor tabletu je plný. Odstráňte niektoré súbory a uvoľnite miesto."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Ukladací priestor hodiniek je plný. Uvoľnite miesto odstránením niektorých súborov."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Pamäť telefónu je plná. Odstráňte niektoré súbory a uvoľnite miesto."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Sieť môže byť monitorovaná"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Neznámou treťou stranou"</string>
@@ -157,14 +145,13 @@
<string name="silent_mode" msgid="7167703389802618663">"Tichý režim"</string>
<string name="turn_on_radio" msgid="3912793092339962371">"Zapnúť bezdrôtové pripojenie"</string>
<string name="turn_off_radio" msgid="8198784949987062346">"Vypnúť bezdrôtové pripojenie"</string>
- <string name="screen_lock" msgid="799094655496098153">"Zámka obrazovky"</string>
+ <string name="screen_lock" msgid="799094655496098153">"Uzamknutie obrazovky"</string>
<string name="power_off" msgid="4266614107412865048">"Vypnúť"</string>
<string name="silent_mode_silent" msgid="319298163018473078">"Zvonenie je vypnuté"</string>
<string name="silent_mode_vibrate" msgid="7072043388581551395">"Vibračné zvonenie"</string>
<string name="silent_mode_ring" msgid="8592241816194074353">"Zvonenie je zapnuté"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Prebieha vypínanie..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Váš tablet bude vypnutý."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Hodinky sa vypnú."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Váš telefón bude vypnutý."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Chcete zariadenie vypnúť?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reštartovať do núdzového režimu"</string>
@@ -173,23 +160,20 @@
<string name="no_recent_tasks" msgid="8794906658732193473">"Žiadne nedávne aplikácie"</string>
<string name="global_actions" product="tablet" msgid="408477140088053665">"Možnosti tabletu"</string>
<string name="global_actions" product="default" msgid="2406416831541615258">"Možnosti telefónu"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Zámka obrazovky"</string>
+ <string name="global_action_lock" msgid="2844945191792119712">"Uzamknutie obrazovky"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Vypnúť"</string>
- <string name="global_action_bug_report" msgid="7934010578922304799">"Hlásenie o chybách"</string>
- <string name="bugreport_title" msgid="2667494803742548533">"Vytvoriť hlásenie o chybách"</string>
- <string name="bugreport_message" msgid="398447048750350456">"Zhromaždí informácie o aktuálnom stave zariadenia na odoslanie v e-mailovej správe. Chvíľu však potrvá, kým bude hlásenie o chybách pripravené na odoslanie. Prosíme vás preto o trpezlivosť."</string>
+ <string name="global_action_bug_report" msgid="7934010578922304799">"Správa o chybe"</string>
+ <string name="bugreport_title" msgid="2667494803742548533">"Zaznamenať správu o chybe"</string>
+ <string name="bugreport_message" msgid="398447048750350456">"Zhromažďuje informácie o aktuálnom stave zariadenia a tieto informácie je následne možné odoslať prostredníctvom e-mailovej správy. Od spustenia vytvárania správy o chybe až do chvíle, kedy je tento nástroj pripravený odoslať prvú správu, môže uplynúť nejaký čas. Prosíme vás preto o trpezlivosť."</string>
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tichý režim"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Zvuk je VYPNUTÝ."</string>
<string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Zvuk je zapnutý"</string>
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Režim V lietadle"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim V lietadle je ZAPNUTÝ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim V lietadle je VYPNUTÝ"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Nastavenia"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Spoplatnené služby"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Vykonávanie činností, ktoré vás môžu stáť peniaze."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vaše správy"</string>
@@ -206,7 +190,7 @@
<string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Prístup k zariadeniam a sieťam prostredníctvom rozhrania Bluetooth."</string>
<string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Nastavenia zvuku"</string>
<string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Zmena nastavení zvuku."</string>
- <string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Vplyv na batériu"</string>
+ <string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Má vplyv na batériu"</string>
<string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"Používanie funkcií, ktoré môžu rýchlo vyčerpať batériu."</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendár"</string>
<string name="permgroupdesc_calendar" msgid="5777534316982184416">"Priamy prístup ku kalendáru a udalostiam."</string>
@@ -248,8 +232,8 @@
<string name="permgroupdesc_developmentTools" msgid="7058828032358142018">"Funkcie len pre vývojárov aplikácií."</string>
<string name="permgrouplab_display" msgid="4279909676036402636">"Používateľské rozhranie iných aplikácií"</string>
<string name="permgroupdesc_display" msgid="6051002031933013714">"Vplyv na používateľské rozhranie ďalších aplikácií."</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Úložisko"</string>
- <string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Prístup do úložiska USB."</string>
+ <string name="permgrouplab_storage" msgid="1971118770546336966">"Ukladací priestor"</string>
+ <string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Prístup do ukl. priestoru USB."</string>
<string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Prístup na kartu SD."</string>
<string name="permgrouplab_accessibilityFeatures" msgid="7919025602283593907">"Funkcie zjednodušenia ovládania"</string>
<string name="permgroupdesc_accessibilityFeatures" msgid="4205196881678144335">"Funkcie, ktoré môže vyžadovať nápomocná technológia."</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"odinštalovať odkazy"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Povoľuje aplikácii odstrániť odkazy na ploche bez zásahu používateľa."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"presmerovať odchádzajúce hovory"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Umožňuje aplikácii počas odchádzajúceho hovoru rozpoznať vytáčané číslo a poskytuje možnosť presmerovať daný hovor na odlišné číslo alebo ho úplne zrušiť."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Umožňuje aplikácii spracovávať odchádzajúce hovory a meniť vytáčané číslo. Toto povolenie umožňuje aplikácii sledovať a presmerovať odchádzajúce hovory alebo im zabrániť."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"prijímať textové správy (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Umožňuje aplikácii prijímať a spracovávať správy SMS. Znamená to, že aplikácia môže sledovať správy odoslané na vaše zariadenie alebo ich odstrániť bez toho, aby sa vám zobrazili."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"prijímať textové správy (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Umožňuje aplikácii načítať obsah aktívneho okna. Škodlivé aplikácie môžu získať celý obsah okna a preskúmať celý jeho text okrem hesiel."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"dočasné povolenie zjednodušenia ovládania"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Umožňuje aplikácii dočasne povoliť zjednodušenie ovládania v zariadení. Škodlivé aplikáciu môžu zjednodušenie ovládania povoliť bez súhlasu používateľa."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"získať token okna"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Umožňuje aplikácii získať token okna. Škodlivé aplikácie sa môžu správať ako systém a vykonať neautorizovanú interakciu s oknom aplikácie."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"získať štatistiky rámcov"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Umožňuje aplikácii zhromažďovať štatistiky rámcov. Škodlivé aplikácie môžu sledovať štatistiky rámcov okien z iných aplikácií."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"načítanie informácií o oknách"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Umožňuje aplikácii načítať informácie o oknách zo správcu okien. Škodlivé aplikácie môžu načítať informácie, ktoré sú určené pre interné využitie systému."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtrovanie udalostí"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Umožňuje aplikácii zaregistrovať vstupný filter, ktorý filtruje stream všetkých prenosov používateľa pred ich odvysielaním. Škodlivá aplikácia môže bez zásahu používateľa ovládať používateľské rozhranie systému."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"priblížiť zobrazenie"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Umožňuje aplikácii priblížiť obsah displeja. Škodlivé aplikácie môžu zmeniť zobrazenie obsahu tak, že sa zariadenie stane nepoužiteľným."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"Čiastočné vypnutie"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Uvedie správcu činností do vypnutého stavu. Úplné vypnutie však nenastane."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zabrániť prepínaniu aplikácií"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Umožňuje aplikácii vysielať oznámenie, že správa SMS bola doručená. Škodlivé aplikácie môžu toto nastavenie použiť na falšovanie prichádzajúcich správ SMS."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"odoslanie vysielania typu WAP-PUSH-received"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Umožňuje aplikácii vysielať oznámenie, že správa WAP PUSH bola doručená. Škodlivé aplikácie môžu použiť toto nastavenie na vytvorenie potvrdenia o doručení správy MMS alebo na utajené nahradenie obsahu akejkoľvek stránky škodlivými variantmi."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"odoslanie skóre vysielaných sieťami"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Umožňuje aplikácii vysielať upozornenie, že je potrebné zadať skóre sietí. Bežné aplikácie toto povolenie nepotrebujú."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"obmedzenie počtu spustených procesov"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Umožňuje aplikácii kontrolovať maximálny počet spustených procesov. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"vynútiť zavretie aplikácií na pozadí"</string>
@@ -369,7 +351,7 @@
<string name="permdesc_backup" msgid="6912230525140589891">"Umožňuje aplikácii ovládať mechanizmus na zálohovanie a obnovu údajov systému. Bežné aplikácie toto nastavenie nepoužívajú."</string>
<string name="permlab_confirm_full_backup" msgid="5557071325804469102">"potvrdenie operácie úplnej zálohy alebo úplného obnovenia"</string>
<string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Umožňuje aplikácii spustiť používateľské rozhranie potvrdenia úplnej zálohy. Toto nastavenie by nemala používať žiadna aplikácia."</string>
- <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"zobraziť neoprávnené okná"</string>
+ <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"zobrazenie neoprávnených okien"</string>
<string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Umožňuje aplikácii vytvárať okná, ktoré majú byť použité interným systémom používateľského rozhrania. Bežné aplikácie toto nastavenie nepoužívajú."</string>
<string name="permlab_systemAlertWindow" msgid="3543347980839518613">"vykresliť cez ďalšie aplikácie"</string>
<string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Umožňuje aplikáciu vykresľovanie nad inými aplikáciami alebo súčasťami používateľského rozhrania. Táto funkcia môže zasahovať do vášho používania rozhrania inej aplikácie alebo meniť zobrazovaný obsah v iných aplikáciách."</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby VPN. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"väzba na tapetu"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania tapety. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"viazanie na hlasovú interakciu"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby hlasovej interakcie. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"viazať na vzdialený displej"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania vzdialeného displeja. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"viazať sa k službe miniaplikácie"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby miniaplikácií. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"viazanie na službu poskytovateľa cesty"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Umožňuje držiteľovi viazať sa na akýchkoľvek registrovaných poskytovateľov cesty. Normálne aplikácie by toto povolenie nemali nikdy nepotrebovať."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovať so správcom zariadenia"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Umožňuje držiteľovi odosielať informácie správcovi zariadenia. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"viazanie na televízny vstup"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Umožňuje aplikácii používať na reprodukciu ľubovoľný nainštalovaný dekódovač na dekódovanie."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"spravovať dôveryhodné poverenia"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Umožňuje aplikácii inštalovať a odinštalovať certifikáty CA ako dôveryhodné poverenia."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"spustiť aplikáciu počas nečinnosti"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Toto povolenie umožňuje systému Android spustiť aplikáciu na pozadí, keď sa zariadenie nepoužíva."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"previazať s nečinnými službami"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Toto povolenie umožní systému Android viazať sa na nečinné služby aplikácie."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"čítanie alebo zápis do prostriedkov funkcie diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Umožňuje aplikácii čítať ľubovoľné prostriedky v skupine diag, napr. súbory v priečinku /dev, a zapisovať do nich. Môže dôjsť k ovplyvneniu stability a bezpečnosti systému. Toto nastavenie by mal používať IBA výrobca či operátor na diagnostiku hardvéru."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"povoliť alebo zakázať súčasti aplikácie"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Umožňuje aplikácii čítať informácie v osobnom profile uložené v zariadení, ako je vaše meno a kontaktné informácie. Znamená to, že vás ostatné aplikácie môžu identifikovať a odoslať informácie o vašom profile iným aplikáciám."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"upraviť vlastnú kartu kontaktu"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Umožňuje aplikácii zmeniť alebo pridať do osobného profilu informácie uložené vo vašom zariadení, ako je vaše meno a kontaktné informácie. Znamená to, že vás aplikácia môže identifikovať a odoslať informácie o vašom profile ostatným aplikáciám."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"telesné senzory (napr. snímače tepu)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Umožňuje aplikácii pristupovať k údajom zo senzorov, pomocou ktorých meriate činnosť svojho tela, napríklad tep."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"čítať váš sociálny stream"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Umožňuje aplikácii pristupovať k sociálnym aktualizáciám od vás a vašich priateľov a synchronizovať ich. Pri zdieľaní informácií dávajte pozor – toto povolenie umožňuje aplikácii čítať komunikáciu medzi vami a vašimi priateľmi v sociálnych sieťach, a to bez ohľadu na jej dôvernosť. Poznámka: Toto povolenie nie je možné vynucovať v prípade všetkých sociálnych sietí."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"písať do vášho sociálneho streamu"</string>
@@ -504,9 +480,9 @@
<string name="permdesc_accessLocationExtraCommands" msgid="5945166642335800763">"Umožňuje aplikácii pristupovať k ďalším príkazom poskytovateľa informácií o polohe. Aplikácii to môže umožniť zasahovať do činnosti systému GPS alebo iných zdrojov informácií o polohe."</string>
<string name="permlab_installLocationProvider" msgid="6578101199825193873">"Oprávnenie na inštaláciu poskytovateľa polohy"</string>
<string name="permdesc_installLocationProvider" msgid="9066146120470591509">"Vytváranie simulovaných zdrojov polohy na testovanie alebo inštalácia nového poskytovateľa informácií o polohe. Aplikácii to umožní nahradiť polohu a stav, ktoré vracajú iné zdroje informácií o polohe, ako sú napríklad systém GPS alebo poskytovatelia informácií o polohe."</string>
- <string name="permlab_accessFineLocation" msgid="1191898061965273372">"zistiť presnú polohu (pomocou GPS a siete)"</string>
+ <string name="permlab_accessFineLocation" msgid="1191898061965273372">"presná poloha (pomocou GPS a siete)"</string>
<string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Umožňuje aplikácii získať vašu presnú polohu pomocou systému GPS (Global Positioning System) alebo zdrojov určenia polohy siete, napríklad mobilných veží a sietí Wi-Fi. Tieto služby určovania polohy musia byť na vašom zariadení zapnuté a dostupné, inak ich aplikácia nebude môcť využívať. Aplikácie môžu tieto služby využívať na určenie vašej polohy. Tieto služby môžu zvýšiť spotrebu batérie."</string>
- <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"zistiť približnú polohu (pomocou siete)"</string>
+ <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"približná poloha (pomocou siete)"</string>
<string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Umožňuje aplikácii získať vašu približnú polohu. Táto poloha je odvodená zo služieb určovania polohy pomocou zdrojov určenia polohy siete, napríklad mobilných veží a sietí Wi-Fi. Tieto služby určovania polohy musia byť na vašom zariadení zapnuté a dostupné, inak ich aplikácia nebude môcť využívať. Aplikácie môžu tieto služby využívať na určenie vašej približnej polohy."</string>
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"prístup k službe SurfaceFlinger"</string>
<string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Umožňuje aplikácii používať funkcie nízkej úrovne aplikácie SurfaceFlinger."</string>
@@ -528,13 +504,13 @@
<string name="permdesc_captureSecureVideoOutput" msgid="2779793064709350289">"Umožňuje aplikácii zachytiť a presmerovať zabezpečený výstup videa."</string>
<string name="permlab_mediaContentControl" msgid="8749790560720562511">"ovládanie reprodukcie médií a prístup k metadátam"</string>
<string name="permdesc_mediaContentControl" msgid="1637478200272062">"Umožňuje aplikácii ovládať reprodukciu médií a pristupovať k informáciám o médiách (názov, autor...)."</string>
- <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"meniť nastavenia zvuku"</string>
+ <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"zmeny vašich nastavení zvuku"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Umožňuje aplikácii upraviť globálne nastavenia zvuku, ako je hlasitosť, alebo určiť, z ktorého reproduktora bude zvuk vychádzať."</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"nahrávať zvuk"</string>
+ <string name="permlab_recordAudio" msgid="3876049771427466323">"záznam zvuku"</string>
<string name="permdesc_recordAudio" msgid="4906839301087980680">"Umožňuje aplikácii zaznamenávať zvuk pomocou mikrofónu. Toto povolenie umožňuje aplikácii zaznamenávať zvuk kedykoľvek bez vášho potvrdenia."</string>
<string name="permlab_sim_communication" msgid="1180265879464893029">"komunikácia s kartou SIM"</string>
<string name="permdesc_sim_communication" msgid="5725159654279639498">"Umožňuje aplikácii odosielať príkazy na kartu SIM. Toto je veľmi nebezpečné povolenie."</string>
- <string name="permlab_camera" msgid="3616391919559751192">"fotiť a nakrúcať videá"</string>
+ <string name="permlab_camera" msgid="3616391919559751192">"snímanie fotografií a natáčanie videí"</string>
<string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikácii fotografovať a nahrávať videá pomocou fotoaparátu. Toto povolenie umožňuje aplikácii používať fotoaparát kedykoľvek a bez vášho potvrdenia."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"Zakázať indikátor LED prenosu pri používaní fotoaparátu"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Umožňuje v predinštalovanej systémovej aplikácii zakázať indikátor LED používania fotoaparátu."</string>
@@ -554,17 +530,17 @@
<string name="permdesc_mount_format_filesystems" msgid="8784268246779198627">"Umožňuje aplikácii formátovať vymeniteľný ukladací priestor."</string>
<string name="permlab_asec_access" msgid="3411338632002193846">"získať informácie o internom ukladacom priestore"</string>
<string name="permdesc_asec_access" msgid="3094563844593878548">"Umožňuje aplikácii získať informácie o internom ukladacom priestore."</string>
- <string name="permlab_asec_create" msgid="6414757234789336327">"vytvoriť interné úložisko"</string>
- <string name="permdesc_asec_create" msgid="4558869273585856876">"Umožňuje aplikácii vytvoriť interné úložisko."</string>
- <string name="permlab_asec_destroy" msgid="526928328301618022">"zničiť interné úložisko"</string>
- <string name="permdesc_asec_destroy" msgid="7218749286145526537">"Umožňuje aplikácii zničiť interné úložisko."</string>
- <string name="permlab_asec_mount_unmount" msgid="8877998101944999386">"pripojiť alebo odpojiť interné úložisko"</string>
- <string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"Umožňuje aplikácii pripojiť alebo odpojiť interné úložisko."</string>
- <string name="permlab_asec_rename" msgid="7496633954080472417">"premenovať interné úložisko"</string>
- <string name="permdesc_asec_rename" msgid="1794757588472127675">"Umožňuje aplikácii premenovať interné úložisko."</string>
+ <string name="permlab_asec_create" msgid="6414757234789336327">"vytvoriť interný ukladací priestor"</string>
+ <string name="permdesc_asec_create" msgid="4558869273585856876">"Umožňuje aplikácii vytvoriť interný ukladací priestor."</string>
+ <string name="permlab_asec_destroy" msgid="526928328301618022">"zničiť interný ukladací priestor"</string>
+ <string name="permdesc_asec_destroy" msgid="7218749286145526537">"Umožňuje aplikácii zničiť interný ukladací priestor."</string>
+ <string name="permlab_asec_mount_unmount" msgid="8877998101944999386">"pripojiť alebo odpojiť interný ukladací priestor"</string>
+ <string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"Umožňuje aplikácii pripojiť alebo odpojiť interný ukladací priestor."</string>
+ <string name="permlab_asec_rename" msgid="7496633954080472417">"premenovať interný ukladací priestor"</string>
+ <string name="permdesc_asec_rename" msgid="1794757588472127675">"Umožňuje aplikácii premenovať interný ukladací priestor."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ovládať vibrovanie"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Umožňuje aplikácii ovládať vibrácie."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ovládať kontrolku"</string>
+ <string name="permlab_flashlight" msgid="2155920810121984215">"ovládanie kontrolky"</string>
<string name="permdesc_flashlight" msgid="6522284794568368310">"Umožňuje aplikácii ovládať svetlo."</string>
<string name="permlab_manageUsb" msgid="1113453430645402723">"spravovať predvoľby a povolenia zariadení USB"</string>
<string name="permdesc_manageUsb" msgid="7776155430218239833">"Umožňuje aplikácii spravovať predvoľby a povolenia zariadení USB."</string>
@@ -572,9 +548,9 @@
<string name="permdesc_accessMtp" msgid="6532961200486791570">"Povoľuje prístup k ovládaču kernel MTP na implementáciu protokolu MTP USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"testovanie hardvéru"</string>
<string name="permdesc_hardware_test" msgid="6597964191208016605">"Umožňuje aplikácii ovládať rôzne periférie na účely testovania hardvéru."</string>
- <string name="permlab_callPhone" msgid="3925836347681847954">"priamo volať na telefónne čísla"</string>
+ <string name="permlab_callPhone" msgid="3925836347681847954">"priame volanie na telefónne čísla"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Umožňuje aplikácii volať telefónne čísla bez vášho zásahu. V dôsledku toho sa môžu účtovať neočakávané poplatky alebo sa môžu uskutočniť neočakávané hovory. Toto povolenie neumožňuje aplikácii volať na čísla tiesňového volania."</string>
- <string name="permlab_callPrivileged" msgid="4198349211108497879">"priamo volať na ľubovoľné telefónne čísla"</string>
+ <string name="permlab_callPrivileged" msgid="4198349211108497879">"priame volanie na ľubovoľné telefónne čísla"</string>
<string name="permdesc_callPrivileged" msgid="1689024901509996810">"Umožňuje aplikácii volať na akékoľvek telefónne číslo (bez vášho zásahu) vrátane čísiel tiesňového volania. Škodlivé aplikácie môžu uskutočňovať zbytočné a nezákonné volania na tiesňové linky."</string>
<string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"priamo spustiť nastavenie tabletu CDMA"</string>
<string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"priamo spustiť nastavenie telefónu CDMA"</string>
@@ -589,10 +565,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Umožňuje aplikácii ovládať telefónne funkcie zariadenia. Aplikácia s týmto povolením môže prepínať siete alebo zapnúť a vypnúť rádio bez toho, aby vás na to upozornila."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"čítať stav a identitu telefónu"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Umožňuje aplikácii pristupovať k telefónnym funkciám zariadenia. Aplikácia s týmto povolením môže určiť telefónne číslo a ID zariadenia, či práve prebieha hovor, a vzdialené číslo, s ktorým je prostredníctvom hovoru nadviazané spojenie."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"čítanie presných stavov telefónu"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Umožňuje aplikácii pristupovať k presným stavom telefónu. Toto povolenie umožňuje aplikácii zistiť skutočný stav hovoru, či je hovor aktívny alebo na pozadí, zlyhania hovorov, presný stav dátového pripojenia a zlyhania dátového pripojenia."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zabránenie prechodu tabletu do režimu spánku"</string>
- <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"deaktivovať režim spánku"</string>
+ <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zabránenie prechodu telefónu do režimu spánku"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Umožňuje aplikácii zabrániť prechodu tabletu do režimu spánku."</string>
<string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Umožňuje aplikácii zabrániť prechodu telefónu do režimu spánku."</string>
<string name="permlab_transmitIr" msgid="7545858504238530105">"infračervený prenos"</string>
@@ -605,7 +579,7 @@
<string name="permlab_factoryTest" msgid="3715225492696416187">"spustenie v režime továrenského testu"</string>
<string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Umožňuje aplikácii spustenie v režime nízkoúrovňového testu výrobcu a povolí úplný prístup k hardvéru tabletu. K dispozícii iba vtedy, keď je tablet spustený v režime testovania výrobcu."</string>
<string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Umožňuje aplikácii spustenie v režime nízkoúrovňového testu výrobcu a povolí úplný prístup k hardvéru telefónu. K dispozícii iba vtedy, keď je telefón spustený v režime testovania výrobcu."</string>
- <string name="permlab_setWallpaper" msgid="6627192333373465143">"nastaviť tapetu"</string>
+ <string name="permlab_setWallpaper" msgid="6627192333373465143">"nastavenie tapety"</string>
<string name="permdesc_setWallpaper" msgid="7373447920977624745">"Umožňuje aplikácii nastaviť tapetu systému."</string>
<string name="permlab_setWallpaperHints" msgid="3278608165977736538">"upraviť veľkosť tapety"</string>
<string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Umožňuje aplikácii nastaviť tipy pre veľkosť tapety systému."</string>
@@ -640,7 +614,7 @@
<string name="permdesc_changeTetherState" msgid="1524441344412319780">"Umožňuje aplikácii zmeniť stav sieťového pripojenia zdieľaného pomocou tetheringu."</string>
<string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"zmeniť nastavenie použitia údajov na pozadí"</string>
<string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Umožňuje aplikácii zmeniť nastavenie používania údajov na pozadí."</string>
- <string name="permlab_accessWifiState" msgid="5202012949247040011">"zobraziť pripojenia Wi-Fi"</string>
+ <string name="permlab_accessWifiState" msgid="5202012949247040011">"zobraziť pripojenia siete Wi-Fi"</string>
<string name="permdesc_accessWifiState" msgid="5002798077387803726">"Umožňuje aplikácii zobraziť informácie o sieťach Wi-Fi. Napríklad o tom, či je sieť Wi-Fi povolená alebo názvy pripojených zariadení Wi-Fi."</string>
<string name="permlab_changeWifiState" msgid="6550641188749128035">"pripojiť a odpojiť od siete Wi-Fi"</string>
<string name="permdesc_changeWifiState" msgid="7137950297386127533">"Umožňuje aplikácii pripojiť sa na prístupové body siete Wi-Fi, odpojiť sa od nich a meniť konfiguráciu zariadení pre siete Wi-Fi."</string>
@@ -658,25 +632,22 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Zmeniť stav siete WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Umožňuje aplikácii pripojiť tablet k sieťam WiMAX a odpojiť ho od nich."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Umožňuje aplikácii pripojiť telefón k sieťam WiMAX a odpojiť ho od nich."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"zadanie skóre sietí"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Umožňuje aplikácii hodnotiť siete a ovplyvňovať, ktoré siete by mal tablet preferovať."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Umožňuje aplikácii hodnotiť siete a ovplyvňovať, ktoré siete by mal telefón preferovať."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"párovať so zariadeniami Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Umožňuje aplikácii zobraziť informácie o konfigurácii Bluetooth na tablete. Taktiež jej umožňuje nadväzovať a akceptovať spojenia so spárovanými zariadeniami."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Umožňuje aplikácii zobraziť informácie o konfigurácii Bluetooth na telefóne. Taktiež jej umožňuje nadväzovať a akceptovať spojenia so spárovanými zariadeniami."</string>
- <string name="permlab_nfc" msgid="4423351274757876953">"ovládať technológiu NFC"</string>
- <string name="permdesc_nfc" msgid="7120611819401789907">"Umožňuje aplikácii komunikovať so značkami, kartami a čítačkami s podporou technológie NFC."</string>
- <string name="permlab_disableKeyguard" msgid="3598496301486439258">"deaktivácia zámky obrazovky"</string>
+ <string name="permlab_nfc" msgid="4423351274757876953">"ovládať technológiu Near Field Communication"</string>
+ <string name="permdesc_nfc" msgid="7120611819401789907">"Umožňuje aplikácii komunikovať so značkami, kartami a čítačkami s podporou technológie Near Field Communication (NFC)."</string>
+ <string name="permlab_disableKeyguard" msgid="3598496301486439258">"zakázať uzamknutie obrazovky"</string>
<string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Umožňuje aplikácii zakázať uzamknutie klávesnice a akékoľvek súvisiace zabezpečenie heslom. Príkladom je zakázanie uzamknutia klávesnice pri prichádzajúcom telefonickom hovore a jeho opätovné povolenie po skončení hovoru."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"čítať nastavenia synchronizácie"</string>
+ <string name="permlab_readSyncSettings" msgid="6201810008230503052">"čítanie nastavení synchronizácie"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Umožňuje aplikácii čítať nastavenia synchronizácie v účte. Môže napríklad určiť, či je s účtom synchronizovaná aplikácia Ľudia."</string>
- <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"zapnúť alebo vypnúť synchronizáciu"</string>
+ <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"prepínať nastavenie synchronizácie medzi hodnotou zapnuté a vypnuté"</string>
<string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Umožňuje aplikácii upraviť nastavenia synchronizácie v účte. Pomocou tohto povolenia je možné napríklad povoliť synchronizáciu aplikácie Ľudia s účtom."</string>
<string name="permlab_readSyncStats" msgid="7396577451360202448">"čítanie štatistických údajov o synchronizácii"</string>
<string name="permdesc_readSyncStats" msgid="1510143761757606156">"Umožňuje aplikácii čítať štatistické informácie o synchronizácii v účte vrátane histórie uskutočnených synchronizácií a informácií o množstve synchronizovaných údajov."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"čítať odoberané informačné kanály"</string>
+ <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"čítanie zdrojov prihlásených na odber"</string>
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Umožňuje aplikácii získať podrobnosti o aktuálne synchronizovaných informačných kanáloch."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"zapisovať odoberané informačné kanály"</string>
+ <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"zápis odoberaných zdrojov"</string>
<string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Umožňuje aplikácii upraviť vaše aktuálne synchronizované informačné kanály. Škodlivé aplikácie môžu synchronizované informačné kanály zmeniť."</string>
<string name="permlab_readDictionary" msgid="4107101525746035718">"čítať výrazy pridané do slovníka"</string>
<string name="permdesc_readDictionary" msgid="659614600338904243">"Umožňuje aplikácii čítať všetky slová, názvy a frázy, ktoré mohol používateľ uložiť do svojho slovníka."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikácii načítať, zobrazovať a mazať upozornenia vrátane tých, ktoré boli uverejnené inými aplikáciami."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"naviazanie sa na službu na počúvanie upozornení"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Umožňuje držiteľovi naviazať sa na najvyššiu úroveň služby na počúvanie upozornení. Bežné aplikácie by toto nastavenie nemali nikdy požadovať."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"viazanie na službu poskytovateľa podmienky"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby poskytovateľa podmienky. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"vyvolanie aplikácie pre konfiguráciu poskytnutú operátorom"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Umožňuje držiteľovi vyvolať aplikáciu pre konfiguráciu poskytnutú operátorom. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"zachytávať informácie o stave siete"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Umožňuje aplikácii zachytávať informácie o stave siete. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"zmeniť kalibráciu vstupného zariadenia"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Umožňuje aplikácii upraviť parametre kalibrácie dotykovej obrazovky. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"prístup k certifikátom DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Umožňuje aplikácii vydávať a používať certifikáty DRM. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nastaviť pravidlá pre heslo"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Ovládanie dĺžky hesiel na odomknutie obrazovky a v nich používané znaky."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Sledovať pokusy o odomknutie obrazovky"</string>
@@ -738,7 +703,7 @@
<string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Bez predchádzajúceho upozornenia zmazať všetky údaje tým, že sa obnovia továrenské nastavenia telefónu."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nastaviť globálny server proxy zariadenia"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Vyberte globálny server proxy, ktorý sa bude používať po aktivácii pravidiel. Platný globálny server proxy nastavuje iba prvý správca zariadenia."</string>
- <string name="policylab_expirePassword" msgid="885279151847254056">"Nastaviť vypršanie hesla zámky"</string>
+ <string name="policylab_expirePassword" msgid="885279151847254056">"Nastav. koniec platnosti hesla"</string>
<string name="policydesc_expirePassword" msgid="1729725226314691591">"Nastavte, ako často sa musí zmeniť heslo na uzamknutie obrazovky."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Nastaviť šifr. ukl. priestoru"</string>
<string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Vyžadovať šifrovanie uložených údajov aplikácií."</string>
@@ -1181,7 +1146,7 @@
<string name="anr_application_process" msgid="8941757607340481057">"Aplikácia <xliff:g id="APPLICATION">%1$s</xliff:g> neodpovedá. Chcete ju zavrieť?"</string>
<string name="anr_process" msgid="6513209874880517125">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> neodpovedá. \n\nChcete ho zavrieť?"</string>
<string name="force_close" msgid="8346072094521265605">"OK"</string>
- <string name="report" msgid="4060218260984795706">"Nahlásiť"</string>
+ <string name="report" msgid="4060218260984795706">"Prehľad"</string>
<string name="wait" msgid="7147118217226317732">"Čakajte"</string>
<string name="webpage_unresponsive" msgid="3272758351138122503">"Stránka nereaguje.\n\nChcete ju zavrieť?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Presmerovaná aplikácia"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Umožňuje aplikácii získať prístup k ukladaciemu priestoru zabezpečenému technológiou keyguard."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Ovládanie zobrazenia alebo skrytia technológie keyguard"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Umožňuje aplikácii ovládať technológiu keyguard."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Reagovanie na zmeny stavu dôveryhodnosti."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Umožňuje aplikácii reagovať na zmeny stavu dôveryhodnosti."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Viazanie sa na službu zástupcu dôveryhodnosti"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Umožňuje aplikácii viazať sa na službu zástupcu dôveryhodnosti."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interakcia so systémom aktualizácií a obnovenia"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Umožňuje aplikácii interakciu so systémom obnovenia a s aktualizáciami systému."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Ovládacie prvky lupy zobrazíte dvojitým dotknutím"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Zmeniť tapetu"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Aplikácia na počúvanie upozornení"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Poskytovateľ podmienky"</string>
<string name="vpn_title" msgid="19615213552042827">"Sieť VPN je aktivovaná"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Aplikáciu <xliff:g id="APP">%s</xliff:g> aktivovala sieť VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dotykom môžete spravovať sieť."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index dfa767b..1f1ab78 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"Št. dni: <xliff:g id="DAYS">%1$d</xliff:g>"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> dan <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> dan <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> h"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> s"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> s"</string>
<string name="untitled" msgid="4638956954852782576">"<Brez naslova>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinhronizacija"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Preveč izbrisov vsebine <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Pomnilnik tabličnega računalnika je poln. Izbrišite nekaj datotek, da sprostite prostor."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Shramba ure je polna. Izbrišite nekaj datotek, da sprostite prostor."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Pomnilnik telefona je poln. Izbrišite nekaj datotek, da sprostite prostor."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Omrežje je lahko nadzorovano"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Neznana tretja oseba"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Vklopi zvonjenje"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Se zaustavlja ..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablični računalnik se bo zaustavil."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ura se bo izklopila."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefon bo zaustavljen."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Ali želite izklopiti napravo?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Vnovičen zagon v varnem načinu"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Način za letalo"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Način za letalo je VKLOPLJEN"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Način za letalo je IZKLOPLJEN"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Nastavitve"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Plačljive storitve"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Dovolite stvari, za katere bo morda treba plačati."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vaša sporočila"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"odstranjevanje bližnjic"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Aplikaciji omogoča odstranjevanje bližnjic z začetnega zaslona brez posredovanja uporabnika."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"preusmeritev odhodnih klicev"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Aplikaciji dovoli ogled klicane številke pri odhodnem klicu in ji omogoča preusmeritev klica na drugo številko ali prekinitev klica."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Aplikaciji omogoča, da obdela odhodne klice in spreminja klicne številke. S tem lahko aplikacija nadzira, preusmerja ali preprečuje odhodne klice."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"prejemanje sporočil (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Aplikaciji omogoča prejemanje in obdelavo SMS-ov. S tem lahko aplikacija nadzoruje ali izbriše sporočila, poslana v napravo, ne da bi vam jih pokazala."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"prejemanje sporočil (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Programu omogoča dostop do vsebine aktivnega okna. Zlonamerni programi lahko dobijo vso vsebino okna in pregledajo njeno besedilo razen gesel."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"začasno omogoči pripomočke za ljudi s posebnimi potrebami"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Aplikaciji omogoča, da v napravi začasno omogoči pripomočke za ljudi s posebnimi potrebami. Zlonamerne aplikacije jih lahko omogočijo brez soglasja uporabnika."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"pridobivanje žetona okna"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Aplikaciji dovoli, da pridobi žeton okna. Zlonamerne aplikacije lahko z oknom aplikacije vzpostavijo stik brez pooblastila in se lažno predstavljajo kot sistem."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"pridobivanje statističnih podatkov o okvirjih"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Aplikaciji dovoli, da zbira statistične podatke o okvirjih. Zlonamerne aplikacije lahko vidijo statistične podatke o okvirjih oken iz drugih aplikacij."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"prenos podatkov o oknih"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Omogoča, da aplikacija iz upravitelja oken pridobiva podatke o oknih. Zlonamerne aplikacije lahko pridobivajo podatke, namenjene za notranjo uporabo v sistemu."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtriranje dogodkov"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Omogoča, da aplikacija registrira vhodni filter, ki pred razpošiljanjem filtrira tok vseh uporabniških dogodkov. Zlonamerne aplikacije lahko nadzirajo uporabniški vmesnik sistema brez posega uporabnika."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"povečevanje zaslona"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Omogoča aplikaciji povečevanje vsebine zaslona. Zlonamerne aplikacije lahko preoblikujejo vsebino zaslona tako, da je naprava neuporabna."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"delna zaustavitev"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Upravitelja dejavnosti preklopi v stanje za zaustavitev. Ne izvede celotne zaustavitve."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"preprečevanje preklopa programov"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Programu omogoča oddajo obvestila o prejetih sporočilih SMS. Zlonamerni programi lahko to uporabijo za ponarejanje dohodnih SMS-ov."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"pošiljanje oddaje, prejete s potisnim sporočilom WAP"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Programu omogoča oddajo obvestila, da je bilo potisno sporočilo WAP prejeto. Zlonamerni programi lahko to uporabijo za ponarejanje potrdila o prejemu sporočila MMS ali za neopazno menjavo vsebine poljubne spletne strani z zlonamernimi različicami."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"pošiljanje oddaj o ocenjevanju omrežij"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Aplikaciji dovoli oddajo obvestila, da je treba omrežja oceniti. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"omejevanje števila izvajajočih se procesov"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Programu omogoča nadzor največjega števila postopkov, ki se bodo izvajali. Tega nikoli ni treba uporabiti za navadne programe."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"vsiljeno zapiranje aplikacij v ozadju"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Lastniku omogoča povezovanje z vmesnikom storitve navideznega zasebnega omrežja najvišje ravni. Ne uporabljajte za navadne programe."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"povezovanje z ozadjem"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Imetniku omogoča povezavo z vmesnikom ozadja najvišje ravni. Tega nikoli ni treba uporabiti za navadne programe."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"povezovanje z glasovnim interaktorjem"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Imetniku omogoča povezovanje z vmesnikom storitve glasovne interakcije najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"povezava z oddaljenim prikazom"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Imetniku omogoča povezovanje z vmesnikom oddaljenega prikaza najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"poveži s storitvijo pripomočka"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lastniku omogoča povezovanje z vmesnikom storitve pripomočka najvišje ravni. Tega ni treba nikoli uporabiti za navadne programe."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"Povezava s storitvijo ponudnika poti"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Omogoča imetniku, da se povezuje z registriranimi ponudniki poti. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s skrbnikom naprave"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Omogoča lastniku, da pošlje namere skrbniku naprave. Nikoli se ne uporablja za navadne programe."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"povezava s TV-vhodom"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Imetniku omogoča povezovanje z vmesnikom TV-vhoda najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"dodajanje ali odstranjevanje skrbnikov naprave"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Imetniku omogoča, da doda ali odstrani aktivne skrbnike naprave. Normalne aplikacije tega načeloma ne potrebujejo."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"spreminjanje usmerjenosti zaslona"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Programu omogoča, da uporabi kateri koli dekodirnik večpredstavnosti za predvajanje."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"upravljanje preverjenih poverilnic"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Aplikaciji dovoli nameščanje in odstranjevanje potrdil overitelja potrdil kot preverjenih poverilnic."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"izvajanje aplikacije ob nedejavnosti"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"To dovoljenje sistemu Android omogoča, da izvaja aplikacijo v ozadju, ko naprava ni v uporabi."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"vezanje na nedejavne storitve"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"To dovoljenje dovoli sistemu Android vezanje nedejavnih storitev aplikacije."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"branje/pisanje v sredstva, ki so v lasti skupine za diagnostiko"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Programu omogoča branje in pisanje na poljuben vir, ki je v lasti skupine za diagnostiko; na primer datoteke v mapi /dev. To lahko vpliva na stabilnost in varnost sistema. To naj uporablja SAMO izdelovalec ali operater za diagnostiko, specifično za strojno opremo."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"omogočanje ali onemogočanje komponent programa"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Aplikaciji omogoča branje osebnih podatkov v profilu, ki so shranjeni v napravi, na primer ime in podatki za stik. To pomeni, da vas lahko aplikacija prepozna in vaše podatke v profilu pošlje drugim."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"spreminj. vaše osebne vizitke"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Aplikaciji omogoča spreminjanje ali dodajanje osebnih podatkov v profilu, ki so shranjeni v napravi, na primer ime in podatki za stik. To pomeni, da vas lahko aplikacija prepozna in vaše podatke v profilu pošlje drugim."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"tipala telesnih funkcij (npr. merilniki srčnega utripa)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Aplikaciji dovoli dostop do podatkov tipal, ki jih uporabljate za merjenje procesov v telesu, kot je srčni utrip."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"branje vašega družabnega toka"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Aplikaciji omogoča dostop do vaših objav in objav vaših prijateljev v družabnih omrežjih ter njihovo sinhronizacijo. Previdno pri objavljanju informacij – aplikacija lahko s tem bere komunikacijo med vami in prijatelji v družabnih omrežjih, ne glede na zasebnost. Opomba: Tega dovoljenja ni mogoče uveljaviti v vseh družabnih omrežjih."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"pisanje v vaš družabni tok"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Programu omogoča nadziranje telefonskih funkcij naprave. Program lahko s tem dovoljenjem preklaplja omrežja, vklopi ali izklopi radio v telefonu, ne da bi vas obvestil."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"branje stanja in identitete telefona"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Aplikaciji omogoča dostop do funkcij telefona v napravi. S tem dovoljenjem lahko aplikacija določi telefonsko številko in ID-je naprave, določi lahko tudi, ali je klic aktiven, in oddaljeno številko, s katero je klic povezan."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"branje natančnih stanj telefona"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Aplikaciji dovoli dostop do natančnih stanj telefona. To dovoljenje aplikaciji omogoča ugotoviti pravo stanje klica; ali je klic aktiven ali v ozadju; neuspele klice; natančno stanje podatkovne povezave in neuspele podatkovne povezave."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"preprečitev prehoda tabličnega računalnika v stanje pripravljenosti"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"preprečevanje prehoda v stanje pripravljenosti telefona"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Omogoča, da program prepreči prehod tabličnega računalnika v stanje pripravljenosti."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Sprememba stanja omrežja WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Aplikaciji omogoča, da vzpostavi povezavo med tabličnim računalnikom in omrežjem WiMAX ter jo prekine."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Aplikaciji omogoča, da vzpostavi povezavo med telefonom in omrežjem WiMAX ter jo prekine."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ocenjevanje omrežij"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Aplikaciji dovoli, da omrežja razvršča in vpliva na to, katera naj tablični računalnik prednostno izbere."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Aplikaciji dovoli, da omrežja razvršča in vpliva na to, katera naj telefon prednostno izbere."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"seznanitev z napravami Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Aplikaciji omogoča ogled konfiguracije Bluetootha tabličnega računalnika ter vzpostavljanje in sprejemanje povezave s seznanjenimi napravami."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Aplikaciji omogoča ogled konfiguracije Bluetootha telefona ter ustvarjanje in sprejemanje povezave s seznanjenimi napravami."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Dovoli aplikaciji, da prenese, razišče in izbriše obvestila, tudi tista, ki so jih objavile druge aplikacije."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"poveži se s storitvijo poslušalca obvestil"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Lastniku omogoča povezovanje z vmesnikom storitve poslušalca obvestil najvišje ravni. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"povezovanje s storitvijo ponudnika pogojev"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Imetniku omogoča povezovanje z vmesnikom storitve ponudnika pogojev najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"sprožitev operaterjeve aplikacije za konfiguracijo"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lastniku omogoča sproženje operaterjeve aplikacije za konfiguracijo. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"spremljanje razmer v omrežju"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Aplikaciji omogoča spremljanje razmer v omrežju. Pri navadnih aplikacijah to ne bi smelo biti potrebno."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"sprememba umerjanja vhodne naprave"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Aplikaciji dovoli spreminjanje parametrov za umerjanje zaslona na dotik. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"dostop do potrdil za upravljanje digitalnih pravic"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Aplikaciji omogoča pripravo in uporabo potrdil za upravljanje digitalnih pravic. To naj ne bi bilo nikoli potrebno za običajne aplikacije."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavitev pravil za geslo"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Nadzor nad dolžino in znaki, ki so dovoljeni v geslih za odklepanje zaslona."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"nadzor nad poskusi odklepanja zaslona"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Aplikaciji omogoča dostop do varne shrambe Keyguard."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Nadzira prikaz in skrivanje zaklepanja tipkovnice"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Aplikaciji omogoča nadzor zaklepanja tipkovnice."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Spremljanje sprememb stanja zaupanja."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Aplikaciji dovoli spremljanje sprememb stanja zaupanja."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Povezovanje s storitvijo posrednikov zaupanja"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Aplikaciji dovoli povezovanje s storitvijo posrednikov zaupanja."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Uporaba sistema za posodobitev in obnovitev"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Aplikaciji dovoli uporabo sistema za obnovitev in posodobitev sistema."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dvakrat se dotaknite za nadzor povečave/pomanjšave"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Ozadje"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Spreminjanje ozadja"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Poslušalec obvestil"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Ponudnik pogojev"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN je aktiviral program <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dotaknite se, če želite upravljati omrežje."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index fb65c02..310de65 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> дана"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> дан <xliff:g id="HOURS">%2$d</xliff:g> с"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> дан <xliff:g id="HOURS">%2$d</xliff:g> с"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> с"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> с <xliff:g id="MINUTES">%2$d</xliff:g> мин"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> с <xliff:g id="MINUTES">%2$d</xliff:g> мин"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> мин"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> мин <xliff:g id="SECONDS">%2$d</xliff:g> сек"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> мин <xliff:g id="SECONDS">%2$d</xliff:g> сек"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> сек"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> сек"</string>
<string name="untitled" msgid="4638956954852782576">"<Без наслова>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синхронизација"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Превише <xliff:g id="CONTENT_TYPE">%s</xliff:g> избрисаних ставки."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Меморија таблета је пуна! Избришите неке датотеке да бисте ослободили простор."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Меморија сата је пуна. Избришите неке датотеке да бисте ослободили простор."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Складиште телефона је пуно! Избришите неке датотеке како бисте ослободили простор."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мрежа се можда надгледа"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Од стране непознате треће стране"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Звоно је укључено"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Искључивање…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Таблет ће се искључити."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Сат ће се угасити."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Телефон ће се искључити."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Да ли желите да искључите телефон?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Поново покрени систем у безбедном режиму"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Режим рада у авиону"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Режим рада у авиону је УКЉУЧЕН"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Режим рада у авиону је ИСКЉУЧЕН"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Подешавања"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Услуге које се плаћају"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Покреће радње које могу да се плаћају."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Поруке"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"деинсталирање пречица"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Омогућава апликацији да уклања пречице са почетног екрана без интервенције корисника."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"преусмеравање одлазних позива"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Дозвољава апликацији да види који број се бира при одлазном позиву уз опцију да преусмери позив на други број или га потпуно прекине."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Дозвољава апликацији да обрађује одлазне позиве и промени број који се бира. Ова дозвола омогућава апликацији да надгледа, преусмерава или спречава одлазне позиве."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"пријем текстуалних порука (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Дозвољава апликацији да прима и обрађује SMS поруке. То значи да апликација може да надгледа или брише поруке које се шаљу уређају, а да вам их не прикаже."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"пријем текстуалних порука (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Дозвољава апликацији да преузме садржај активног прозора. Злонамерне апликације могу да преузму цео садржај прозора и прегледају целокупан текст, осим лозинки."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"привремено омогућавање приступачности"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Дозвољава апликацији да привремено омогући приступачност на уређају. Злонамерне апликације могу да омогуће приступачност без дозволе корисника."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"преузимање токена прозора"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Дозвољава апликацији да преузима токен прозора. Злонамерне апликације могу да ступе у неовлашћену интеракцију са прозором апликације лажно се представљајући као систем."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"преузимње статистике оквира"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Дозвољава апликацији да прикупља статистику о оквиру. Злонамерне апликације могу да прате статистику оквира прозора из других апликација."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"преузимање информација о прозорима"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Омогућава апликацији да преузме информације о прозорима од менаџера прозора. Злонамерне апликације могу да преузму информације које су намењене за интерну употребу система."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"филтрирање догађаја"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Омогућава апликацији да региструје филтер улазног садржаја који филтрира стрим свих догађаја корисника пре њиховог слања. Злонамерна апликација може да контролише кориснички интерфејс система без интервенције корисника."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"увеличавање екрана"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Дозвољава апликацији да увеличава садржај екрана. Злонамерне апликације могу да промене садржај екрана до те мере да уређај постаје неупотребљив."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"делимично искључивање"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Ставља менаџера активности у стање искључивања. Не искључује га у потпуности."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"спречавање пребацивања са једне апликације на другу"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Дозвољава апликацији да емитује обавештење да је SMS порука примљена. Злонамерне апликације на тај начин могу да фалсификују долазне SMS поруке."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"слање примљених PUSH емитовања преко WAP-а"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Дозвољава апликацији да емитује обавештење да је примљена PUSH порука преко WAP-а. Злонамерне апликације то могу да искористе да фалсификују пријем MMS порука или да кришом замене садржај било које веб-странице уносом злонамерног садржаја."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"шаљи обавештења о тестирању мрежа"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Омогућава апликацији да емитује обавештење да је потребно тестирање мрежа. Никада није потребно за стандардне апликације."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"ограничење броја покренутих процеса"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Дозвољава апликацији да управља максималним бројем процеса који ће моћи да се покрену. Никада није потребна уобичајеним апликацијама."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"принудно затварање позадинских апликација"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дозвољава власнику да се повеже са интерфејсом VPN услуге највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"обавезивање на позадину"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дозвољава власнику да се повеже са интерфејсом позадине највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"повежи са гласовним интерактором"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Дозвољава власнику да се повеже са интерфејсом највишег нивоа услуге гласовне интеракције. Не би требало никада да буде потребно за уобичајене апликације."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"повезивање са удаљеним екраном"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Дозвољава власнику да се повеже са интерфејсом удаљеног екрана највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"обавезивање на услугу виџета"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозвољава власнику да се обавеже на интерфејс услуге виџета највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"повежи са услугом добављача путања"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Дозвољава власнику да се повеже са добављачима путања. Никада не би требало да буде потребно за обичне апликације."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"интеракција са администратором уређаја"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Омогућава да власник шаље своје намере администратору уређаја. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"повезивање са ТВ улазом"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Омогућава апликацији да користи било који инсталирани декодер медија за декодирање за репродукцију."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"управљање поузданим акредитивима"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Дозвољава апликацији да инсталира и деинсталира CA сертификате као поуздане акредитиве."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"покреће апликације током неактивности"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ова дозвола омогућава систему Android да покреће апликације у позадини док се уређај не користи."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"повезивање са неактивним услугама"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Ова дозвола дозвољава систему Android да се веже за неактивне услуге апликације."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"читање ресурса у власништву дијагностике и уписивање података у њих"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Дозвољава апликацији да чита и уписује податке у било који ресурс у власништву групе за дијагностиковање, на пример, датотеке у директоријуму /dev. То може да угрози стабилност и безбедност система и треба да је користе САМО произвођач или оператер у сврхе дијагностиковањa хардвера."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"омогућавање или онемогућавање компоненти апликације"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Дозвољава апликацији да чита личне информације о профилу ускладиштене на уређају, као што су име и контакт информације. То значи да апликација може да вас идентификује и шаље другима информације о профилу."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"измена ваше контакт картице"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Дозвољава апликацији да мења или додаје нове личне информације о профилу ускладиштене на уређају, као што су име и контакт информације. То значи да апликација може да вас идентификује и шаље другима информације о профилу."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"телесни сензори (нпр. срчани монитор)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Дозвољава апликацији да приступа подацима сензора које користите за мерење телесних функција, као што је срчани пулс."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"читање друштвеног стрима"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Дозвољава апликацији да приступа вашим друштвеним ажурирањима и друштвеним ажурирањима пријатеља и да их синхронизује. Будите опрезни када делите информације – ово омогућава апликацији да чита преписке између вас и пријатеља на друштвеним мрежама, без обзира на поверљивост. Напомена: Ова дозвола се можда не примењује на све друштвене мреже."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"писање у друштвени стрим"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Дозвољава апликацији да управља функцијама телефона на уређају. Апликација са овом дозволом може да прелази са једне мреже на другу и да без обавештења укључује и искључује радио телефона и сличне функције."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"читање статуса и идентитета телефона"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Дозвољава апликацији да приступа функцијама телефона на уређају. Ова дозвола омогућава апликацији да утврди број телефона и ИД-ове уређаја, затим да ли је позив активан, као и број даљинског уређаја са којим је успостављен позив."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"читај прецизне статусе телефона"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Омогућава апликацији да приступа прецизним статусима телефона. Ова дозвола омогућава апликацији да утврди стварни статус позива, да ли је позив активан или у позадини, неуспеле позиве, прецизан статус везе за пренос података и неуспела успостављања везе за пренос података."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"спречавање преласка таблета у стање спавања"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"спречавање преласка телефона у стање спавања"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дозвољава апликацији да спречи таблет да пређе у стање спавања."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Промени WiMAX статус"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Дозвољава апликацији да повезује таблет са WiMAX мрежама и прекида везе са њима."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Дозвољава апликацији да повезује телефон са WiMAX мрежама и прекида везе са њима."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"тестирај мреже"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Омогућава апликацији да рангира мреже и утиче на то које су мреже примарне на таблету."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Омогућава апликацији да рангира мреже и утиче на то које су мреже примарне на телефону."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"упаривање са Bluetooth уређајима"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Дозвољава апликацији да прегледа конфигурацију Bluetooth-а на таблету, као и да успоставља и прихвата везе са упареним уређајима."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Дозвољава апликацији да прегледа конфигурацију Bluetooth-а на телефону, као и да успоставља и прихвата везе са упареним уређајима."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозвољава апликацији да преузима, испитује и брише обавештења, укључујући она која постављају друге апликације."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"повезивање са услугом монитора обавештења"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозвољава власнику да се повеже са интерфејсом услуге монитора обавештења највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"повежи са услугом добављача услова"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Дозвољава власнику да се повеже са интерфејсом највишег нивоа услуге добављача услова. Не би требало никада да буде потребно за уобичајене апликације."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"позивање апликације са конфигурацијом коју одређује оператер"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозвољава власнику да позива апликацију са конфигурацијом коју одређује оператер. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"праћење података о условима на мрежи"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Дозвољава апликацији да прати податке о условима на мрежи. Не би никада требало да буде потребно за нормалне апликације."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"промени калибрацију улазног уређаја"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Дозвољава апликацији да модификује параметре калибрације додирног екрана. Не би требало да буде потребно за нормалне апликације."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"приступ DRM сертификатима"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Дозвољава апликацији да додељује и користи DRM сертификате. Никада не би требало да се користи за уобичајене апликације."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Подешавање правила за лозинку"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролишите дужину и знакове дозвољене у лозинкама за откључавање екрана."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Надгледање покушаја откључавања екрана"</string>
@@ -917,7 +882,7 @@
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Откључавање налога"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Превише покушаја уноса шаблона"</string>
<string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Да бисте откључали, пријавите се помоћу Google налога."</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Корисничко име (имејл адреса)"</string>
+ <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Корисничко име (адреса е-поште)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Лозинка"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Пријави ме"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Неважеће корисничко име или лозинка."</string>
@@ -967,7 +932,7 @@
<string name="js_dialog_title" msgid="1987483977834603872">"На страници на адреси „<xliff:g id="TITLE">%s</xliff:g>“ пише следеће:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
<string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Потврда навигације"</string>
- <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Напусти ову страницу"</string>
+ <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Затвори ову страницу"</string>
<string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Остани на овој страници"</string>
<string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nДа ли стварно желите да напустите ову страницу?"</string>
<string name="save_password_label" msgid="6860261758665825069">"Потврда"</string>
@@ -1271,7 +1236,7 @@
<string name="sim_removed_message" msgid="2333164559970958645">"Мобилна мрежа неће бити доступна док не покренете систем поново уз уметање важеће SIM картице."</string>
<string name="sim_done_button" msgid="827949989369963775">"Готово"</string>
<string name="sim_added_title" msgid="3719670512889674693">"SIM картица је додата"</string>
- <string name="sim_added_message" msgid="6599945301141050216">"Рестартујте уређај да бисте могли да приступите мобилној мрежи."</string>
+ <string name="sim_added_message" msgid="6599945301141050216">"Поново покрените уређај да бисте могли да приступите мобилној мрежи."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Поново покрени"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Подешавање времена"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Подешавање датума"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Дозвољава апликацији да приступа безбедној меморији заштићеној шифром."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Контролиши приказивање и скривање заштите шифром"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Дозвољава апликацији да контролише заштиту шифром."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Праћење промена Trust стања."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Дозвољава апликацији да прати промене Trust стања."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Везивање за услугу Trust agents"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Дозвољава апликацији да се веже за услугу Trust agents."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Интеракција са системом за ажурирање и опоравак"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Дозвољава апликацији да ступа у интеракцију са системом за опоравак и ажурирањима система."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Додирните двапут да бисте контролисали зум"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Позадина"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Промена позадине"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Монитор обавештења"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Добављач услова"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN је активиран"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Апликација <xliff:g id="APP">%s</xliff:g> је активирала VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Додирните да бисте управљали мрежом."</string>
@@ -1575,7 +1535,7 @@
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN кодови се не подударају"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Превише покушаја уноса шаблона"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Да бисте откључали, пријавите се помоћу Google налога."</string>
- <string name="kg_login_username_hint" msgid="5718534272070920364">"Корисничко име (имејл адреса)"</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Корисничко име (адреса е-поште)"</string>
<string name="kg_login_password_hint" msgid="9057289103827298549">"Лозинка"</string>
<string name="kg_login_submit_button" msgid="5355904582674054702">"Пријави ме"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Неважеће корисничко име или лозинка."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index ea713a6..cdc1ffb 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> dagar"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> dag <xliff:g id="HOURS">%2$d</xliff:g> tim"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> dag <xliff:g id="HOURS">%2$d</xliff:g> tim"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> timmar"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> tim <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> tim <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> minuter"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> sek"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> sek"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sekunder"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sekund"</string>
<string name="untitled" msgid="4638956954852782576">"<Okänd>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkronisera"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"För många <xliff:g id="CONTENT_TYPE">%s</xliff:g>-borttagningar."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Pekdatorns lagringsutrymme är fullt. Ta bort några filer för att frigöra utrymme."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Klockans lagringsutrymme är fullt. Ta bort några filer för att frigöra utrymme."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Mobilens lagringsutrymme är fullt. Ta bort några filer för att frigöra utrymme."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Nätverket kan vara övervakat"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Av en okänd tredje part"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Ringsignal på"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Avslutar…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Din surfplatta stängs av."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Klockan stängs av."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Din telefon stängs av."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Vill du stänga av?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Starta om i felsäkert läge"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flygplansläge"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flygplansläge är AKTIVERAT"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flygplansläge är INAKTIVERAT"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Inställningar"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Tjänster som kostar pengar"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Göra saker som kan kosta pengar."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Dina meddelanden"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"avinstallera genvägar"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Tillåter att appen tar bort genvägar på startskärmen utan åtgärd från användaren."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"omdirigera utgående samtal"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Tillåter att appen ser numret du slår under ett utgående samtal och har möjlighet att koppla samtalet till ett annat nummer eller avbryta samtalet helt."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Tillåter att appen hanterar utgående samtal och ändrar numret som ska ringas upp. Med den här behörigheten kan appen övervaka, omdirigera eller förhindra utgående samtal."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"ta emot textmeddelanden (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Tillåter att appen tar emot och hanterar SMS. Detta innebär att appen kan övervaka eller ta bort meddelanden som skickats till enheten utan att visa dem för dig."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"ta emot textmeddelanden (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Tillåter att appen hämtar innehållet i det aktiva fönstret. Skadliga appar kan hämta allt innehåll i fönstret och läsa all text utom lösenord."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"aktivera tillgänglighetsläget tillfälligt"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Tillåt att en app tillfälligt aktiverar tillgänglighetsläget på enheten. Skadliga appar kan aktivera tillgänglighetsläget utan användarens medgivande."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"hämta fönstrets token"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Appen tillåts hämta fönstrets token. Skadliga appar kan interagera med appens fönster på ett otillåtet sätt och efterlikna systemet."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"hämta ramstatistik"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Appen tillåts samla in ramstatistik. Skadliga appar kan registrera statistik om ramar i andra appars fönster."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"hämta information om fönster"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Tillåter att appen hämtar information om fönstren från fönsterhanteraren. Skadliga appar kan hämta information som är avsedd för användning i det interna systemet."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"filtrera händelser"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Tillåter att appen registrerar indatafilter som filtrerar flödet med användarhändelser innan de skickas. Skadliga appar kan styra systemets användargränssnitt utan att användaren gör något."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"förstora skärmen"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Tillåter att en app förstorar innehållet på en skärm. Skadliga appar kan förvandla skärminnehållet på ett sätt som gör att enheten blir oanvändbar."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"avsluta delvis"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Sätter aktivitetshanteraren i avstängningsläge. Utför inte en fullständig avstängning."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"förhindrar programbyten"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Tillåter att appen sänder ut en avisering när SMS tas emot. Skadliga appar kan använda detta för att förfalska inkommande SMS."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"skicka WAP-PUSH-mottagen sändning"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Tillåter att appen skickar ett meddelande om att ett WAP PUSH-meddelande har tagits emot. Skadliga appar kan använda detta för att förfalska mottagning av MMS eller för att obemärkt byta ut innehållet på en webbsida mot skadligt innehåll."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"skicka betyg som nätverk skickar"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Tillåter att appen skickar ett meddelande om att nätverket måste betygsättas. Ska inte behövas för vanliga appar."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"begränsa antalet processer som körs"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Tillåter att appen styr högsta antalet processer som körs. Behövs inte för vanliga appar."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"tvinga bakgrundsappar att avslutas"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en VPN-tjänst. Ska inte behövas för vanliga appar."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"binda till en bakgrund"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Innehavaren kan binda till den översta nivåns gränssnitt för en bakgrund. Ska inte behövas för vanliga appar."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"bind till en röstkomponent"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en rösttjänst. Ska inte behövas för vanliga appar."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind till en fjärrskärm"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en fjärrskärm. Ska inte behövas för vanliga appar."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind till en widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en widget. Ska inte behövas för vanliga appar."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bind till en ruttleverantörstjänst"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Tillåter att innehavaren binds till en registrerad ruttleverantör. Detta ska inte behövas för vanliga appar."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"arbeta med en enhetsadministratör"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Tillåter att innehavaren skickar avsikter till en enhetsadministratör. Vanliga appar behöver aldrig göra detta."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"binda till en tv-insignal"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Tillåter att appen använder installerade medieavkodare för att avkoda media för uppspelning."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"hantera betrodda uppgifter"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Tillåter att appen installerar och avinstallerar CA-certifikat som betrodda uppgifter."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"kör appen när enheten är inaktiv"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Med den här behörigheten tillåts Android-systemet att köra appen i bakgrunden när enheten inte används."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"knyt till inaktiva tjänster"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Med den här behörigheten kan Android-systemet bindas till en apps inaktiva tjänster."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"läsa/skriva till resurser som ägs av diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Tillåter att appen läser och skriver till en resurs som ägs av diag-gruppen, till exempel filer i /dev. Detta kan eventuellt påverka systemets stabilitet och säkerhet. Detta bör ENDAST användas av tillverkaren eller operatören för maskinvaruspecifik diagnostik."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivera eller inaktivera appkomponenter"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Tillåter att appen läser personliga profiluppgifter som sparats på din enhet, t.ex. ditt namn och kontaktuppgifter. Det innebär att appen kan identifiera dig och skicka profiluppgifter till andra."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"ändra ditt eget kontaktkort"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Tillåter att appen ändrar eller lägger till personliga profiluppgifter som sparats på din enhet, till exempel ditt namn och dina kontaktuppgifter. Det innebär att appen kan identifiera dig och skicka profiluppgifter till andra."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"kroppssens. (för hjärtat m.m.)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Tillåter att appen får åtkomst till data från sensorer som används för att mäta vad som sker inuti kroppen, till exempel hjärtfrekvens."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"läs mitt sociala flöde"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Tillåter att appen kommer åt och synkroniserar sociala uppdateringar från dig och dina vänner. Var försiktig när du delar information – med den här behörigheten tillåts appen att läsa kommunikation mellan dig och dina vänner på sociala nätverk oavsett sekretessnivå. Observera att den här behörigheten kanske inte är tillämplig på alla sociala nätverk."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"skriv till mitt sociala flöde"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Tillåter att appen styr enhetens telefonfunktioner. En app med den här behörigheten kan byta nätverk, aktivera/inaktivera mobilens radio och liknande utan att meddela dig."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"läsa telefonens status och identitet"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Tillåter att appen kommer åt enhetens telefonfunktioner. Med den här behörigheten tillåts appen att identifiera mobilens telefonnummer och enhets-ID, om ett samtal pågår och vilket nummer samtalet är kopplat till."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"läsa mobilens exakta status"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Tillåter att appen får tillgång till mobilens exakta status. Appen får behörighet att avgöra mobilens faktiska samtalsstatus, om samtalet är aktivt eller i bakgrunden, om samtal misslyckas, mobilens exakta dataanslutningsstatus och om dataanslutningar misslyckas."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"förhindra att surfplattan går in i viloläge"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"förhindra att telefonen sätts i viloläge"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Tillåter att appen förhindrar att surfplattan går in i viloläge."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"ändra WiMAX-status"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Tillåter att appen ansluter surfplattan till eller kopplar från WiMAX-nätverk."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Tillåter att appen ansluter mobilen till eller kopplar från WiMAX-nätverk."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"betygsätt nätverk"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Tillåter att appen betygsätter nätverk och påverkar vilka nätverk som ska användas i första hand av surfplattan."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Tillåter att appen betygsätter nätverk och påverkar vilka nätverk som ska användas i första hand av mobilen."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"koppla till Bluetooth-enheter"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Tillåter att appen kommer åt pekdatorns Bluetooth-konfiguration och upprättar och godkänner anslutningar till parkopplade enheter."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Tillåter att appen kommer åt mobilens Bluetooth-konfiguration och upprättar och godkänner anslutningar till parkopplade enheter."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillåter att appen hämtar, granskar och raderar meddelanden, även sådana som skickats av andra appar."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"binda till en meddelandelyssnare"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en meddelandelyssnare. Ska inte behövas för vanliga appar."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bind till en leverantörstjänst"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en leverantörstjänst. Ska inte behövas för vanliga appar."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"anropa konfigurationsappen från operatören"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Innehavaren tillåts att anropa konfigurationsappen från operatören. Ska inte behövas för vanliga appar."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"lyssna efter information om nätverksförhållanden"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Tillåter att appen lyssnar efter information om nätverksförhållanden. Vanliga appar bör aldrig behöva den här behörigheten."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"ändra kalibreringen för inmatningsenheten"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Tillåter att appen ändrar kalibreringsparametrarna för pekskärmen. Detta behövs aldrig för vanliga appar."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"tillgång till DRM-certifikat"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Tillåter att en app tillhandahåller och använder DRM-certifikat. Behövs inte för vanliga appar."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Ange lösenordsregler"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Bestäm hur många och vilka tecken som är tillåtna i skärmlåsets lösenord."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Övervaka försök att låsa upp skärmen"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Tillåter att en app får åtkomst till säkert keyguard-lagringsutrymme."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Kontrollera hur knapplåset visas och döljs"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Tillåter att en app kontrollerar knapplåsfunktionen."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Lyssna efter ändringar i betrodda agenters status."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Tillåter att en app lyssnar efter ändringar i den betrodda agentens status."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bind till en tjänst från en betrodd agent"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Tillåter att en app binds vid en tjänst från en betrodd agent."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interagera med uppdaterings- och återställningssystemet"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Tillåter att en app interagerar med systemuppdateringar och återställningssystemet."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Tryck två gånger för zoomkontroll"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Bakgrund"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ändra bakgrund"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Meddelandelyssnare"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Leverantör"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN är aktiverat"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveras av <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Tryck om du vill hantera nätverket."</string>
@@ -1501,7 +1461,7 @@
<string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Gränsen för data via Wi-Fi har överskridits"</string>
<string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> över angiven gräns."</string>
<string name="data_usage_restricted_title" msgid="5965157361036321914">"Bakgrundsdata är begränsade"</string>
- <string name="data_usage_restricted_body" msgid="6741521330997452990">"Tryck för att ta bort begränsning"</string>
+ <string name="data_usage_restricted_body" msgid="6741521330997452990">"Tryck för att radera begränsning"</string>
<string name="ssl_certificate" msgid="6510040486049237639">"Säkerhetscertifikat"</string>
<string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Certifikatet är giltigt."</string>
<string name="issued_to" msgid="454239480274921032">"Utfärdad till:"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 8c77050..e840e37 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"Siku <xliff:g id="DAYS">%1$d</xliff:g>"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"Siku <xliff:g id="DAYS">%1$d</xliff:g> saa <xliff:g id="HOURS">%2$d</xliff:g>"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"Siku <xliff:g id="DAYS">%1$d</xliff:g> saa <xliff:g id="HOURS">%2$d</xliff:g>"</string>
- <string name="durationHours" msgid="4266858287167358988">"Saa <xliff:g id="HOURS">%1$d</xliff:g>"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"Saa <xliff:g id="HOURS">%1$d</xliff:g> dak <xliff:g id="MINUTES">%2$d</xliff:g>"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"Saa <xliff:g id="HOURS">%1$d</xliff:g> dak <xliff:g id="MINUTES">%2$d</xliff:g>"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"Dakika <xliff:g id="MINUTES">%1$d</xliff:g>"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"Dak <xliff:g id="MINUTES">%1$d</xliff:g> sek <xliff:g id="SECONDS">%2$d</xliff:g>"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"Dak <xliff:g id="MINUTES">%1$d</xliff:g> sek <xliff:g id="SECONDS">%2$d</xliff:g>"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"Sekunde <xliff:g id="SECONDS">%1$d</xliff:g>"</string>
- <string name="durationSecond" msgid="985669622276420331">"Sekunde <xliff:g id="SECONDS">%1$d</xliff:g>"</string>
<string name="untitled" msgid="4638956954852782576">"<Haina jina>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -111,7 +100,7 @@
<string name="roamingText4" msgid="8808456682550796530">"Nje ya Jengo"</string>
<string name="roamingText5" msgid="7604063252850354350">"Urandaji - Mfumo unaopendelewa"</string>
<string name="roamingText6" msgid="2059440825782871513">"Uzururaji - Mfumo Unaopatikana"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Roaming - Alliance Partner"</string>
+ <string name="roamingText7" msgid="7112078724097233605">"Uzururaji - Mwenza wa Ushirikiamo"</string>
<string name="roamingText8" msgid="5989569778604089291">"Uzururaji - Mwenzi wa Thamani"</string>
<string name="roamingText9" msgid="7969296811355152491">"Uzururaji - Utendajikazi Kamili wa Huduma"</string>
<string name="roamingText10" msgid="3992906999815316417">"Uzururaji - Utendajikazi Nusi wa Huduma"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sawazisha"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Ufutaji mwingi sana <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Hifadhi ya kompyuta kibao imejaa. Futa baadhi ya faili ili kupata nafasi."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Hifadhi ya saa imejaa. Futa baadhi ya faili ili uweze kupata nafasi."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Hifadhi ya simu imejaa. Futa baadhi ya faili ili uweze kupata nafasi."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Huenda mtandao unafuatiliwa"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Na mtu mwingine asiyejulikana"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Programu ya milio imewashwa"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Inafunga..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Kompyuta kibao yako itazima."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Saa yako itajizima."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Simu yako itazima."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Unataka kuzima?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Washa upya kwa hali salama"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Hali ya ndege"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Hali ya ndege IMEWASHWA"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Hali ya ndege IMEZIMWA"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Mipangilio"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Huduma ambazo zinakugharimu pesa"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Fanya mambo ambayo yanaweza kukugharimu pesa."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Ujumbe wako"</string>
@@ -267,12 +251,12 @@
<string name="permdesc_statusBarService" msgid="716113660795976060">"Inaruhusu programu kuwa upau wa hali."</string>
<string name="permlab_expandStatusBar" msgid="1148198785937489264">"panua/kunja mwambaa hali"</string>
<string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Inaruhusu programu kupanua au kukunja upau wa hali."</string>
- <string name="permlab_install_shortcut" msgid="4279070216371564234">"kuweka njia za mkato"</string>
+ <string name="permlab_install_shortcut" msgid="4279070216371564234">"sakinisha njia za mkato"</string>
<string name="permdesc_install_shortcut" msgid="8341295916286736996">"Huruhusu programu kuongeza njia za mkato za Skrini ya kwanza bila mtumiaji kuingilia."</string>
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"ondoa njia za mikato"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Huruhusu programu kuondoa njia za mkato za Skrini ya kwanza bila mtumiaji kuingilia."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"panga upya simu zinazotoka"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Huruhusu programu kuona nambari inayopigwa wakati simu inapigwa ikiwa na chaguo la kuelekeza simu kwenye nambari tofauti au kukata simu kabisa."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Inaruhusu programu kuchakata simu zinazotoka nje na kubadilisha nambari ya kupigwa. Idhini hii inaruhusu programu kuchunguza, kuelekeza upya, au kuzuia simu zinazotoka nje."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"pokea ujumbe wa maandishi wa SMS"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Inaruhusu programu kupokea na kuchakata ujumbe wa SMS. Hii inamaanisha programu hii inaweza kuchunguza na kufuta ujumbe uliotumwa katika kifaa chako bila ya kukuonyesha."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"pokea ujumbe wa maandishi wa MMS"</string>
@@ -295,7 +279,7 @@
<string name="permdesc_receiveWapPush" msgid="748232190220583385">"Inaruhusu programu kupokea na kuchakata ujumbe wa WAP. Idhini hii inajumuisha uwezo wa kuchunguza na kufuta ujumbe uliotumwa kwako bila ya kukuonyesha."</string>
<string name="permlab_getTasks" msgid="6466095396623933906">"rudisha programu zinazoendeshwa"</string>
<string name="permdesc_getTasks" msgid="7454215995847658102">"Inaruhusu programu kurudisha taarifa kuhusu kazi zinazoendeshwa sasa na hivi karibuni. Hii inaweza kuruhusu programu kugundua taarifa kuhusu ni programu zipi zinazotumika kwenye kifaa."</string>
- <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"kuwasiliana na watumiaji wengine"</string>
+ <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"Tagusana na watumiaji"</string>
<string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Inaruhusu programu kutenda vitendo kwa watumiaji tofauti kwenye kifaa. Programu hasidi huenda zikatumia hii ili kukiuka ulinzi kati ya watumiaji."</string>
<string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"leseni kamili ili kushirikiana na watumiaji"</string>
<string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Inaruhusu miingialiano yote inayowezekana kwa watumiaji."</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Inaruhusu programu kutoa maudhui ya dirisha amilifu. Programu hasidi zinaweza kutoa maudhui yote ya dirisha na kuchunguza maandishi yake yote isipokuwa nenosiri."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"wezesha ufikivu kwa muda"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Inaruhusu programu kuwezesha kwa muda ufikivu kwenye kifaa. Huenda programu hasidi zikawezesha ufikivu bila kibali cha mtumiaji."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"rejesha tokeni ya dirisha"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Inaruhusu programu kurejesha tokeni ya dirisha. Programu hasidi zinaweza kutekeleza mwingiliano usioidhinishwa na dirisha la programu zikiiga mfumo."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"rejesha takwimu za fremu"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Inaruhusu programu kukusanya takwimu za fremu. Programu hasidi zinaweza kuchunguza takwimu za fremu za dirisha kutoka kwenye programu zingine."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"okoa maelezo ya dirisha"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Huruhusu programu kuokoa maelezo kuhusu madirisha kutoka kwenye kidhibiti dirisha. Huenda programu hasidi ikakusanya maelezo ambayo yamekusudiwa kwa matumizi ya mfumo wa ndani."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"chuja matukio"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Huruhusu programu kusajili kichujio ingizo kinachochuja mkondo wa matukio ya mtumiaji kabla ya kutumwa. Huenda programu hasidi ikadhibiti mfumo wa UI bila mtumiaji kuingilia kati."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"kuza oneysho"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Inaruhusu programu kukuza maudhui ya onyesho. Programu hasidi zinaweza kubadili maudhui kwa njia ambayo inaweza kukifanya kifaa kutotumika."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"Zima nusu"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Huweka kisimamia shughuli katika hali ya kuzima. Haiadhiri uzimaji kamili"</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"zuia swichi za app"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Huruhusu programu kutangaza taarifa kwamba ujumbe wa SMS umeingia. Programu hasidi zinaweza kutumia hii kubuni SMS zinazoingia."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"tuma tangazo lililopokewa la MSUKUMO WA WAP"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Inaruhusu programu kutangaza taarifa kwamba ujumbe wa WAP PUSH umepokewa. Programu hasidi zinaweza kutumia hii kubuni risiti ya ujumbe wa MMS au polepole kubadilisha maudhui yoyote ya ukurasa wa tovuti na vibadala vibovu."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"tuma tangazo la alama za mitandao"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Huruhusu programu kutangaza arifa kuwa mitandao inafaa kupewa alama. Haihitajiki kamwe kwa programu za kawaida."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"zuia idadi ya michakato inayoendeshwa"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Inaruhusu programu kudhibiti upeo wa idadi ya michakato ambayo itaendeshwa. Kamwe hazihitajiki kwa programu za kwaida."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"lazimisha programu za usuli kufunga"</string>
@@ -366,7 +348,7 @@
<string name="permlab_updateAppOpsStats" msgid="8829097373851521505">"rekebisha takwimu za oparesheni ya programu"</string>
<string name="permdesc_updateAppOpsStats" msgid="50784596594403483">"Inaruhusu programu kurekebisha takwimu za matumizi ya programu zilizokusanywa. Si ya kutumiwa na programu za kawaida."</string>
<string name="permlab_backup" msgid="470013022865453920">"Dhibiti kuhifadhi nakala na kurejesha kwa mfumo"</string>
- <string name="permdesc_backup" msgid="6912230525140589891">"Huruhusu programu kudhibiti utaratibu wa kuhifadhi nakala rudufu na kurejesha mfumo. Haifai kutumiwa na programu za kawaida."</string>
+ <string name="permdesc_backup" msgid="6912230525140589891">"Inaruhusu programu kudhibiti utaratibu wa kucheleza na kurejesha wa mfumo. Si kwa matumizi na programu za kawaida."</string>
<string name="permlab_confirm_full_backup" msgid="5557071325804469102">"thibitisha chelezo kamilifu au rejesha upya uendeshaji"</string>
<string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Huruhusu programu kuzindua kiolesura cha kuthibitisha kuhifadhiwa kwa nakala rudufu kamili. Haitumiwi na programu yoyote."</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"onyesha madirisha yasiyoidhinishwa"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Inaruhusu kishikiliaji kushurutisha kusano ya kiwango cha juu cha huduma ya Vpn. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"funga kwa mandhari"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Inaruhusu kishikiliaji kushurutisha kwa kusano ya kiwango cha juu cha mandhari. Haipaswi kamwe kuhitajika kwa programu za kawaida."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"bandika kwenye mwingiliano wa sauti"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Humruhusu mmiliki kubandika kwenye kiolesura cha hali ya juu cha huduma ya muingiliano wa sauti. Isihitajike kamwe kwa programu za kawaida."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"fungisha kwenye mwonekano wa mbali"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Huruhusu mtumiaji kujifungia kiolesura cha kiwango cha juu cha mwonekano wa mbali. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"funga kwenye huduma ya widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Inaruhusu mmiliki kushurutisha kusano ya kiwango cha juu ya huduma ya wijeti. Haipaswi kuhitajika kwa programu za kawaida."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bandika kwenye huduma ya mtoa huduma za njia"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Huruhusu mmiliki kubandika kwenye watoa huduma za njia waliosajiliwa. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"jiunge na msimamizi wa kifaa"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Inamruhusu mmiliki kutuma malengo kwa msimamizi wa kifaa. Haipaswi kuhitajika kwa programu za kawaida."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"bandika kwenye zana za data ya runinga"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Inaruhusu kishikiliaji kubandika kwenye kusano la kiwango cha juu cha zana za data kwenye runinga. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"ongeza au ondoa msimamizi wa kifaa"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Inaruhusu mmiliki kuongeza au kuondoa wasimamizi wa kifaa waliopo. Kamwe kisihitajike kwa ajili ya programu za kawaida."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"badilisha uelekezo wa skrini"</string>
@@ -429,15 +405,15 @@
<string name="permdesc_deletePackages" msgid="7411480275167205081">"Inaruhusu programu kufuta furushi za Android. Programu hasidi zinaweza kutumia hii kufuta programu muhimu."</string>
<string name="permlab_clearAppUserData" msgid="274109191845842756">"Futa data za programu zingine"</string>
<string name="permdesc_clearAppUserData" msgid="4625323684125459488">"Inaruhusu programu kufuta data ya mtumiaji."</string>
- <string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"Kufuta akiba za programu zingine"</string>
- <string name="permdesc_deleteCacheFiles" msgid="3812998599006730196">"Huruhusu programu kufuta faili za akiba."</string>
+ <string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"Futa kache za programu zingine"</string>
+ <string name="permdesc_deleteCacheFiles" msgid="3812998599006730196">"Inaruhusu programu kufuta faili za kache."</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"Pima nafasi ya hifadhi ya programu"</string>
- <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Huruhusu Programu kupata tena msimbo, data na ukubwa wa akiba yake"</string>
+ <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Inaruhusu Programu kupata tena msimbo, data na ukubwa wa kache yake."</string>
<string name="permlab_installPackages" msgid="2199128482820306924">"sakinisha programu moja kwa moja"</string>
<string name="permdesc_installPackages" msgid="5628530972548071284">"Inaruhusu programu kusakanisha au kusasisha furushi mpya za Android. Programu hasidi zinaweza kutumia hii kuongeza programu mpya ambazo zina ruhusa zenye nguvu."</string>
- <string name="permlab_clearAppCache" msgid="7487279391723526815">"kufuta data yote kwenye akiba ya programu"</string>
- <string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"Huruhusu programu kuongeza nafasi katika hifadhi ya kompyuta kibao kwa kufuta faili katika saraka za akiba za programu zingine. Huenda hii ikafanya baadhi ya programu zianze kufanya kazi polepole kwa sababu zinahitaji kupakua tena data iliyokuwemo."</string>
- <string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"Huruhusu programu kuongeza nafasi ya hifadhi ya simu kwa kufuta faili katika saraka za akiba za programu zingine. Huenda hii ikafanya baadhi ya programu zianze kufanya kazi polepole kwa sababu zinahitaji kupakua tena data iliyokuwemo."</string>
+ <string name="permlab_clearAppCache" msgid="7487279391723526815">"Futa data yote kwenye kache ya programu"</string>
+ <string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"Inaruhusu programu kutoa nafasi ya hifadhi ya kompyuta ndogo kwa kufuta faili katika saraka za kache za programu nyingine. Huenda hii ikasababisha programu nyingine kuanza polepole zaidi kwa sababu zinahitaji kuepua data zazo."</string>
+ <string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"Inaruhusu programu kutoa nafasi ya hifadhi ya simu kwa kufuta faili katika saraka za kache za programu nyingine. Huenda hii ikasababisha programu nyingine kuanza polepole zaidi kwa sababu zinahitaji kuepua data zazo."</string>
<string name="permlab_movePackage" msgid="3289890271645921411">"songesha rasilimali ya programu"</string>
<string name="permdesc_movePackage" msgid="319562217778244524">"Huruhusu programu kuhamisha nyenzo za programu kutoka midia ya ndani hadi ya nje na kinyume chake."</string>
<string name="permlab_readLogs" msgid="6615778543198967614">"soma kumbukumbu ya data muhimu"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Huruhusu programu kutumia vyombo vyovyote vya habari vilivyosakinishwa ili kusimbua kwa ajili ya kucheza tena."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"dhibiti vitambulisho vinavyoaminika"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Huruhusu programu kusakinisha na kusanidua vyeti vya CA kama vitambulisho vinavyoaminika."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"endesha programu wakati kifaa hakifanyi kitu"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ruhusa hii huwezesha mfumo wa Android kuendesha programu chini kwa chini wakati kifaa hakitumiki."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"funga kwenye huduma zisizofanya kitu"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Ruhusa hii huruhusu mfumo wa Android kuunga kwenye huduma za programu amabazo hazitumiki."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"soma/andika kwa vyanzo vinavyomilikiwa na diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Inaruhusu programu kusoma na kuandika kwa chanzo chochote kinachomilikiwa na kikundi cha diag; kwa mfano, faili katika /dev. Hii inaweza kuathiri udhabiti na usalama wa mfumo. Hii inapaswa kutumiwa TU kwa utambuzi mahsusi wa maunzi na mtengenezaji au opareta."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"wezesha au lemeza vijenzi vya programu"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Inaruhusu programu kusoma taarifa ya kibinafsi ya maelezo mafupi yaliyohifadhiwa kwenye kifaa chako, kama vile jina lako na taarifa ya anwani. Hii inamaanisha kuwa programu inaweza kukutambua na inaweza kuwatumia wengine taarifa yako ya maelezo mafupi."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"rekebisha kadi yako mwenyewe ya mawasiliano"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Inaruhusu programu kubadilisha au kuongeza taarifa ya maelezo mafupi ya kibinafsi yaliyohifadhiwa kwenye kifaa chako, kama vile jina lako na taarifa ya anwani. Hii inamaanisha kuwa programu inaweza kukutambua na inaweza kutuma taarifa ya maelezo yako mafupi kwa wengine."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"vipima hali ya mwili (kama mpigo wa moyo)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Huruhusu programu kufikia data kutoka kwenye vipima mawimbi unavyotumia kupima kinachoendelea mwilini mwako kama vile mpigo wa moyo."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"soma mipasho yako wa kijamii"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Huruhusu programu kufikia na kupatanisha masasisho ya kijamii kutoka kwa marafiki zako. Kuwa makini wakati unashiriki taarifa -- hii huruhusu programu kusoma mawasiliano kati yako na marafiki zako kwenye mitandao jamii, bila kujali usiri. Kumbuka: idhini hii haiwezi kutekelezwa kwenye mitandao yote ya jamii."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"kuandikia mipasho yako wa kijamii"</string>
@@ -562,7 +536,7 @@
<string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"Inaruhusu programu kupachika/kupachua hifadhi ya ndani."</string>
<string name="permlab_asec_rename" msgid="7496633954080472417">"ipe hifadhi ya ndani jina jipya"</string>
<string name="permdesc_asec_rename" msgid="1794757588472127675">"Inaruhusu programu kubadilisha jina la hifadhi ya ndani."</string>
- <string name="permlab_vibrate" msgid="7696427026057705834">"Kudhibiti mtetemo"</string>
+ <string name="permlab_vibrate" msgid="7696427026057705834">"dhibiti mtetemo"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Inaruhusu programu kudhibiti kitingishi."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"dhibiti tochi"</string>
<string name="permdesc_flashlight" msgid="6522284794568368310">"Inaruhusu programu kudhibiti tochi."</string>
@@ -588,9 +562,7 @@
<string name="permlab_modifyPhoneState" msgid="8423923777659292228">"badiliisha hali ya simu"</string>
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Inaruhusu programu kudhibiti vipengee vya kifaa. Programu iliyo na ruhusa hii inaweza badilisha mtandao, kuzima na kuwasha redio ya simu bila hata kukujulisha."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"kusoma hali na kitambulisho cha simu"</string>
- <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Huruhusu programu kufikia vipengele vya simu vilivyo kwenye kifaa. Idhini hii inaruhusu programu kutambua nambari ya simu na kifaa, kama kuna simu inayopigwa, na nambari ya mbali iliyounganishwa kwenye simu."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"Soma hali sahihi ya simu"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Huruhusu programu kufikia hali sahihi ya simu. Ruhusa hii huwezesha programu kufahamu hali sahihi ya simu, iwapo simu inatumika au iko katika hali ya chini kwa chini, simu inaposhindikana, hali sahihi ya muunganisho wa data na muunganisho wa data unaposhindikana."</string>
+ <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Inaruhusu programu kufikia vipengele vya simu vya kifaa. Idhini hii inaruhusu programu kutambua nambari ya simu na kifaa, kama simu ni amilifu, na nambari ya mbali iliyounganishwa kwa simu."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zuia kompyuta ndogo dhidi ya kulala"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"kuzuia simu isilale"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Inaruhusu programu kuzuia kompyuta kibao kwenda kulala."</string>
@@ -628,19 +600,19 @@
<string name="permdesc_manageAccounts" msgid="8698295625488292506">"Inaruhusu programu kutekeleza shughuli kama vile kuongeza na kutoa akaunti, na kufuta manenosiri yazo."</string>
<string name="permlab_useCredentials" msgid="235481396163877642">"kutumia akaunti zilizo kwenye kifaa"</string>
<string name="permdesc_useCredentials" msgid="7984227147403346422">"Inaruhusu programu kuomba shuhuda za uthibitisho."</string>
- <string name="permlab_accessNetworkState" msgid="4951027964348974773">"kuona mitandao"</string>
+ <string name="permlab_accessNetworkState" msgid="4951027964348974773">"Kuangalia mitandao"</string>
<string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Inaruhusu programu kuona taarifa kuhusu miunganisho ya mtandao kama vile mitandao ipi iliyopo na imeunganishwa."</string>
<string name="permlab_createNetworkSockets" msgid="8018758136404323658">"ufikiaji kamili wa mtandao"</string>
<string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Inaruhusu programu kuunda soketi za mtandao na kutumia itifaki za mtandao maalum. Kivinajri na programu nyingine zilizotolewa zinamaanisha kutuma data kwenye mtandao, kwa hivyo kibali hiki hakihitajiki kutuma data kwenye mtandao."</string>
<string name="permlab_writeApnSettings" msgid="505660159675751896">"mabadiliko / kuingilia mipangilio ya mtandao/msonmgamano"</string>
<string name="permdesc_writeApnSettings" msgid="5333798886412714193">"Inaruhusu programu kubadilisha mipangilio ya mtandao na kukatiza na kukagua uendaji wa mtandao, kwa mfano kubadilisha kituo tarishi na mbadala cha APN yoyote. Programu hasidi zinaweza kuangalia, kuelekeza kwingine, au kurekebisha furushi za mtandao bila ya wewe kujua."</string>
- <string name="permlab_changeNetworkState" msgid="958884291454327309">"kubadilisha muunganisho wa mtandao"</string>
+ <string name="permlab_changeNetworkState" msgid="958884291454327309">"badilisha muunganisho wa mtandao"</string>
<string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Inaruhusu programu kubadilisha hali ya muunganisho wa mtandao."</string>
<string name="permlab_changeTetherState" msgid="5952584964373017960">"Badilisha muunganisho uliofunganishwa"</string>
<string name="permdesc_changeTetherState" msgid="1524441344412319780">"Inaruhusu programu kubadilisha hali ya muunganisho wa mtandao uliofungwa."</string>
<string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"badilisha mpangilio wa utumiaji data ya mandharinyuma"</string>
<string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Inaruhusu programu kubadilisha mpangilio wa matumizi ya data ya usuli."</string>
- <string name="permlab_accessWifiState" msgid="5202012949247040011">"Kuona miunganisho ya Wi-Fi"</string>
+ <string name="permlab_accessWifiState" msgid="5202012949247040011">"ona miunganisho ya Wi-Fi"</string>
<string name="permdesc_accessWifiState" msgid="5002798077387803726">"Inaruhusu programu kuona taarifa kuhusu mtandao wa Wi-Fi, kama vile ikiwa Wi-Fi imewezeshwa mna jina la vifaa vya Wi-Fi vilivyounganishwa."</string>
<string name="permlab_changeWifiState" msgid="6550641188749128035">"unganisha na utenganishe kutoka kwa Wi-Fi"</string>
<string name="permdesc_changeWifiState" msgid="7137950297386127533">"Inaruhusu programu kuunganisha kwenye au kukata kutoka pointi za ufikivu wa Wi-Fi na kufanya mabadiliko kwenye usanidi wa kifaa cha mitandao ya Wi-Fi."</string>
@@ -658,31 +630,28 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Badilisha hali ya WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Inaruhusu programu kuunganisha kompyuta kibao, na kukata kompyuta kibao kutoka mitandao ya WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Inaruhusu programu kuunganisha simu kwenye, na kukata simu kutoka mitandao ya WiMAX."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ipe mitandao alama"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Huruhusu programu kupanga mitandao kwa alama na kushawishi mitandao ambayo kompyuta kibao inapaswa kupendelea."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Huruhusu programu kupanga mitandao kwa alama na kushawishi mitandao ambayo simu inapaswa kupendelea."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"oanisha na vifaa vya Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Inaruhusu programu kuona usanidi wa Bluetooth kwenye kompyuta kibao, na kuunda na kukubali miunganisho kwa vifaa vilivyooanishwa."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Inaruhusu programu kuona usanidi wa Bluetooth kwenye simu, na kuunda na kukubali miunganisho kwa vifaa vilivyooanishwa."</string>
- <string name="permlab_nfc" msgid="4423351274757876953">"kudhibiti Mawasiliano ya Vifaa Vilivyokaribu (NFC)"</string>
+ <string name="permlab_nfc" msgid="4423351274757876953">"dhibiti Mawasiliano ya vifaa vilivyo Karibu"</string>
<string name="permdesc_nfc" msgid="7120611819401789907">"Inaruhusu programu kuwasiliana na lebo, kadi na wasomaji wa Near Field Communication (NFC)."</string>
<string name="permlab_disableKeyguard" msgid="3598496301486439258">"zima kufuli la skrini yako"</string>
<string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Inaruhusu programu kulemaza ufunguo wa vitufe na usalama mwingine ambata wa nenosiri. Kwa mfano, simu inalemaza ufunguo wa viitufe inapopokea simu inayoingia, kisha inawezesha upya ufunguo wa vitufe wakati simu inapokamilika."</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"kusoma mipangilio ya usawazishaji"</string>
+ <string name="permlab_readSyncSettings" msgid="6201810008230503052">"soma mipangilio ya usawazishaji"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Inaruhusu programu kusoma mipangilio ya upatanishi wa akaunti. Kwa mfano, huku kunaweza kuamua kama programu ya Watu imepatanishwa na akaunti."</string>
- <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"kuwasha na kuzima usawazishaji"</string>
+ <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"washa na uzime usawazishaji"</string>
<string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Inaruhusu programu kurekebisha mipangalio ya upatanishi wa akaunti. Kwa mfano, hii inaweza kuwezesha programu ya upatanishi wa Watu na akaunti."</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"kusoma takwimu za usawazishaji"</string>
+ <string name="permlab_readSyncStats" msgid="7396577451360202448">"soma takwimu za usawazishaji"</string>
<string name="permdesc_readSyncStats" msgid="1510143761757606156">"Inaruhusu programu kusoma takwimu za upatanishi za akaunti, ikiwa ni pamoja na historia ya matukio ya upatanishi na kiasi cha data kimepatanishwa."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"kusoma mipasho kutoka vyanzo unavyofuatilia"</string>
+ <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"soma milisho ya kujiunga"</string>
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Inaruhusu programu kupata maelezo kuhusu mlisho iliyolandanishwa kwa sasa."</string>
- <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"kuandika mipasho kutoka vyanzo unavyofuatilia"</string>
+ <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"andika milisho ya kujiunga"</string>
<string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Inaruhusu programu kurekebisha milisho yako iliyolandanishwa kwa sasa. Programu hasidi zinaweza kubadilisha milisho yako iliyolandanishwa."</string>
<string name="permlab_readDictionary" msgid="4107101525746035718">"soma maneno uliyoongeza kwenye kamusi"</string>
<string name="permdesc_readDictionary" msgid="659614600338904243">"Inaruhusu programu kusoma maneno, majina na misemo yote ambayo mtumiaji alihifadhi katika kamusi ya mtumiaji."</string>
<string name="permlab_writeDictionary" msgid="2183110402314441106">"ongeza maneno katika kamusi ya mtumiaji iliyofafanuliwa"</string>
<string name="permdesc_writeDictionary" msgid="8185385716255065291">"Inaruhusu programu kuandika maneno mapya katika kamusi ya mtumiaji."</string>
- <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"kusoma maudhui yaliyo kwenye hifadhi yako ya USB"</string>
+ <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"soma maudhui ya hifadhi yako ya USB"</string>
<string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"soma maudhui ya kadi yako ya SD"</string>
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Huruhusu programu kusoma maudhui ya hifadhi ya USB."</string>
<string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Huruhusu programu kusoma maudhui ya kadi yako ya SD."</string>
@@ -696,12 +665,12 @@
<string name="permdesc_manageDocs" product="default" msgid="8704323176914121484">"Huruhusu programu kudhibiti hifadhi ya hati."</string>
<string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"Fikia hifadhi ya nje ya watumiaji wote"</string>
<string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Inaruhusu programu kufikia hifadhi ya nje kwa watumiaji wote."</string>
- <string name="permlab_cache_filesystem" msgid="5656487264819669824">"fikia faili za mfumo za akiba"</string>
- <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Huruhusu programu kusoma na kuandika mfumo wa faili wa akiba."</string>
+ <string name="permlab_cache_filesystem" msgid="5656487264819669824">"fikia faili za mfumo za kache"</string>
+ <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Inaruhusu programu kusoma na kuandika mfumo wa faili wa kache."</string>
<string name="permlab_use_sip" msgid="5986952362795870502">"piga/pokea simu za mtandao"</string>
<string name="permdesc_use_sip" msgid="4717632000062674294">"Inaruhusu programu kutumia huduma ya SIP kupiga/kupokea simu za mtandao."</string>
<string name="permlab_bind_call_service" msgid="6724009726671246551">"tumikisha skrini ya simu inayoendelea"</string>
- <string name="permdesc_bind_call_service" msgid="8732547662442572435">"Huruhusu programu kudhibiti wakati na jinsi mtumiaji anaona skrini anapopigiwa simu."</string>
+ <string name="permdesc_bind_call_service" msgid="8732547662442572435">"Inaruhusu programu kudhibiti wakati na jinsi mtumiaji anaona skrini ya simu inayoendelea."</string>
<string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"soma matumizi ya historia ya mtandao"</string>
<string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Inaruhusu programu kusoma historia ya matumizi ya mtandao kwa mitandao maalum na programu."</string>
<string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"dhibiti sera ya mtandao"</string>
@@ -714,21 +683,15 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Huruhusu programu kurejesha, kuchunguza, na kuondoa arifa, ikiwa ni pamoja na zile zilizochapishwa na programu nyingine."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"unganisha kwenye huduma ya kisikilizi cha arifa"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Inaruhusu kishikilizi kuunganishwa kwenye kusano cha kiwango cha juu cha huduma ya kisikilizi cha arifa. Haipaswi kuhitajika tena kwa programu za kawaida."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bandika kwenye huduma ya mtoa masharti"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Humruhusu mmiliki kubandika kwenye kiolesura cha kiwango cha juu cha huduma ya mtoa masharti. Isihitajike kamwe kwa pogramu za kawaida."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"omba programu ya usakinishaji inayotolewa na mtoa huduma."</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Inaruhusu kishikiliaji kuomba programu ya usakinishaji inayotolewa na mto huduma. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"sikiliza matukio katika hali za mtandao"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Huruhusu programu kusikiliza matukio katika hali za mtandao. Haipaswi kuhitajika kamwe kwa programu za kawaida."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"badilisha urekebishaji wa kifaa cha kuingiza data"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Huruhusu programu kubadilisha vigezo vya urekebishaji vya skrini ya kugusa. Havipaswi kuhitajika kamwe kwa programu za kawaida."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"fikia vyeti vya DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Huruhusu programu kwa utoaji na matumizi ya vyeti vya DRM. Havifahi kuhitajika kwa ajili ya programu za kawaida."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Kuweka kanuni za nenosiri"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kudhibiti urefu na herufi zinazoruhusiwa katika manenosiri ya kufungua skrini."</string>
- <string name="policylab_watchLogin" msgid="914130646942199503">"Kuhesabu mara ambazo skrini inajaribu kufunguliwa"</string>
- <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Kufuatilia idadi ya manenosiri yasiyo sahihi yatakayoingizwa wakati wa kufungua skrini, na kufunga kompyuta kibao au kufuta data yote iliyomo kama manenosiri mengi yasiyo sahihi yataingizwa."</string>
- <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Kufuatilia idadi ya manenosiri yasiyo sahihi yatakayoingizwa wakati wa kufungua skrini, na kufunga simu au kufuta data yote iliyomo kama manenosiri mengi sana yasiyo sahihi yataingizwa."</string>
+ <string name="policylab_watchLogin" msgid="914130646942199503">"Kuhesabu idadi ya mara ambazo skrini inajaribu kufunguliwa"</string>
+ <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Fuatilia idadi ya manenosiri yasiyo sahihi yatakayoingizwa wakati wa kufungua skrini, na ufunge kompyuta kibao au ufute data yote iliyomo kama manenosiri mengi yenye makosa yataingizwa."</string>
+ <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Fuatilia idadi ya manenosiri yasiyo sahihi yatakayoingizwa wakati wa kufungua skrini, na ufunge simu au ufute data yote iliyomo kama manenosiri mengi sana yasiyo sahihi yataingizwa."</string>
<string name="policylab_resetPassword" msgid="2620077191242688955">"Kubadilisha nenosiri la kufungua skrini"</string>
<string name="policydesc_resetPassword" msgid="605963962301904458">"Kubadilisha nenosiri la kufungua skrini."</string>
<string name="policylab_forceLock" msgid="2274085384704248431">"Kufunga skrini"</string>
@@ -1305,14 +1268,14 @@
<string name="usb_ptp_notification_title" msgid="1960817192216064833">"Imeunganishwa kama kamera"</string>
<string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Imeunganishwa kama kisakinishi"</string>
<string name="usb_accessory_notification_title" msgid="7848236974087653666">"Imeunganishwa kwa kifuasi cha USB"</string>
- <string name="usb_notification_message" msgid="2290859399983720271">"Gusa ili uone chaguo zingine za USB."</string>
+ <string name="usb_notification_message" msgid="2290859399983720271">"Gusa kwa chaguo nyingine za USB."</string>
<string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"Fomati hifadhi ya USB?"</string>
<string name="extmedia_format_title" product="default" msgid="3648415921526526069">"Umbiza kadi ya SD."</string>
<string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"Faili zote zilizohifadhiwa katika hifadhi yako ya USB zitafutwa. Hatua hii haiwezi kubadilishwa!"</string>
<string name="extmedia_format_message" product="default" msgid="14131895027543830">"Data yote kwenye kadi yako itapotea."</string>
<string name="extmedia_format_button_format" msgid="4131064560127478695">"Fomati"</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"Utatuaji wa USB umeunganishwa"</string>
- <string name="adb_active_notification_message" msgid="1016654627626476142">"Gusa ili uzime utatuaji wa USB."</string>
+ <string name="adb_active_notification_title" msgid="6729044778949189918">"Utatuaji USB umeunganishwa"</string>
+ <string name="adb_active_notification_message" msgid="1016654627626476142">"Gusa ili kulemaza utatuaji wa USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Chagua njia ya ingizo"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Weka mbinu za ingizo"</string>
<string name="use_physical_keyboard" msgid="6203112478095117625">"Kibodi halisi"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Inaruhusu programu kufikia hifadhi salama ya ufunguo wa ulinzi."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Dhibiti uonyeshaji na ufichaji wa kilinda-funguo"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Huruhusu programu kudhibiti kilinda-funguo."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Sikiliza mabadiliko ya hali ya kuaminiwa."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Huruhusu programu kusikiliza mabadiliko katika hali ya kuaminiwa."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Funga kwenye huduma ya dalali wa kuaminiwa"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Huruhusu programu kufungamanisha kwenye huduma ya dalali wa kuaminiwa."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Ingiliana na sasisho na mfumo wa kurejesha"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Huruhusu programu kuingiliana na mfumo wa kurejesha na sasisho la mfumo."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Gusa mara mbili kwa udhibiti cha kuza"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Mandhari"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Badilisha mandhari"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Kisikilizi cha arifa"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Mtoa masharti"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN imewezeshwa"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN imeamilishwa na <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Gusa ili kudhibiti mtandao."</string>
diff --git a/core/res/res/values-television/themes.xml b/core/res/res/values-television/themes.xml
new file mode 100644
index 0000000..6e17cdd3
--- /dev/null
+++ b/core/res/res/values-television/themes.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <style name="Theme.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
+ <style name="Theme.Dialog.AppError" parent="Theme.Leanback.Dialog.AppError" />
+ <style name="Theme.Holo.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
+ <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
+ <style name="Theme.Quantum.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
+ <style name="Theme.Quantum.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
+</resources>
diff --git a/core/res/res/values-television/themes_device_defaults.xml b/core/res/res/values-television/themes_device_defaults.xml
new file mode 100644
index 0000000..e01caa3
--- /dev/null
+++ b/core/res/res/values-television/themes_device_defaults.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
+ <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
+</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 7f0cf61..c1f1c9b 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> วัน"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> วัน <xliff:g id="HOURS">%2$d</xliff:g> ชม."</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> วัน <xliff:g id="HOURS">%2$d</xliff:g> ชม."</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> ชม."</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> ชม. <xliff:g id="MINUTES">%2$d</xliff:g> นาที"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> ชม. <xliff:g id="MINUTES">%2$d</xliff:g> นาที"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> นาที"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> นาที <xliff:g id="SECONDS">%2$d</xliff:g> วิ."</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> นาที <xliff:g id="SECONDS">%2$d</xliff:g> วิ."</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> วินาที"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> วินาที"</string>
<string name="untitled" msgid="4638956954852782576">"<ไม่มีชื่อ>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"ซิงค์"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"มีการลบ <xliff:g id="CONTENT_TYPE">%s</xliff:g> มากเกินไป"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"ที่จัดเก็บข้อมูลของแท็บเล็ตเต็ม ลบไฟล์บางไฟล์เพื่อเพิ่มพื้นที่ว่าง"</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"ที่เก็บข้อมูลนาฬิกาเต็ม โปรดลบไฟล์บางไฟล์เพื่อเพิ่มพื้นที่ว่าง"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"ที่เก็บข้อมูลโทรศัพท์เต็ม ลบบางไฟล์เพื่อเพิ่มที่ว่าง"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"เครือข่ายอาจได้รับการตรวจสอบ"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"โดยบุคคลที่สามที่ไม่รู้จัก"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"เปิดเสียง"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"กำลังปิดระบบ..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"แท็บเล็ตของคุณจะปิดการทำงาน"</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"นาฬิกาจะปิดการทำงาน"</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"โทรศัพท์ของคุณจะปิดเครื่อง"</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"คุณต้องการปิดการทำงานหรือไม่"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"รีบูตเข้าสู่โหมดปลอดภัย"</string>
@@ -175,21 +162,18 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"ตัวเลือกโทรศัพท์"</string>
<string name="global_action_lock" msgid="2844945191792119712">"ล็อกหน้าจอ"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"ปิดเครื่อง"</string>
- <string name="global_action_bug_report" msgid="7934010578922304799">"รายงานข้อบกพร่อง"</string>
- <string name="bugreport_title" msgid="2667494803742548533">"ใช้รายงานข้อบกพร่อง"</string>
- <string name="bugreport_message" msgid="398447048750350456">"การดำเนินการนี้จะรวบรวมข้อมูลเกี่ยวกับสถานะปัจจุบันของอุปกรณ์ของคุณ โดยจะส่งไปในรูปแบบข้อความอีเมล อาจใช้เวลาสักครู่ตั้งแต่เริ่มการสร้างรายงานข้อบกพร่องจนกระทั่งเสร็จสมบูรณ์ โปรดอดทนรอ"</string>
+ <string name="global_action_bug_report" msgid="7934010578922304799">"รายงานบั๊ก"</string>
+ <string name="bugreport_title" msgid="2667494803742548533">"ใช้รายงานบั๊ก"</string>
+ <string name="bugreport_message" msgid="398447048750350456">"การดำเนินการนี้จะรวบรวมข้อมูลเกี่ยวกับสถานะปัจจุบันของอุปกรณ์ของคุณ โดยจะส่งไปในรูปแบบข้อความอีเมล อาจใช้เวลาสักครู่ตั้งแต่เริ่มการสร้างรายงานบั๊กจนกระทั่งเสร็จสมบูรณ์ โปรดอดทนรอ"</string>
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"โหมดปิดเสียง"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"ปิดเสียงไว้"</string>
<string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"เปิดเสียงแล้ว"</string>
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"โหมดใช้งานบนเครื่องบิน"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"เปิดโหมดใช้งานบนเครื่องบิน"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"โหมดใช้งานบนเครื่องบินปิดทำงานอยู่"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"การตั้งค่า"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"บริการที่ต้องเสียค่าใช้จ่าย"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ทำสิ่งที่คุณต้องเสียค่าใช้จ่าย"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"ข้อความของคุณ"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"ถอนการติดตั้งทางลัด"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"อนุญาตให้แอปพลิเคชันลบทางลัดหน้าจอหลักโดยไม่ต้องให้ผู้ใช้จัดการ"</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"จัดเส้นทางการโทรออกใหม่"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"อนุญาตให้แอปดูหมายเลขที่โทรในระหว่างการโทรออกโดยสามารถเลือกเปลี่ยนเส้นทางการโทรไปยังหมายเลขอื่นหรือยกเลิกการโทรไปเลยได้"</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"อนุญาตให้แอปพลิเคชันประมวลผลการโทรออกและเปลี่ยนแปลงหมายเลขที่จะโทรไป การอนุญาตนี้จะทำให้แอปพลิเคชันสามารถตรวจสอบ เปลี่ยนเส้นทาง หรือกีดขวางไม่ให้โทรออกได้"</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"รับข้อความ (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"อนุญาตให้แอปพลิเคชันรับและประมวลผลข้อความ SMS ซึ่งหมายความว่าแอปพลิเคชันจะสามารถตรวจสอบหรือลบข้อความที่ส่งมายังอุปกรณ์ของคุณได้โดยไม่ต้องแสดงให้คุณเห็น"</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"รับข้อความ (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"อนุญาตให้แอปพลิเคชันดึงเนื้อหาของหน้าต่างที่ใช้งานอยู่ แอปพลิเคชันที่เป็นอันตรายอาจดึงเนื้อหาจากหน้าต่างทั้งหมดและตรวจสอบข้อความทั้งหมดยกเว้นรหัสผ่าน"</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"เปิดใช้งานการเข้าถึงชั่วคราว"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"ช่วยให้แอปพลิเคชันสามารถเปิดใช้งานการเข้าถึงบนอุปกรณ์เป็นการชั่วคราว แอปพลิเคชันที่เป็นอันตรายอาจเปิดใช้งานการเข้าถึงโดยไม่ได้รับความยินยอมจากผู้ใช้"</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"เรียกโทเค็นหน้าต่าง"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"อนุญาตให้แอปพลิเคชันเรียกโทเค็นหน้าต่าง แอปที่เป็นอันตรายอาจทำการโต้ตอบที่ไม่ได้รับอนุญาตกับหน้าต่างแอปพลิเคชันโดยปลอมแปลงเป็นระบบ"</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"เรียกสถิติเฟรม"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"อนุญาตให้แอปพลิเคชันเก็บสถิติเฟรม แอปที่เป็นอันตรายอาจดูสถิติเฟรมของหน้าต่างจากแอปอื่น"</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"เรียกข้อมูลหน้าต่าง"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"อนุญาตให้แอปพลิเคชันดึงข้อมูลเกี่ยวกับหน้าต่างจากเครื่องมือจัดการหน้าต่าง แอปพลิเคชันที่เป็นอันตรายอาจดึงข้อมูลที่มีไว้เพื่อการใช้ของระบบภายใน"</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"กรองกิจกรรม"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"อนุญาตให้แอปพลิเคชันลงทะเบียนตัวกรองข้อมูลซึ่งจะกรองสตรีมกิจกรรมทั้งหมดของผู้ใช้ก่อนที่จะทำการเผยแพร่ออกไป แอปพลิเคชันที่เป็นอันตรายอาจควบคุม UI ของระบบโดยไม่ต้องให้ผู้ใช้จัดการ"</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"ขยายการแสดงผล"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"อนุญาตให้แอปพลิเคชันขยายเนื้อหาที่แสดงผล แอปพลิเคชันที่เป็นอันตรายอาจแปลงเนื้อหาที่แสดงในลักษณะที่ทำให้ไม่สามารถใช้อุปกรณ์ได้"</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"ปิดการทำงานบางส่วน"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"กำหนดให้ตัวจัดการกิจกรรมอยู่ในสถานะปิดระบบ โดยไม่ได้ปิดระบบอย่างสมบูรณ์"</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ป้องกันการเปลี่ยนแอปพลิเคชัน"</string>
@@ -345,14 +329,12 @@
<string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"ช่วยให้เจ้าของสามารถดึงข้อมูลส่วนตัวเกี่ยวกับแอปพลิเคชันปัจจุบันในส่วนหน้าของหน้าจอ"</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"ตรวจสอบและควบคุมแอปพลิเคชันทั้งหมดที่เปิดใช้งาน"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"อนุญาตให้แอปพลิเคชันตรวจสอบและควบคุมวิธีการที่ระบบเปิดกิจกรรมต่างๆ แอปพลิเคชันที่เป็นอันตรายอาจทำอันตรายแก่ระบบได้อย่างสิ้นเชิง การอนุญาตนี้จำเป็นสำหรับการพัฒนาเท่านั้น ไม่ใช้สำหรับแอปพลิเคชันทั่วไปโดยเด็ดขาด"</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"ส่งการกระจายข้อมูลว่ามีการนำแพ็กเกจออก"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"อนุญาตให้แอปพลิเคชันกระจายข้อมูลการแจ้งเตือนว่าแพ็กเกจของแอปพลิเคชันหนึ่งๆ ได้ถูกนำออกไปแล้ว แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ยุติแอปพลิเคชันอื่นๆ ที่กำลังทำงานอยู่"</string>
+ <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"ส่งการกระจายข้อมูลว่ามีการนำแพคเกจออก"</string>
+ <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"อนุญาตให้แอปพลิเคชันกระจายข้อมูลการแจ้งเตือนว่าแพคเกจของแอปพลิเคชันหนึ่งๆ ได้ถูกนำออกไปแล้ว แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ยุติแอปพลิเคชันอื่นๆ ที่กำลังทำงานอยู่"</string>
<string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"ส่งการกระจายข้อมูลว่าได้รับ SMS"</string>
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"อนุญาตให้แอปพลิเคชันกระจายข้อมูลการแจ้งเตือนว่าได้รับข้อความ SMS แล้ว แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ปลอมข้อความ SMS ที่เข้ามา"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ส่งการกระจายข้อมูลว่าได้รับ WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"อนุญาตให้แอปพลิเคชันกระจายข้อมูลการแจ้งเตือนว่าได้รับข้อความ WAP PUSH แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ปลอมการแจ้งรับข้อความ MMS หรือแอบเปลี่ยนเนื้อหาในหน้าเว็บโดยใช้ตัวแปรที่เป็นอันตราย"</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ส่งเผยแพร่การให้คะแนนเครือข่าย"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"อนุญาตให้แอปนี้เผยแพร่ข้อมูลการแจ้งเตือนว่าเครือข่ายจะต้องผ่านการให้คะแนน ไม่จำเป็นสำหรับแอปทั่วไป"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"จำกัดจำนวนกระบวนการที่กำลังทำงาน"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"อนุญาตให้แอปพลิเคชันควบคุมจำนวนสูงสุดของกระบวนการที่จะเรียกใช้ ไม่จำเป็นต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"บังคับปิดแอปพลิเคชันในพื้นหลัง"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"อนุญาตให้เจ้าของเชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการ VPN ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"เชื่อมโยงกับวอลเปเปอร์"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของวอลเปเปอร์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"เชื่อมโยงกับโปรแกรมโต้ตอบด้วยเสียง"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"อนุญาตให้ผู้ใช้อุปกรณ์เชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการโต้ตอบด้วยเสียง ไม่จำเป็นสำหรับแอปทั่วไป"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ผูกกับจอแสดงผลระยะไกล"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"อนุญาตให้ผู้ใช้ผูกกับอินเทอร์เฟซระดับสูงสุดของจอแสดงผลระยะไกล ซึ่งแอปพลิเคชันทั่วไปไม่จำเป็นต้องใช้"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"เชื่อมโยงกับบริการวิดเจ็ต"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการวิดเจ็ต ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"เชื่อมโยงกับบริการของผู้ให้บริการเส้นทาง"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"ช่วยให้เจ้าของสามารถเชื่อมโยงกับผู้ให้บริการเส้นทางที่ลงทะเบียนรายใดก็ได้ ไม่จำเป็นสำหรับแอปทั่วไป"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ติดต่อกับผู้ดูแลอุปกรณ์"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"อนุญาตให้ผู้ใช้ส่งการติดต่อไปยังโปรแกรมควบคุมอุปกรณ์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"เชื่อมโยงกับอินพุตทีวี"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"อนุญาตให้เจ้าของเชื่อมโยงกับส่วนติดต่อระดับสูงสุดของอินพุตทีวี ซึ่งแอปทั่วไปไม่จำเป็นต้องใช้"</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"เพิ่มหรือลบผู้ดูแลระบบอุปกรณ์"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"อนุญาตให้เจ้าของเพิ่มหรือลบผู้ดูแลระบบอุปกรณ์ที่ใช้งาน ไม่ควรต้องใช้สำหรับแอปปกติ"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"เปลี่ยนการวางแนวหน้าจอ"</string>
@@ -426,7 +402,7 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"อนุญาตให้แอปพลิเคชันทำให้ส่วนหนึ่งของตัวเองคงอยู่ถาวรในหน่วยความจำ ซึ่งจะจำกัดพื้นที่หน่วยความจำที่ใช้งานได้ของแอปพลิเคชันอื่นๆ และทำให้แท็บเล็ตทำงานช้าลง"</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"อนุญาตให้แอปพลิเคชันทำให้ส่วนหนึ่งของตัวเองคงอยู่ถาวรในหน่วยความจำ ซึ่งจะจำกัดพื้นที่หน่วยความจำที่ใช้งานได้ของแอปพลิเคชันอื่นๆ และทำให้โทรศัพท์ทำงานช้าลง"</string>
<string name="permlab_deletePackages" msgid="184385129537705938">"ลบแอปพลิเคชัน"</string>
- <string name="permdesc_deletePackages" msgid="7411480275167205081">"อนุญาตให้แอปพลิเคชันลบแพ็กเกจ Android แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ลบแอปพลิเคชันที่สำคัญ"</string>
+ <string name="permdesc_deletePackages" msgid="7411480275167205081">"อนุญาตให้แอปพลิเคชันลบแพคเกจ Android แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ลบแอปพลิเคชันที่สำคัญ"</string>
<string name="permlab_clearAppUserData" msgid="274109191845842756">"ลบข้อมูลของแอปพลิเคชันอื่น"</string>
<string name="permdesc_clearAppUserData" msgid="4625323684125459488">"อนุญาตให้แอปพลิเคชันล้างข้อมูลผู้ใช้"</string>
<string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"ลบแคชของแอปพลิเคชันอื่น"</string>
@@ -434,7 +410,7 @@
<string name="permlab_getPackageSize" msgid="7472921768357981986">"วัดพื้นที่เก็บข้อมูลของแอปพลิเคชัน"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"อนุญาตให้แอปพลิเคชันเรียกดูรหัส ข้อมูล และขนาดแคชของตน"</string>
<string name="permlab_installPackages" msgid="2199128482820306924">"ติดตั้งแอปพลิเคชันโดยตรง"</string>
- <string name="permdesc_installPackages" msgid="5628530972548071284">"อนุญาตให้แอปพลิเคชันติดตั้งแพ็กเกจ Android ใหม่หรือที่อัปเดต แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ในการเพิ่มแอปพลิเคชันใหม่ๆ ด้วยสิทธิ์ที่สูงนี้ได้ตามต้องการ"</string>
+ <string name="permdesc_installPackages" msgid="5628530972548071284">"อนุญาตให้แอปพลิเคชันติดตั้งแพคเกจ Android ใหม่หรือที่อัปเดต แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ในการเพิ่มแอปพลิเคชันใหม่ๆ ด้วยสิทธิ์ที่สูงนี้ได้ตามต้องการ"</string>
<string name="permlab_clearAppCache" msgid="7487279391723526815">"ลบข้อมูลแคชของแอปพลิเคชันทั้งหมด"</string>
<string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"อนุญาตให้แอปพลิเคชันสร้างพื้นที่ว่างในที่จัดเก็บข้อมูลของแท็บเล็ต โดยลบไฟล์ในไดเรกทอรีแคชของแอปพลิเคชันอื่นๆ ซึ่งอาจทำให้แอปพลิเคชันอื่นเริ่มทำงานช้ากว่าเดิมเนื่องจากต้องดึงข้อมูลของตนซ้ำ"</string>
<string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"อนุญาตให้แอปพลิเคชันสร้างพื้นที่ว่างในที่จัดเก็บข้อมูลของโทรศัพท์ โดยลบไฟล์ในไดเรกทอรีแคชของแอปพลิเคชันอื่นๆ ซึ่งอาจทำให้แอปพลิเคชันอื่นเริ่มทำงานช้ากว่าเดิมเนื่องจากต้องดึงข้อมูลของตนซ้ำ"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"อนุญาตให้แอปพลิเคชันใช้ตัวถอดรหัสสื่อใดก็ได้ที่ติดตั้งไว้เพื่อถอดรหัสสำหรับการเล่น"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"จัดการข้อมูลรับรองที่เชื่อถือได้"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"อนุญาตให้แอปติดตั้งและถอนการติดตั้งใบรับรอง CA ในฐานะข้อมูลรับรองที่เชื่อถือได้"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"เรียกใช้แอปพลิเคชันในระหว่างที่ไม่ได้ใช้งาน"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"สิทธิ์นี้ช่วยให้ระบบแอนดรอยด์สามารถเรียกใช้แอปพลิเคชันในพื้นหลังขณะไม่ได้ใช้งานอุปกรณ์อยู่"</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"เชื่อมโยงกับบริการที่ไม่ได้ใช้งาน"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"สิทธิ์นี้จะทำให้ระบบแอนดรอยด์สามารถเชื่อมโยงกับบริการรายงานเวลาที่ไม่มีการใช้งานของแอปพลิเคชัน"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"อ่าน/เขียนไปยังรีซอร์สที่เป็นเจ้าของโดยกลุ่มวินิจฉัย"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"อนุญาตให้แอปพลิเคชันอ่านและเขียนไปยังทรัพยากรที่เป็นของกลุ่มวินิจฉัย เช่น ไฟล์ใน /dev การทำเช่นนี้อาจส่งผลต่อความเสถียรและความปลอดภัยของระบบ และควรใช้สำหรับการวินิจฉัยเกี่ยวกับฮาร์ดแวร์โดยเฉพาะที่ทำโดยผู้ผลิตหรือผู้ให้บริการเท่านั้น"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"เปิดหรือปิดใช้งานคอมโพเนนต์ของแอปพลิเคชัน"</string>
@@ -471,14 +447,14 @@
<string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"อนุญาตให้แอปพลิเคชันส่งการกระจายข้อมูลที่ติดหนึบ ซึ่งจะยังคงอยู่หลังจากการกระจายข้อมูลจบไปแล้ว การใช้งานมากเกินไปอาจทำให้แท็บเล็ตทำงานช้าลงหรือไม่เสถียรโดยการใช้หน่วยความจำมากเกินไป"</string>
<string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"อนุญาตให้แอปพลิเคชันส่งการกระจายข้อมูลที่ติดหนึบ ซึ่งจะยังคงอยู่หลังจากการกระจายข้อมูลจบไปแล้ว การใช้งานมากเกินไปอาจทำให้โทรศัพท์ทำงานช้าลงหรือไม่เสถียรโดยการใช้หน่วยความจำมากเกินไป"</string>
<string name="permlab_readContacts" msgid="8348481131899886131">"อ่านผู้ติดต่อของคุณ"</string>
- <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"อนุญาตให้แอปพลิเคชันอ่านข้อมูลผู้ติดต่อที่จัดเก็บไว้ในแท็บเล็ต ซึ่งรวมถึงความถี่ในการโทร ส่งอีเมล หรือการติดต่อด้วยวิธีอื่นๆ กับบุคคลใดบุคคลหนึ่ง การอนุญาตนี้ทำให้แอปพลิเคชันสามารถบันทึกข้อมูลผู้ติดต่อของคุณ และแอปพลิเคชันที่เป็นอันตรายอาจแชร์ข้อมูลผู้ติดต่อโดยไม่แจ้งให้คุณทราบ"</string>
- <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"อนุญาตให้แอปพลิเคชันอ่านข้อมูลผู้ติดต่อที่จัดเก็บไว้ในโทรศัพท์ ซึ่งรวมถึงความถี่ในการโทร ส่งอีเมล หรือการติดต่อด้วยวิธีอื่นๆ กับบุคคลใดบุคคลหนึ่ง การอนุญาตนี้ทำให้แอปพลิเคชันสามารถบันทึกข้อมูลผู้ติดต่อของคุณ และแอปพลิเคชันที่เป็นอันตรายอาจแชร์ข้อมูลผู้ติดต่อโดยไม่แจ้งให้คุณทราบ"</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"อนุญาตให้แอปพลิเคชันอ่านข้อมูลผู้ติดต่อที่จัดเก็บไว้ในแท็บเล็ต ซึ่งรวมถึงความถี่ในการโทร ส่งอีเมล หรือการติดต่อด้วยวิธีอื่นๆ กับบุคคลใดบุคคลหนึ่ง การอนุญาตนี้ทำให้แอปพลิเคชันสามารถบันทึกข้อมูลผู้ติดต่อของคุณ และแอปพลิเคชันที่เป็นอันตรายอาจแบ่งปันข้อมูลผู้ติดต่อโดยไม่แจ้งให้คุณทราบ"</string>
+ <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"อนุญาตให้แอปพลิเคชันอ่านข้อมูลผู้ติดต่อที่จัดเก็บไว้ในโทรศัพท์ ซึ่งรวมถึงความถี่ในการโทร ส่งอีเมล หรือการติดต่อด้วยวิธีอื่นๆ กับบุคคลใดบุคคลหนึ่ง การอนุญาตนี้ทำให้แอปพลิเคชันสามารถบันทึกข้อมูลผู้ติดต่อของคุณ และแอปพลิเคชันที่เป็นอันตรายอาจแบ่งปันข้อมูลผู้ติดต่อโดยไม่แจ้งให้คุณทราบ"</string>
<string name="permlab_writeContacts" msgid="5107492086416793544">"แก้ไขผู้ติดต่อของคุณ"</string>
<string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"อนุญาตให้แอปพลิเคชันเปลี่ยนแปลงข้อมูลผู้ติดต่อที่จัดเก็บไว้ในแท็บเล็ต ซึ่งรวมถึงความถี่ในการโทร ส่งอีเมล หรือการติดต่อด้วยวิธีอื่นๆ กับบุคคลใดบุคคลหนึ่ง การอนุญาตนี้ทำให้แอปพลิเคชันสามารถลบข้อมูลผู้ติดต่อได้"</string>
<string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"อนุญาตให้แอปพลิเคชันเปลี่ยนแปลงข้อมูลผู้ติดต่อที่จัดเก็บไว้ในโทรศัพท์ ซึ่งรวมถึงความถี่ในการโทร ส่งอีเมล หรือการติดต่อด้วยวิธีอื่นๆ กับบุคคลใดบุคคลหนึ่ง การอนุญาตนี้ทำให้แอปพลิเคชันสามารถลบข้อมูลผู้ติดต่อได้"</string>
<string name="permlab_readCallLog" msgid="3478133184624102739">"อ่านประวัติการโทร"</string>
- <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"อนุญาตให้แอปพลิเคชันอ่านบันทึกการโทรของแท็บเล็ต ซึ่งรวมถึงข้อมูลเกี่ยวกับการโทรเข้าและโทรออก การอนุญาตนี้ทำให้แอปพลิเคชันสามารถบันทึกข้อมูลบันทึกการโทรของคุณได้ และแอปพลิเคชันที่เป็นอันตรายอาจแชร์ข้อมูลบันทึกการโทรนี้โดยไม่แจ้งให้คุณทราบ"</string>
- <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"อนุญาตให้แอปพลิเคชันอ่านบันทึกการโทรของโทรศัพท์ ซึ่งรวมถึงข้อมูลเกี่ยวกับการโทรเข้าและโทรออก การอนุญาตนี้ทำให้แอปพลิเคชันสามารถบันทึกข้อมูลบันทึกการโทรของคุณได้ และแอปพลิเคชันที่เป็นอันตรายอาจแชร์ข้อมูลบันทึกการโทรนี้โดยไม่แจ้งให้คุณทราบ"</string>
+ <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"อนุญาตให้แอปพลิเคชันอ่านบันทึกการโทรของแท็บเล็ต ซึ่งรวมถึงข้อมูลเกี่ยวกับการโทรเข้าและโทรออก การอนุญาตนี้ทำให้แอปพลิเคชันสามารถบันทึกข้อมูลบันทึกการโทรของคุณได้ และแอปพลิเคชันที่เป็นอันตรายอาจแบ่งปันข้อมูลบันทึกการโทรนี้โดยไม่แจ้งให้คุณทราบ"</string>
+ <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"อนุญาตให้แอปพลิเคชันอ่านบันทึกการโทรของโทรศัพท์ ซึ่งรวมถึงข้อมูลเกี่ยวกับการโทรเข้าและโทรออก การอนุญาตนี้ทำให้แอปพลิเคชันสามารถบันทึกข้อมูลบันทึกการโทรของคุณได้ และแอปพลิเคชันที่เป็นอันตรายอาจแบ่งปันข้อมูลบันทึกการโทรนี้โดยไม่แจ้งให้คุณทราบ"</string>
<string name="permlab_writeCallLog" msgid="8552045664743499354">"เขียนประวัติการโทร"</string>
<string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"อนุญาตให้แอปแก้ไขประวัติการโทรจากแท็บเล็ตของคุณ รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและการโทรออก แอปที่เป็นอันตรายอาจใช้สิ่งนี้เพื่อลบหรือแก้ไขประวัติการโทรของคุณ"</string>
<string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"อนุญาตให้แอปแก้ไขประวัติการโทรจากโทรศัพท์ของคุณ รวมถึงข้อมูลเกี่ยวกับสายเรียกเข้าและการโทรออก แอปที่เป็นอันตรายอาจใช้สิ่งนี้เพื่อลบหรือแก้ไขประวัติการโทรของคุณ"</string>
@@ -486,15 +462,13 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"อนุญาตให้แอปพลิเคชันอ่านข้อมูลส่วนตัวในโปรไฟล์ที่จัดเก็บไว้ในอุปกรณ์ของคุณ เช่น ชื่อและข้อมูลติดต่อของคุณ ซึ่งหมายความว่าแอปพลิเคชันสามารถระบุตัวคุณและอาจส่งข้อมูลโปรไฟล์ของคุณให้ผู้อื่น"</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"แก้ไขบัตรผู้ติดต่อของคุณเอง"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"อนุญาตให้แอปพลิเคชันเปลี่ยนแปลงหรือเพิ่มข้อมูลโปรไฟล์ส่วนตัวที่จัดเก็บไว้บนอุปกรณ์ของคุณ เช่น ชื่อและข้อมูลติดต่อ ซึ่งหมายความว่าแอปพลิเคชันจะสามารถระบุตัวตนของคุณและส่งข้อมูลโปรไฟล์ของคุณให้แก่ผู้อื่นได้"</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"เซ็นเซอร์ร่างกาย (เช่น วัดอัตราการเต้นของหัวใจ)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"ช่วยให้แอปสามารถเข้าถึงข้อมูลจากเซ็นเซอร์ที่คุณใช้เพื่อวัดความเป็นไปภายในร่างกายของคุณ เช่น อัตราการเต้นของหัวใจ"</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"อ่านสตรีมเครือข่ายสังคม"</string>
- <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"อนุญาตให้แอปพลิเคชันเข้าถึงและซิงค์การอัปเดตทางสังคมจากคุณและเพื่อน โปรดแชร์ข้อมูลอย่างระมัดระวังเนื่องจากการอนุญาตนี้ทำให้แอปพลิเคชันสามารถอ่านการติดต่อระหว่างคุณและเพื่อนในเครือข่ายสังคมได้ ไม่ว่าจะมีการรักษาข้อมูลที่เป็นความลับแบบใดก็ตาม หมายเหตุ: การอนุญาตนี้อาจไม่สามารถใช้งานได้กับทุกเครือข่ายสังคม"</string>
+ <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"อนุญาตให้แอปพลิเคชันเข้าถึงและซิงค์การอัปเดตทางสังคมจากคุณและเพื่อน โปรดแบ่งปันข้อมูลอย่างระมัดระวังเนื่องจากการอนุญาตนี้ทำให้แอปพลิเคชันสามารถอ่านการติดต่อระหว่างคุณและเพื่อนในเครือข่ายสังคมได้ ไม่ว่าจะมีการรักษาข้อมูลที่เป็นความลับแบบใดก็ตาม หมายเหตุ: การอนุญาตนี้อาจไม่สามารถใช้งานได้กับทุกเครือข่ายสังคม"</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"เขียนในสตรีมเครือข่ายสังคม"</string>
- <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"อนุญาตให้แอปพลิเคชันแสดงการอัปเดตทางสังคมจากเพื่อนของคุณ โปรดแชร์ข้อมูลอย่างระมัดระวังเนื่องจากการอนุญาตนี้ทำให้แอปพลิเคชันสามารถสร้างข้อความที่ดูเหมือนมาจากเพื่อนได้ หมายเหตุ: การอนุญาตนี้อาจไม่สามารถใช้ได้กับทุกเครือข่ายสังคม"</string>
+ <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"อนุญาตให้แอปพลิเคชันแสดงการอัปเดตทางสังคมจากเพื่อนของคุณ โปรดแบ่งปันข้อมูลอย่างระมัดระวังเนื่องจากการอนุญาตนี้ทำให้แอปพลิเคชันสามารถสร้างข้อความที่ดูเหมือนมาจากเพื่อนได้ หมายเหตุ: การอนุญาตนี้อาจไม่สามารถใช้ได้กับทุกเครือข่ายสังคม"</string>
<string name="permlab_readCalendar" msgid="5972727560257612398">"อ่านกิจกรรมบนปฏิทินรวมถึงข้อมูลที่เป็นความลับ"</string>
- <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"อนุญาตให้แอปพลิเคชันอ่านกิจกรรมในปฏิทินทั้งหมดที่จัดเก็บไว้ในแท็บเล็ตของคุณ ซึ่งรวมถึงกิจกรรมของเพื่อนหรือเพื่อนร่วมงานด้วย ซึ่งอาจทำให้แอปพลิเคชันสามารถแชร์หรือบันทึกข้อมูลในปฏิทินของคุณได้ไม่ว่าจะมีการรักษาข้อมูลที่เป็นความลับหรือหรือข้อมูลที่อ่อนไหวแบบใดก็ตาม"</string>
- <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"อนุญาตให้แอปพลิเคชันอ่านกิจกรรมในปฏิทินทั้งหมดที่จัดเก็บไว้ในโทรศัพท์ของคุณ ซึ่งรวมถึงกิจกรรมของเพื่อนหรือเพื่อนร่วมงานด้วย ซึ่งอาจทำให้แอปพลิเคชันสามารถแชร์หรือบันทึกข้อมูลในปฏิทินของคุณได้ไม่ว่าจะมีการรักษาข้อมูลที่เป็นความลับหรือหรือข้อมูลที่อ่อนไหวแบบใดก็ตาม"</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"อนุญาตให้แอปพลิเคชันอ่านกิจกรรมในปฏิทินทั้งหมดที่จัดเก็บไว้ในแท็บเล็ตของคุณ ซึ่งรวมถึงกิจกรรมของเพื่อนหรือเพื่อนร่วมงานด้วย ซึ่งอาจทำให้แอปพลิเคชันสามารถแบ่งปันหรือบันทึกข้อมูลในปฏิทินของคุณได้ไม่ว่าจะมีการรักษาข้อมูลที่เป็นความลับหรือหรือข้อมูลที่อ่อนไหวแบบใดก็ตาม"</string>
+ <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"อนุญาตให้แอปพลิเคชันอ่านกิจกรรมในปฏิทินทั้งหมดที่จัดเก็บไว้ในโทรศัพท์ของคุณ ซึ่งรวมถึงกิจกรรมของเพื่อนหรือเพื่อนร่วมงานด้วย ซึ่งอาจทำให้แอปพลิเคชันสามารถแบ่งปันหรือบันทึกข้อมูลในปฏิทินของคุณได้ไม่ว่าจะมีการรักษาข้อมูลที่เป็นความลับหรือหรือข้อมูลที่อ่อนไหวแบบใดก็ตาม"</string>
<string name="permlab_writeCalendar" msgid="8438874755193825647">"เพิ่มหรือแก้ไขกิจกรรมบนปฏิทินและส่งอีเมลให้ผู้เข้าร่วมโดยที่เจ้าของไม่ทราบ"</string>
<string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"อนุญาตให้แอปพลิเคชันเพิ่ม ลบ เปลี่ยนกิจกรรมที่คุณสามารถเปลี่ยนแปลงในแท็บเล็ตได้ รวมถึงกิจกรรมของเพื่อนหรือเพื่อนร่วมงานด้วย การอนุญาตนี้อาจทำให้แอปพลิเคชันสามารถส่งข้อความที่มาจากเจ้าของปฏิทิน หรือเปลี่ยนแปลงกิจกรรมโดยที่เจ้าของไม่ทราบ"</string>
<string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"อนุญาตให้แอปพลิเคชันเพิ่ม ลบ เปลี่ยนกิจกรรมที่คุณสามารถเปลี่ยนแปลงในโทรศัพท์ได้ รวมถึงกิจกรรมของเพื่อนหรือเพื่อนร่วมงานด้วย การอนุญาตนี้อาจทำให้แอปพลิเคชันสามารถส่งข้อความที่มาจากเจ้าของปฏิทิน หรือเปลี่ยนแปลงกิจกรรมโดยที่เจ้าของไม่ทราบ"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"อนุญาตให้แอปพลิชันควบคุมคุณลักษณะโทรศัพท์ของอุปกรณ์ แอปพลิเคชันที่ได้รับอนุญาตจะสามารถสลับเครือข่าย เปิดและปิดวิทยุในโทรศัพท์ และคุณลักษณะอื่นที่คล้ายกันนี้ได้โดยไม่ต้องแจ้งให้คุณทราบ"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"อ่านสถานะและข้อมูลระบุตัวตนของโทรศัพท์"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"อนุญาตให้แอปพลิเคชันเข้าถึงคุณลักษณะโทรศัพท์ของอุปกรณ์ การอนุญาตนี้ทำให้แอปพลิเคชันสามารถตรวจสอบหมายเลขโทรศัพท์และรหัสอุปกรณ์ ตรวจสอบว่ามีการโทรที่ทำงานอยู่หรือไม่ และตรวจสอบหมายเลขระยะไกลที่เชื่อมต่อด้วยการโทร"</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"อ่านสถานะที่แม่นยำของโทรศัพท์"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"ช่วยให้แอปสามารถเข้าถึงสถานะที่แม่นยำของโทรศัพท์ สิทธิ์นี้ช่วยให้แอปสามารถทราบถึงสถานะการโทรที่แท้จริงว่ากำลังมีการโทรอยู่หรือการโทรในพื้นหลัง การโทรล้มเหลว สถานะการเชื่อมต่อข้อมูลที่แม่นยำและการเชื่อมต่อข้อมูลล้มเหลว"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ป้องกันไม่ให้แท็บเล็ตเข้าสู่โหมดสลีป"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ป้องกันไม่ให้โทรศัพท์เข้าโหมดสลีป"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"อนุญาตให้แอปพลิเคชันป้องกันไม่ให้แท็บเล็ตเข้าสู่โหมดสลีป"</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"เปลี่ยนสถานะของ WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"อนุญาตให้แอปพลิเคชันเชื่อมต่อและยกเลิกการเชื่อมต่อแท็บเล็ตกับเครือข่าย WiMAX"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"อนุญาตให้แอปพลิเคชันเชื่อมต่อและยกเลิกการเชื่อมต่อโทรศัพท์กับเครือข่าย WiMAX"</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ให้คะแนนเครือข่าย"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"อนุญาตให้แอปนี้จัดลำดับเครือข่าย ซึ่งมีผลต่อการเลือกใช้เครือข่ายของแท็บเล็ต"</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"อนุญาตให้แอปนี้จัดอันดับเครือข่ายและมีผลต่อการเลือกใช้เครือข่ายของโทรศัพท์"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"จับคู่กับอุปกรณ์บลูทูธ"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"อนุญาตให้แอปพลิเคชันดูการกำหนดค่าบลูทูธของแท็บเล็ต ตลอดจนเชื่อมต่อและยอมรับการเชื่อมต่อกับอุปกรณ์ที่จับคู่ไว้"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"อนุญาตให้แอปพลิเคชันดูการกำหนดค่าบลูทูธของโทรศัพท์ ตลอดจนเชื่อมต่อและยอมรับการเชื่อมต่อกับอุปกรณ์ที่จับคู่ไว้"</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"ทำให้แอปสามารถเรียกดู ตรวจสอบ และล้างการแจ้งเตือนได้ ซึ่งรวมถึงการแจ้งเตือนที่โพสต์โดยแอปอื่นๆ ด้วย"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"เชื่อมโยงกับบริการตัวฟังการแจ้งเตือน"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"อนุญาตให้เจ้าของเชื่อมโยงกับอินเตอร์เฟซระดับสูงสุดของบริการตัวฟังการแจ้งเตือน ซึ่งไม่มีความจำเป็นสำหรับแอปธรรมดา"</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"เชื่อมโยงกับบริการของผู้เสนอเงื่อนไข"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"อนุญาตให้ผู้ใช้อุปกรณ์เชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการของผู้เสนอเงื่อนไข ไม่จำเป็นสำหรับแอปทั่วไป"</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"เรียกใช้แอปการกำหนดค่าของผู้ให้บริการ"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"อนุญาตให้ผู้ใช้สามารถเรียกใช้แอปการกำหนดค่าของผู้ให้บริการ ซึ่งแอปทั่วไปไม่จำเป็นต้องใช้"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ฟังข้อสังเกตเกี่ยวกับสภาวะของเครือข่าย"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"อนุญาตให้แอปพลิเคชันฟังข้อสังเกตเกี่ยวกับสภาวะของเครือข่าย ไม่จำเป็นสำหรับแอปปกติ"</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"เปลี่ยนการเทียบมาตรฐานอุปกรณ์อินพุต"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"อนุญาตให้แอปสามารถปรับพารามิเตอร์การเทียบมาตรฐานของหน้าจอสัมผัส ไม่ควรใช้สำหรับแอปทั่วไป"</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"เข้าถึงใบรับรอง DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"ช่วยให้แอปพลิเคชันสามารถจัดสรรและใช้ใบรับรอง DRM ได้ ไม่จำเป็นสำหรับแอปปกติทั่วไป"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"ตั้งค่ากฎรหัสผ่าน"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"ควบคุมความยาวและอักขระที่อนุญาตให้ใช้ในรหัสผ่านการปลดล็อกหน้าจอ"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"ตรวจสอบความพยายามในการปลดล็อกหน้าจอ"</string>
@@ -962,7 +925,7 @@
<string name="hour_cap_ampm" msgid="2083465992940444366">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<string name="factorytest_failed" msgid="5410270329114212041">"การทดสอบจากโรงงานล้มเหลว"</string>
<string name="factorytest_not_system" msgid="4435201656767276723">"การทำงาน FACTORY_TEST ได้รับการสนับสนุนเฉพาะสำหรับแพ็คเก็จที่ติดตั้งใน /system/app เท่านั้น"</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"ไม่พบแพ็กเกจที่มีการทำงาน FACTORY_TEST"</string>
+ <string name="factorytest_no_action" msgid="872991874799998561">"ไม่พบแพคเกจที่มีการทำงาน FACTORY_TEST"</string>
<string name="factorytest_reboot" msgid="6320168203050791643">"รีบูต"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"หน้าเว็บที่ \"<xliff:g id="TITLE">%s</xliff:g>\" ระบุว่า:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
@@ -1001,10 +964,10 @@
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"อนุญาตให้แอปพลิเคชันเพิ่มข้อความลงในกล่องข้อความเสียงของคุณ"</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"แก้ไขการอนุญาตเกี่ยวกับการระบุตำแหน่งทางภูมิศาสตร์ของเบราว์เซอร์"</string>
<string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"อนุญาตให้แอปพลิเคชันแก้ไขการอนุญาตตำแหน่งทางภูมิศาสตร์ของเบราว์เซอร์ แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ในการส่งข้อมูลตำแหน่งไปยังเว็บไซต์ต่างๆ ได้ตามต้องการ"</string>
- <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"ยืนยันแพ็กเกจ"</string>
- <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"อนุญาตให้แอปพลิเคชันยืนยันว่าแพ็กเกจสามารถติดตั้งได้หรือไม่"</string>
- <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"เชื่อมโยงกับการยืนยันแพ็กเกจ"</string>
- <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"อนุญาตให้ผู้ใช้ส่งคำขอให้มีการยืนยันแพ็กเกจ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+ <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"ยืนยันแพคเกจ"</string>
+ <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"อนุญาตให้แอปพลิเคชันยืนยันว่าแพคเกจสามารถติดตั้งได้หรือไม่"</string>
+ <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"เชื่อมโยงกับการยืนยันแพคเกจ"</string>
+ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"อนุญาตให้ผู้ใช้ส่งคำขอให้มีการยืนยันแพคเกจ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="permlab_serialPort" msgid="546083327654631076">"เข้าถึงพอร์ตอนุกรม"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"อนุญาตให้ผู้ถือสามารถเข้าถึงพอร์ตอนุกรมโดยใช้ SerialManager API"</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"เข้าถึงผู้ให้บริการเนื้อหาจากภายนอก"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"อนุญาตให้แอปพลิเคชันเข้าถึงพื้นที่จัดเก็บที่รักษาความปลอดภัยด้วยคีย์การ์ด"</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"ควบคุมการแสดงผลและการซ่อนตัวล็อกปุ่มกด"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"อนุญาตให้แอปพลิเคชันควบคุมตัวล็อกปุ่มกด"</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"ฟังการเปลี่ยนแปลงของสถานะความน่าเชื่อถือ"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"อนุญาตให้แอปพลิเคชันฟังการเปลี่ยนแปลงที่มีต่อสถานะความน่าเชื่อถือ"</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ผูกกับบริการของตัวแทนที่เชื่อถือได้"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"อนุญาตให้แอปพลิเคชันผูกกับบริการของตัวแทนที่เชื่อถือได้"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"โต้ตอบกับการอัปเดตและระบบการกู้คืน"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"ช่วยให้แอปพลิเคชันสามารถโต้ตอบกับระบบการกู้คืนและการอัปเดตระบบ"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"แตะสองครั้งเพื่อควบคุมการซูม"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"วอลเปเปอร์"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"เปลี่ยนวอลเปเปอร์"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ตัวฟังการแจ้งเตือน"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ผู้เสนอเงื่อนไข"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN เปิดใช้งานแล้ว"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"เปิดใช้งาน VPN โดย <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"แตะเพื่อจัดการเครือข่าย"</string>
@@ -1403,7 +1361,7 @@
<string name="car_mode_disable_notification_message" msgid="8035230537563503262">"แตะเพื่อออกจากโหมดรถยนต์"</string>
<string name="tethered_notification_title" msgid="3146694234398202601">"การปล่อยสัญญาณหรือฮอตสปอตทำงานอยู่"</string>
<string name="tethered_notification_message" msgid="6857031760103062982">"แตะเพื่อตั้งค่า"</string>
- <string name="back_button_label" msgid="2300470004503343439">"กลับ"</string>
+ <string name="back_button_label" msgid="2300470004503343439">"ย้อนกลับ"</string>
<string name="next_button_label" msgid="1080555104677992408">"ถัดไป"</string>
<string name="skip_button_label" msgid="1275362299471631819">"ข้าม"</string>
<string name="throttle_warning_notification_title" msgid="4890894267454867276">"การใช้งานข้อมูลมือถือในระดับสูง"</string>
@@ -1430,7 +1388,7 @@
<string name="media_shared" product="nosdcard" msgid="5830814349250834225">"ขณะนี้ที่เก็บข้อมูล USB ถูกใช้งานอยู่โดยคอมพิวเตอร์"</string>
<string name="media_shared" product="default" msgid="5706130568133540435">"ขณะนี้การ์ด SD มีการใช้งานอยู่โดยคอมพิวเตอร์"</string>
<string name="media_unknown_state" msgid="729192782197290385">"สื่อภายนอกอยู่ในสถานะที่ไม่รู้จัก"</string>
- <string name="share" msgid="1778686618230011964">"แชร์"</string>
+ <string name="share" msgid="1778686618230011964">"แบ่งปัน"</string>
<string name="find" msgid="4808270900322985960">"ค้นหา"</string>
<string name="websearch" msgid="4337157977400211589">"ค้นเว็บ"</string>
<string name="find_next" msgid="5742124618942193978">"ค้นหาถัดไป"</string>
@@ -1473,8 +1431,8 @@
<string name="keyboardview_keycode_enter" msgid="2985864015076059467">"ป้อน"</string>
<string name="activitychooserview_choose_application" msgid="2125168057199941199">"เลือกแอปพลิเคชัน"</string>
<string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"ไม่สามารถเปิด <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
- <string name="shareactionprovider_share_with" msgid="806688056141131819">"แชร์กับ"</string>
- <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"แชร์ด้วย <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="shareactionprovider_share_with" msgid="806688056141131819">"แบ่งปันกับ"</string>
+ <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"แบ่งปันด้วย <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"ที่จับสำหรับเลื่อน แตะค้างไว้"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"กวาดเพื่อปลดล็อก"</string>
<string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"เสียบชุดหูฟังเพื่อฟังเสียงเมื่อพิมพ์รหัสผ่าน"</string>
@@ -1518,7 +1476,7 @@
<string name="sha1_fingerprint" msgid="7930330235269404581">"ลายนิ้วมือ SHA-1"</string>
<string name="activity_chooser_view_see_all" msgid="4292569383976636200">"ดูทั้งหมด"</string>
<string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"เลือกกิจกรรม"</string>
- <string name="share_action_provider_share_with" msgid="5247684435979149216">"แชร์กับ"</string>
+ <string name="share_action_provider_share_with" msgid="5247684435979149216">"แบ่งปันกับ"</string>
<string name="list_delimeter" msgid="3975117572185494152">", "</string>
<string name="sending" msgid="3245653681008218030">"กำลังส่ง…"</string>
<string name="launchBrowserDefault" msgid="2057951947297614725">"เปิดเบราว์เซอร์หรือไม่"</string>
@@ -1705,7 +1663,7 @@
<item quantity="other" msgid="4730868920742952817">"ลองอีกใน <xliff:g id="COUNT">%d</xliff:g> วินาที"</item>
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"ลองอีกครั้งในภายหลัง"</string>
- <string name="immersive_mode_confirmation" msgid="7227416894979047467">"กวาดนิ้วบนลงล่างเพื่อออกจากโหมดเต็มหน้าจอ"</string>
+ <string name="immersive_mode_confirmation" msgid="7227416894979047467">"กวาดนิ้วจากบนลงล่างเพื่อออกจากโหมดเต็มหน้าจอ"</string>
<string name="done_label" msgid="2093726099505892398">"เสร็จสิ้น"</string>
<string name="hour_picker_description" msgid="6698199186859736512">"ตัวเลื่อนหมุนระบุชั่วโมง"</string>
<string name="minute_picker_description" msgid="8606010966873791190">"ตัวเลื่อนหมุนระบุนาที"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 969b651..4196a82 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> (na) araw"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> day <xliff:g id="HOURS">%2$d</xliff:g> hr"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> day <xliff:g id="HOURS">%2$d</xliff:g> hr"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> (na) oras"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> oras <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> oras <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> (na) min"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> seg"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> seg"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> (na) seg"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> (na) seg"</string>
<string name="untitled" msgid="4638956954852782576">"<Walang pamagat>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"I-sync"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Masyadong maraming pagtanggal ng <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Puno na ang storage ng tablet. Magtanggal ng ilang file upang magbakante ng espasyo."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Puno na ang storage ng relo. Magtanggal ng ilang file upang magbakante ng espasyo."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Puno na ang storage ng telepono. Magtanggal ng ilang file upang magbakante ng espasyo."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Maaaring sinusubaybayan ang network"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Ng isang di-kilalang third party"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"I-on ang ringer"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Nagsa-shut down…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Mag-shut down ang iyong tablet."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Magsa-shut down ang iyong relo."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Magsa-shut down ang iyong telepono."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Nais mo bang mag-shut down?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Mag-reboot sa safe mode"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Airplane mode"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Naka-ON ang airplane mode"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Naka-OFF ang airplane mode"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Mga Setting"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Mga serbisyong ginagastusan mo"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Gumawa ng mga bagay na magpapagastos sa iyo."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Iyong mga mensahe"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"i-uninstall ang mga shortcut"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Pinapayagan ang application na alisin ang mga shortcut ng Homescreen nang walang panghihimasok ng user."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"baguhin ang ruta ng mga papalabas na tawag"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Pinapayagan ang app na makita ang numerong idina-dial sa isang papalabas na tawag na may opsyon na i-redirect ang tawag sa ibang numero o itigil ang tawag nang tuluyan."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Pinapayagan ang app na magproseso ng mga papalabas na tawag at baguhin ang numerong ida-dial. Pinapayagan ng pahintulot na ito ang app na sumubaybay, mag-redirect, o pumigil ng mga papalabas na tawag."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"tumanggap ng mga text message (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Pinapayagan ang app na tumanggap at magproseso ng mga mensaheng SMS. Nangangahulugan ito na maaaring sumubaybay o magtanggal ang app ng mga mensaheng ipinapadala sa iyong device nang hindi ipinapakita ang mga ito sa iyo."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"tumanggap ng mga text message (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Pinapayagan ang app na bawiin ang nilalaman ng aktibong window. Maaaring bawiin ng nakakahamak na apps ang kabuuang nilalaman ng window at suriin ang lahat ng teksto nito maliban sa mga password."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"pansamantalang paganahin ang accessibility"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Nagbibigay-daan sa isang application na pansamantalang paganahin ang accessibility sa device. Maaaring paganahin ng nakakahamak na apps ang accessibility nang walang pahintulot ng user."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"kunin ang token ng window"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Nagbibigay-daan sa isang application upang makuha ang token ng window. Maaaring magsagawa ng hindi pinapahintulutang pakikipag-ugnayan ang mga nakakahamak na app sa window ng application nang nagkukunwari bilang ang system."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"kunin ang mga istatistika ng frame"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Nagbibigay-daan sa isang application upang mangolekta ng mga istatistika ng frame. Maaaring mag-obserba ng mga window mula sa ibang mga app ang mga nakakahamak na app."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"kunin ang impormasyon ng window"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Pinapayagan ang application na kumuha ng impormasyon tungkol sa mga window mula sa tagapamahala ng window. Maaaring kumuha ang mga nakakahamak na app ng impormasyong nilayon para sa panloob na paggamit ng system."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"i-filter ang mga kaganapan"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Pinapayagan ang isang application na magrehistro ng filter ng input na nagpi-filter sa stream ng lahat ng kaganapan ng user bago maipadala ang mga iyon. Maaaring kontrolin ng nakakahamak na app ang system UI nang hindi nakikialam ang user."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"i-magnify ang display"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Pinapayagan ang isang application na i-magnify ang nilalaman ng isang display. Maaaring ibahin ng nakakahamak na apps ang nilalaman ng display sa paraang nagre-render sa device na hindi kapaki-pakinabang."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"bahagyang pag-shutdown"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Inilalagay ang tagapamahala ng aktibidad sa katayuan ng pag-shutdown. Hindi nagsasagawa ng kumpletong pag-shutdown."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"pigilan ang mga paglipat ng app"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Pinapayagan ang app na mag-broadcast ng isang notification na natanggap ang isang mensaheng SMS. Maaari itong gamitin ng nakakahamak na apps upang dayain ang papasok na mga mensaheng SMS."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ipadala ang WAP-PUSH-natanggap na pag-broadcast"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Pinapayagan ang app na mag-broadcast ng isang notification na natanggap ang isang mensaheng WAP PUSH. Maaari itong gamitin ng nakakahamak na apps upang dayain ang pagtanggap ng mensaheng MMS o upang tahimik na palitan ang nilalaman ng anumang webpage ng mga nakakahamak na variant."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"magpadala ng broadcast ng mga network ng score"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Nagbibigay-daan sa app na mag-broadcast ng notification na kailangang ma-score ng mga network. Hindi kailanman kinakailangan para sa mga normal na app."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitahan ang numero ng mga tumatakbong proseso"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Pinapayagan ang app na kontrolin ang maximum na bilang ng mga proseso na tatakbo. Hindi kailanman kinakailangan para sa normal na apps."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"pwersahin ang mga app sa background na magsara"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng serbisyo ng Vpn. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"sumailalim sa wallpaper"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng isang wallpaper. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"i-bind sa isang voice interactor"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Nagbibigay-daan sa may-hawak na i-bind ang top-level na interface ng isang serbisyo sa pakikipag-ugnayan gamit ang boses. Hindi kailanman dapat kailanganin ng mga normal na app."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"magpasaklaw sa isang remote na display"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Binibigyang-daan ang may-hawak na masaklaw ang pinakamataas na antas ng interface ng isang remote na display. Hindi dapat kailanman kailanganin ng normal na apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"itali sa serbisyo ng widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng serbisyo ng widget. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"mag-bind sa isang serbisyo ng route provider"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Nagbibigay-daan sa may-pahintulot na mag-bind sa anumang nakarehistrong route provider. Hindi dapat kailanganin kailanman ng mga normal na app."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"makipag-ugnay sa tagapangasiwa ng device"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Pinapayagan ang mga may-ari na magpadala ng mga layunin sa administrator ng device. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"i-bind sa isang TV input"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Pinapayagan ang may-hawak na mag-bind sa top-level na interface ng isang TV input. Hindi kailanman kakailanganin ng mga normal na app."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"magdagdag o mag-alis ng admin ng device"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Pinapayagan ang may-ari na magdagdag o mag-alis ng mga aktibong administrator ng device. Hindi dapat kailanganin kailanman para sa normal na apps."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"baguhin ang orientation ng screen"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Pinapayagan ang app na gumamit ng anumang naka-install na media decoder upang mag-decode para sa pag-playback."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"mga pinamamahalaang pinagkakatiwalaang kredensyal"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Pinapayagan ang app na mag-install at mag-uninstall ng mga CA certificate bilang mga pinagkakatiwalaang kredensyal."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"paganahin ang application habang idle"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Nagbibigay-daan ang pahintulot na ito sa Android system na paganahin ang application sa background habang hindi ginagamit ang device."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"sumailalim sa mga idle na serbisyo"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Nagbibigay-daan ang pahintulot na ito sa Android system na sumailalim sa mga idle na serbisyo ng isang application."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"magbasa/magsulat sa mga mapagkukunang pag-aari ng diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Pinapayagan ang app na magbasa at magsulat sa anumang mapagkukunang pag-aari ng pangkat ng diag; halimbawa, mga file sa /dev. Maaaring potensyal na maapektuhan nito ang katatagan at seguridad ng system. Dapat LAMANG itong gamitin para sa diagnostics na tukoy sa hardware ng tagagawa o operator."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"paganahin o huwag paganahin ang mga bahagi ng app"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Pinapayagan ang app na basahin ang personal na impormasyon ng profile na naka-imbak sa iyong device, gaya ng iyong pangalan at impormasyon sa pakikipag-ugnay. Nangangahulugan ito na makikilala ka ng app at maaari nitong ipadala ang impormasyon ng iyong profile sa iba."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"baguhin sarili mo contact card"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Pinapayagan ang app na baguhin ang o magdagdag sa personal na impormasyon ng profile na naka-imbak sa iyong device, gaya ng iyong pangalan at impormasyon sa pakikipag-ugnay. Nangangahulugan ito na makikilala ka ng app at maaari nitong ipadala ang impormasyon ng iyong profile sa iba."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"mga sensor sa katawan (gaya ng mga heart rate monitor)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Pinapayagan ang app na i-access ang data mula sa mga sensor na ginagamit mo upang sukatin kung anong nangyayari sa iyong katawan, gaya ng heart rate."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"basahin ang iyong social stream"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Pinapayagan ang app na mag-access at mag-sync ng mga social na update mula sa iyo at sa iyong mga kaibigan. Maging maingat kapag nagbabahagi ng impormasyon -- pinapayagan nito ang app na magbasa ng mga pakikipag-ugnayan sa pagitan mo at ng iyong mga kaibigan sa mga social network, ano pa man ang katayuan sa pagiging kumpedensyal nito. Tandaan: hindi maaaring ipatupad ang pahintulot na ito sa lahat ng social network."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"magsulat sa iyong social stream"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Pinapayagan ang app na kontrolin ang mga tampok ng telepono ng device. Maaaring lumipat ng mga network ang isang app na mayroong ganitong pahintulot, i-on o i-off ang radyo ng telepono at mga kaparehong bagay nang hindi ka nano-notify."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"basahin ang katayuan at pagkakakilanlan ng telepono"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Pinapayagan ang app na i-access ang mga tampok ng telepono ng device. Pinapayagan ng pahintulot na ito ang app na tukuyin ang numero ng telepono at mga ID ng device, kung aktibo man ang isang tawag, at ang malayuang numerong ikinonekta ng isang tawag."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"basahin ang tiyak na katayuan ng telepono"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Binibigyang-daan ang app na ma-access ang tumpak na katayuan ng telepono. Nagbibigay-daan ang pahintulot na ito sa app na matukoy ang tunay na status ng tawag, kung aktibo ang isang tawag o nasa background, mga hindi natuloy na tawag, tumpak na status ng koneksyon sa data at hindi natuloy na pagkonekta sa data."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"pigilan ang tablet mula sa pag-sleep"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"pigilan ang telepono mula sa paghinto"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Pinapayagan ang app na pigilan ang tablet mula sa pag-sleep."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Baguhin ang katayuan ng WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Pinapayagan ang app na ikonekta ang tablet at idiskonekta ang tablet mula sa mga WiMAX network."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Pinapayagan ang app na ikonekta ang telepono at idiskonekta ang telepono mula sa mga WiMAX network."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"mga network ng score"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Nagbibigay-daan sa app na iranggo ang mga network at impluwensiyahan kung aling mga network ang dapat na piliin ng tablet."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Nagbibigay-daan sa app na iranggo ang mga network at impluwensiyahan kung aling mga network ang dapat na piliin ng telepono."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"ipares sa mga Bluetooth device"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Pinapayagan ang app na tingnan ang configuration ng Bluetooth sa tablet, at na gumawa at tumanggap ng mga koneksyong may mga nakapares na device."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Pinapayagan ang app na tingnan ang configuration ng Bluetooth sa telepono, at na gumawa at tumanggap ng mga koneksyong may mga nakapares na device."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Pinapayagan ang app na kumuha, sumuri, at mag-clear ng mga notification, kabilang ang mga na-post ng iba pang apps."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"mapailalim sa isang serbisyo ng notification listener"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Nagbibigay-daan sa may-ari na mapailalim sa interface sa tuktok na antas ng isang serbisyo ng notification listener. Hindi dapat kailanganin para sa karaniwang apps kahit kailan."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"i-bind sa isang serbisyo sa pagbibigay ng kundisyon"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Nagbibigay-daan sa naghahawak na i-bind ang top-level na interface ng isang serbisyo sa pagbibigay ng kundisyon. Hindi kailanman dapat kailanganin ng mga normal na app."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"paganahin ang app ng configuration na ibinigay ng carrier"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Nagbibigay-daan sa may-ari na paganahin ang app ng configuration na ibinigay ng carrier. Hindi dapat kailanganin para sa normal na apps kahit kailan."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"makinig sa mga obserbasyon sa mga kundisyon ng network"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Nagbibigay-daan sa isang application na makinig sa mga obserbasyon sa mga kundisyon ng network. Dapat na hindi kailanman kakailanganin para sa normal na apps."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"baguhin ang pag-calibrate ng input device"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Pinapayagan ang app na baguhin ang mga parameter sa pag-calibrate ng touch screen. Hindi dapat kailanganin sa normal na apps."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"access sa Mga DRM certificate"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Nagbibigay-daan sa isang application na makapagbigay at gumamit ng mga DRM certficate. Hindi dapat kailanman kailanganin para sa mga normal na app."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Magtakda ng mga panuntunan sa password"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolin ang haba at mga character na pinapayagan sa mga password sa pag-unlock ng screen."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Subaybayan ang mga pagsubok sa pag-unlock ng screen"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Nagbibigay-daan sa isang application na i-access ang secure na storage ng keyguard."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Kontrolin ang pagpapakita at pagtago sa keyguard"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Pinapayagan ang isang application na kontrolin ang keyguard."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Makinig sa mga pagbabago sa estado ng trust."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Pinapayagan ang isang application na makinig para sa mga pagbabago sa estado ng trust."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Sumailalim sa isang serbisyo ng trust agent"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Pinapayagan ang isang application na sumailalim sa isang serbisyo ng trust agent."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Makipag-ugnay sa system ng pag-update at pagbawi"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Binibigyang-daan ang isang application na makipag-ugnay sa system ng pagbawi at mga pag-update ng system."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Pindutin nang dalawang beses para sa pagkontrol ng zoom"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Baguhin ang wallpaper"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification listener"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Nagbibigay ng kundisyon"</string>
<string name="vpn_title" msgid="19615213552042827">"Naka-activate ang VPN"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Isinaaktibo ang VPN ng <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Pindutin upang pamahalaan ang network."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 6e6151f..132d9f0 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> gün"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> gün <xliff:g id="HOURS">%2$d</xliff:g> sa."</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> gün <xliff:g id="HOURS">%2$d</xliff:g> sa."</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> sa."</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> sa. <xliff:g id="MINUTES">%2$d</xliff:g> dk."</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> sa. <xliff:g id="MINUTES">%2$d</xliff:g> dk."</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> dk."</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> dk. <xliff:g id="SECONDS">%2$d</xliff:g> sn."</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> dk. <xliff:g id="SECONDS">%2$d</xliff:g> sn."</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sn."</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sn."</string>
<string name="untitled" msgid="4638956954852782576">"<Adsız>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Senk."</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Çok fazla <xliff:g id="CONTENT_TYPE">%s</xliff:g> silme var."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tabletin depolama alanı dolu! Yer açmak için bazı dosyaları silin."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Saat depolama alanınız dolu. Lütfen yer boşaltmak için bazı dosyaları silin."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefonun depolama alanı dolu! Yer açmak için bazı dosyaları silin."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Ağ izlenebilir"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Bunu, bilinmeyen üçüncü taraflar yapabilir"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Telefon zili açık"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Kapanıyor…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tabletiniz kapanacak."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Saatiniz kapatılacak."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefonunuz kapanacak."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Kapatmak istiyor musunuz?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Güvenli modda yeniden aç"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Uçak modu"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uçak modu AÇIK"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Uçak modu KAPALI"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Ayarlar"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Size maliyet getiren hizmetler"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Size maliyet getirebilecek işlemler yapma."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Mesajlarınız"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"kısayolların yüklemesini kaldırma"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Uygulamaya, kullanıcının müdahalesi olmadan kısayolları Ana Ekrandan kaldırma izni verir."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"giden çağrıları yeniden yönlendir"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Uygulamaya, giden bir çağrının numarası çevrilirken çağrıyı farklı bir numaraya yönlendirme ya da tamamen kapatma seçeneğiyle birlikte numarayı görme izni verir."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Uygulamaya, yapılan çağrıları işleme ve aranacak numarayı değiştirme izni verir. Bu izin, uygulamanın yapılan çağrıları izlemesine, yönlendirmesine ve önlemesine olanak sağlar."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"kısa mesajları al (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Uygulamaya SMS mesajlarını alma ve işleme izni verir. Bu izin, uygulamanın cihazınıza gönderilen mesajları takip edip size göstermeden silebileceği anlamına gelir."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"kısa mesajları (MMS) al"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Uygulamaya, etkin pencerenin içeriğini alma izni verir. Kötü amaçlı uygulamalar tüm pencere içeriğini alabilir ve şifreleri hariç tüm metni inceleyebilir."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"erişilebilirliği geçici olarak etkinleştir"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Uygulamaya, cihazda erişilebilirliği geçici olarak etkinleştirme izni verir. Kötü amaçlı uygulamalar, kullanıcının izni olmadan erişilebilirliği etkinleştirebilirler."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"pencere kodunu alma"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Bir uygulamanın pencere kodunu almasına izin verir. Zararlı uygulamalar, uygulama penceresi yerine geçme sistemiyle yetkisiz etkileşim gerçekleştirebilir."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"çerçeve istatistiklerini alma"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Bir uygulamanın çerçeve istatistikleri toplamasına izin verir. Zararlı uygulamalar, diğer uygulamalardan pencerelerin çerçeve istatistiklerini alabilirler."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"pencere bilgilerini al"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Uygulamaya, pencere yöneticisinden pencerelerle ilgili bilgi alma izni verir. Zararlı uygulamalar dahili sistem kullanımına yönelik bilgileri alabilir."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"etkinlikleri filtrele"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Uygulamaya, tüm kullanıcı etkinlikleri dağıtılmadan önce ilgili akışa filtre uygulayan bir giriş filtresi kaydetme izni verir. Zararlı uygulamalar kullanıcı müdahalesi olmadan sistem arayüzünü denetleyebilir."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"ekranı büyüt"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Uygulamaya bir ekranın içeriğini büyütme izni verir. Kötü amaçlı uygulamalar ekranın içeriğini etkileyerek cihazı kullanılmaz hale getirebilir."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"kısmi kapatma"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Eylem yöneticisini kapalı duruma getirir. Tam kapatma işlemi gerçekleştirmez."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"uygulama değişimlerini engelle"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Uygulamaya, SMS mesajı alındığına dair bildirim yayınlama izni verir. Kötü amaçlı uygulamalar sahte SMS mesajları göndermek için bunu kullanabilir."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH ile alınan yayın gönder"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Uygulamaya, WAP PUSH mesajı alındığına dair bildirim yayınlama izni verir. Kötü amaçlı uygulamalar sahte MMS bildirimleri oluşturmak veya bir web sayfasının içeriğini sessiz şekilde zararlı öğelerle değiştirmek için bunu kullanabilir."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ağları puanlama yayını gönderme"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Uygulamaya, ağların puanlanması gerektiği bildirimini yayınlama izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"çalışan işlem sayısını sınırla"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Uygulamaya, çalışacak süreçlerin azami sayısını denetleme izni verir. Normal uygulamalar için gerekli değildir."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"arka plan uygulamaları kapanmaya zorla"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Cihazın sahibine bir VPN hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"bir duvar kağıdına tabi kıl"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Cihazın sahibine, duvar kağıdının en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"bir ses etkileşimi hizmetine bağlanma"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"İzin sahibinin, bir ses etkileşimi hizmetine ait üst düzey arayüze bağlanmasına izin verir. Normal uygulamalar için hiçbir zaman gerekli değildir."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"uzak ekrana bağlan"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"İzin sahibine, bir uzak ekranın en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bir widget hizmetine bağla"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Cihazın sahibine bir widget hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"rota sağlayıcı hizmetine bağlanma"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"İzin verilen uygulamaya tüm kayıtlı rota sağlayıcılarına bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"bir cihaz yöneticisi ile etkileşimde bulun"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Cihazın sahibinin cihaz yöneticisine amaç göndermesine izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"TV girişine bağlanma"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"İzin sahibine, bir TV girişinin en üst düzey arayüzüne bağlanma olanağı verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"cihaz yöneticisi ekle veya kaldır"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"İzin sahibine, etkin cihaz yöneticileri ekleyip kaldırma izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"ekran yönünü değiştir"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Uygulamaya, oynatma kodunu çözmek için herhangi bir yüklü medya kod çözücüyü kullanma izni verir."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"güvenilen kimlik bilgilerini yönetme"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Uygulamaya, güvenilir kimlik bilgileri olarak CA sertifikaları yükleme veya sertifikaların yüklemelerini kaldırma izni verir."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"boşta kaldığında uygulamayı çalıştır"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Bu izin, cihaz kullanımda değilken Android sistemin uygulamayı arka planda çalıştırmasına olanak sağlar."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"boşta kalma hizmetlerine bağlan"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Bu izin, Android sistemin, bir uygulamanın boşta kalma hizmetlerine bağlanmasına olanak sağlar."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"sahibi tanılama olan kaynakları oku/bunlara yaz"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Uygulamaya, tanılama grubunun sahip olduğu tüm kaynaklara (örneğin /dev içindeki dosyalar) okuma ve yazma izni verir. Bu işlevin sistem kararlılığını ve güvenliğini olumsuz etkileme olasılığı vardır. Üretici veya operatör tarafından YALNIZCA donanıma özgü tanılama için kullanılmalıdır."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"uygulama bileşenlerini etkinleştir veya devre dışı bırak"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Uygulamaya adınız ve iletişim bilgileriniz gibi cihazınızda saklanan kişisel profil bilgilerini okuma izni verir. Bu izin, uygulamanın sizi tanımlayabileceği ve profil bilgilerinizi başkalarına gönderebileceği anlamına gelir."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"kendi kişi kartınızı değiştirme"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Uygulamaya adınız ve iletişim bilgileriniz gibi cihazınızda saklanan kişisel profil bilgilerini değiştirme veya bunlara ekleme yapma izni verir. Bu izin, uygulamanın sizi tanımlayabileceği ve profil bilgilerinizi başkalarına gönderebileceği anlamına gelir."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"vücut sensörleri (kalp atış hızı takip cihazları gibi)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Uygulamanın, kalp atış hızınız gibi vücudunuzla ilgili olayları ölçmek için kullandığınız sensörlerden gelen verilere erişmesine izin verir."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"sosyal akışınızı okuma"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Uygulamaya size veya arkadaşlarınıza ait sosyal güncellemelere erişme ve bunları senkronize etme izni verir. Bilgi paylaşırken dikkatli olun. Bu izin, uygulamanın sosyal ağlarda sizinle arkadaşlarınız arasındaki iletişimi, gizliliğine bakılmaksızın okumasına olanak sağlar. Not: Bu izin tüm sosyal ağlar için geçerli olmayabilir."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"sosyal akışınıza yazma"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Uygulamaya, cihazın telefon özelliklerini kontrol etme izni verir. Bu izne sahip bir uygulama sizi hiç uyarmadan ağlar arasında geçiş, telefonun radyosunu açıp kapatma ve benzeri işlemler yapabilir."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"telefonun durumunu ve kimliğini okuma"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Uygulamaya cihazdaki telefon özelliklerine erişme izni verir. Bu izin, uygulamanın telefon numarasını ve cihaz kimliğini, etkin bir çağrı olup olmadığını ve çağrıda bağlanılan karşı tarafın numarasını öğrenmesine olanak sağlar."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"telefon durum bilgilerini hassas bir şekilde oku"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Uygulamanın, telefonun durum bilgilerine hassas bir şekilde erişmesine izin verir. Bu izin sayesinde uygulama, gerçek çağrı durumunu, çağrının aktif mi yoksa arka planda mı olduğunu, çağrının başarısız olup olmadığını, veri bağlantısı durumuyla ilgili hassas bilgileri ve veri bağlantısının başarısız olup olmadığını belirleyebilir."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"tabletin uykuya geçmesini önle"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"telefonun uykuya geçmesini önleme"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Uygulamaya, tabletin uykuya geçmesini önleme izni verir."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX durumunu değiştir"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Uygulamaya, tableti WiMAX ağlarına bağlanma veya bağlantıyı kesme izni verir."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Uygulamaya, telefonu WiMAX ağlarına bağlanma veya bağlantıyı kesme izni verir."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ağları puanlama"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Uygulamaya, ağları sıralama ve tabletin tercih edeceği ağları etkileme izni verir."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Uygulamaya, ağları sıralama ve telefonunun tercih edeceği ağları etkileme izni verir."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetooth cihazlarla eşle"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Uygulamaya, tabletteki Bluetooth yapılandırmasını görüntüleme, eşleştirilmiş cihazlarla bağlantı yapma ve bu tür bağlantıları kabul etme izni verir."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Uygulamaya, telefondaki Bluetooth yapılandırmasını görüntüleme, eşleştirilmiş cihazlarla bağlantı yapma ve bu tür bağlantıları kabul etme izni verir."</string>
@@ -682,7 +651,7 @@
<string name="permdesc_readDictionary" msgid="659614600338904243">"Uygulamaya, kullanıcının kullanıcı sözlüğünde depolamış olabileceği kelimeleri, adları ve kelime öbeklerini okuma izni verir."</string>
<string name="permlab_writeDictionary" msgid="2183110402314441106">"kullanıcı tanımlı sözlüğe kelime ekle"</string>
<string name="permdesc_writeDictionary" msgid="8185385716255065291">"Uygulamaya, kullanıcı sözlüğüne yeni kelimeler yazma izni verir."</string>
- <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"USB belleğini okuma"</string>
+ <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"USB belleğimin içeriğini oku"</string>
<string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"SD kartımın içeriğini oku"</string>
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Uygulamaya, USB depolama biriminizin içeriğini okuma izni verir."</string>
<string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Uygulamaya, SD kartınızın içeriğini okuma izni verir."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Uygulamanın bildirimler almasına, bildirimleri incelemesine ve temizlemesine izin verir. Buna diğer uygulamalar tarafından yayınlanan bildirimler de dahildir."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bildirim dinleyici hizmetine bağlan"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"İzin sahibine bir bildirim dinleyici hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"bir durum sağlayıcı hizmetine bağlanma"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"İzin sahibinin, bir durum sağlayıcı hizmete ait üst düzey arayüze bağlanmasına izin verir. Normal uygulamalar için hiçbir zaman gerekli değildir."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"operatör tarafından sağlanan yapılandırma uygulamasını çalıştır"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"İzin sahibine, operatör tarafından sağlanan yapılandırma uygulamasını çalıştırma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ağ koşullarındaki gözlemleri dinle"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Bir uygulamaya, ağ koşullarındaki gözlemleri dinleme izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"giriş cihazı kalibrasyonunu değiştir"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Uygulamaya, dokunmatik ekranın kalibrasyon parametrelerini değiştirme izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM sertifikalarına eriş"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Bir uygulamanın DRM sertifikaları için temel hazırlık yapmasına ve bunları kullanmasına izin verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Şifre kuralları ayarla"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Ekran kilidini açma şifrelerinde izin verilen uzunluğu ve karakterleri denetleme."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Ekran kilidini açma denemelerini izle"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Bir uygulamanın tuş kilitli güvenli depolamaya erişimine izin verir."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Tuş koruyucuyu görüntülemeyi ve gizlemeyi kontrol et"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Bir uygulamaya tuş koruyucuyu denetleme izni verir."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Güven durumundaki değişiklileri dinle."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Bir uygulamanın, güven durumundaki değişiklikleri dinlemesine izin verir."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Güven aracı hizmetine bağlan"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Bir uygulamanın, güven aracı hizmetine bağlanmasına izin verir."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Güncelleme ve kurtarma sistemiyle etkileşim kur"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Bir uygulamaya, kurtarma sistemi ve sistem güncellemeriyle etkileşim kurma izni verir."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Yakınlaştırma denetimi için iki kez dokunun"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Duvar Kağıdı"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Duvar kağıdını değiştir"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Bildirim dinleyici"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Durum sağlayıcı"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN etkinleştirildi"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN, <xliff:g id="APP">%s</xliff:g> tarafından etkinleştirildi"</string>
<string name="vpn_text" msgid="3011306607126450322">"Ağı yönetmek için dokunun."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 63fdd15..857e339 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"Тб"</string>
<string name="petabyteShort" msgid="5637816680144990219">"Пб"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> дн."</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> день <xliff:g id="HOURS">%2$d</xliff:g> год"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> дн. <xliff:g id="HOURS">%2$d</xliff:g> год"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> год"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> год <xliff:g id="MINUTES">%2$d</xliff:g> хв"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> год <xliff:g id="MINUTES">%2$d</xliff:g> хв"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> хв"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> хв <xliff:g id="SECONDS">%2$d</xliff:g> с"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> хв <xliff:g id="SECONDS">%2$d</xliff:g> с"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> с"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> с"</string>
<string name="untitled" msgid="4638956954852782576">"<Без назви>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
@@ -146,9 +135,8 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синхр."</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Забагато видалень <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Пам’ять планшетного ПК заповнено. Видаліть якісь файли, щоб звільнити місце."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Пам’ять годинника заповнено. Видаліть файли, щоб звільнити місце."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Пам’ять телефону заповнено. Видаліть якісь файли, щоб звільнити місце."</string>
- <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мережа може відстежуватися"</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мережу можуть відстежувати"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Невідомою третьою стороною"</string>
<string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Доменом <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
<string name="me" msgid="6545696007631404292">"Я"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Дзвінок увімкнено"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Вимкнення..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Ваш пристрій буде вимкнено."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Годинник буде вимкнено."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Ваш телефон буде вимкнено."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Вимкнути?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Перейти в безпечний режим"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Режим польоту"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Режим польоту ВВІМК."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Режим польоту ВИМК."</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Налаштування"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Служби, які потребують оплати"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Виконувати дії, які потребують оплати."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Ваші повідомл."</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"видаляти ярлики"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Дозволяє програмі самостійно вилучати ярлики з головного екрана."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"переадресовувати вихідні виклики"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Дозволяє додатку читати номер вихідного дзвінка, переспрямовувати дзвінок на інший номер або переривати його."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Дозволяє програмі обробляти вихідні дзвінки та змінювати номер для виклику. Такий дозвіл дає програмі змогу відстежувати, переадресовувати чи блокувати вихідні дзвінки."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"отримувати текстові повідомлення (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Дозволяє програмі отримувати й обробляти SMS-повідомлення. Це означає, що програма може відстежувати чи видаляти повідомлення, надіслані на ваш пристрій, навіть не показуючи їх вам."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"отримувати текстові повідомлення (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Дозволяє програмі отримувати вміст активного вікна. Шкідливі програми можуть отримувати весь вміст вікна та вивчати весь його текст, окрім паролів."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"тимчасово вмикати доступність"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Дозволяє програмі тимчасового вмикати доступність на пристрої. Шкідливі програми можуть вмикати доступність без згоди користувача."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"отримувати маркер вікна"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Дозволяє додатку отримувати маркер вікна. Шкідливі додатки можуть без дозволу взаємодіяти з вікном додатка, видаючи себе за систему."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"отримувати статистику частоти кадрів"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Дозволяє додатку збирати статистику частоти кадрів. Шкідливі додатки можуть відстежувати частоту кадрів у вікнах інших додатків."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"отримувати інформацію про вікна"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Дозволяє програмі отримувати інформацію про вікна від диспетчера вікон. Шкідливі програми можуть отримувати інформацію, яка призначена для внутрішнього користування системи."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"фільтрувати події"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Дозволяє програмі реєструвати вхідний фільтр, який фільтрує потік усіх подій користувача перед їх надсиланням. Шкідливі програми можуть контролювати інтерфейс системи без втручання користувача."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"збільшити екран"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Дозволяє програмі збільшувати вміст екрана. Зловмисні програми можуть змінювати вміст екрана так, що пристроєм стає неможливо користуватися."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"частк. заверш. роб."</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Переводить диспетчер дій у стан завершення роботи. Не виконує повне завершення роботи."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"запобіг. зміні програм"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Дозволяє програмі передавати сповіщення про отримання SMS повідомлення. Шкідливі програми можуть використовувати це для підробки вхідних SMS повідомлень."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"надсил. запис, отр. через WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Дозволяє програмі передавати сповіщення про отримання повідомлення WAP PUSH. Шкідливі програми можуть використовувати це для підробки отримання MMS повідомлень або для непомітної заміни вмісту будь-якої веб-сторінки шкідливими варіантами."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"надсилати сповіщення про оцінку мереж"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Дозволяє додатку передавати сповіщення про оцінку мереж. Ніколи не застосовується для звичайних додатків."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"обмежувати кількість запущ. процесів"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Дозволяє програмі контролювати максимальну кількість процесів, які буде запущено. Ніколи не вимагається для звичайних програм."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"примусово закривати фонові програми"</string>
@@ -400,18 +382,14 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби VPN. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"прив’язати до фонового малюнка"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня фонового малюнка. Ніколи не застосовується для звичайних програм."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"підключитися до служби голосової взаємодії"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Додаток зможе підключатися до інтерфейсу верхнього рівня служби голосової взаємодії. Звичайні додатки ніколи не використовують цей дозвіл."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"прив’язуватися до віддаленого екрана"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня віддаленого екрана. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"прив\'язувати до служби віджетів"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби віджетів. Ніколи не застосовується для звичайних програм."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"підключитися до служби постачання маршрутів"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Дозволяє власникові підключатися до зареєстрованих постачальників маршрутів. Звичайні додатки ніколи не використовують цей дозвіл."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаємодіяти з адмін. пристрою"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Дозволяє власнику надсилати задавані функції адміністратору пристрою. Ніколи не застосовується для звичайних програм."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"підключатися до TV-входу"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Додаток зможе підключатися до інтерфейсу верхнього рівня TV-входу. Звичайні додатки ніколи не використовують цей дозвіл."</string>
+ <string name="permlab_bindTvInput" msgid="5601264742478168987">"прив’язуватися до вводу телевізора"</string>
+ <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня вводу телевізора. Ніколи не застосовується для звичайних додатків."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"додавати чи вилучати адміністраторів пристрою"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Дозволяє власнику додавати чи вилучати активних адміністраторів пристрою. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"змінювати орієнтацію екрана"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Дозволяє програмі використовувати будь-який установлений медіа-декодер для декодування з метою відтворення."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"керувати захищеними обліковими даними"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Дозволяє програмі встановлювати та видаляти сертифікати центру сертифікації (CA) як захищені облікові дані."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"запускати додаток, коли пристрій неактивний"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Маючи цей дозвіл, система Android може запускати додаток у фоновому режимі, коли пристрій не використовується."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"взаємодіяти з неактивними службами"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Такий дозвіл дає змогу системі Android прив’язуватися до неактивних служб програми."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"чит./зап. на ресури., якими вол. діаг."</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Дозволяє програмі читати та писати на будь-який ресурс, яким володіє діагностична група; наприклад, у файли в папці /dev. Це потенційно може вплинути на стабільність і безпеку системи. Потрібно використовувати ЛИШЕ для певної діагностики обладнання, яку виконує виробник чи оператор."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"вмикати чи вимикати компоненти програми"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Дозволяє програмі читати особисту інформацію профілю, збережену на пристрої, як-от ваше ім’я та контактну інформацію. Це означає, що програма може ідентифікувати вашу особу та надсилати дані вашого профілю іншим."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"змінювати картки контактів"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Дозволяє програмі змінювати чи додавати особисту інформацію профілю, збережену на пристрої, як-от ваше ім’я та контактну інформацію. Це означає, що програма може ідентифікувати вашу особу та надсилати дані вашого профілю іншим."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"датчики на тілі (як-от пульсометр)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Дозволяє додатку отримувати дані з датчиків, які вимірюють фізіологічні процеси, як-от пульс."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"читати ваш соціальний потік"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Дозволяє програмі отримувати доступ до оновлень із соціальних мереж від вас і ваших друзів та синхронізувати їх. Будьте обережні, надаючи доступ до інформації – це дозволяє програмі читати повідомлення, якими ви та ваші друзі обмінювалися в соціальних мережах, незалежно від конфіденційності. Зауважте: цей дозвіл не можна застосовувати в усіх соціальних мережах."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"писати у ваш соціальний потік"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Дозволяє програмі контролювати телефонні функції пристрою. Програма з цим дозволом може переключати мережі, вмикати та вимикати радіо в телефоні тощо без вашого відома."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"читати статус та ідентифікаційну інформацію телефону"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Дозволяє програмі отримувати доступ до телефонних функцій пристрою. Такий дозвіл дає програмі змогу визначати номер телефону й ідентифікатори пристрою, активність виклику, а також віддалений номер, на який здійснюється виклик."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"читати точні статуси телефону"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Дозволяє додатку отримувати доступ до статусів телефону. Цей дозвіл дає додатку змогу визначати статус виклику (активний чи у фоновому режимі), помилки викликів, точний статус передавання даних і помилки передавання даних."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"не доп.перехід пристр.в реж.сну"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"недоп. перехід тел. в реж. сну"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дозволяє програмі не допускати перехід планшетного ПК у режим сну."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Змінити стан WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Дозволяє програмі під’єднувати планшетний ПК до мереж WiMAX і від’єднувати його від них."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Дозволяє програмі під’єднувати телефон до мереж WiMAX і від’єднувати його від них."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"оцінювати мережі"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Дозволяє додатку оцінювати мережі та впливати на вибір мережі планшетом."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Дозволяє додатку оцінювати мережі та впливати на вибір мережі телефоном."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"створювати пару з пристроями Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Дозволяє програмі переглядати конфігурацію Bluetooth на планшетному ПК, а також створювати та приймати з’єднання зі спареними пристроями."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Дозволяє програмі переглядати конфігурацію Bluetooth на телефоні, а також створювати та приймати з’єднання зі спареними пристроями."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозволяє програмі отримувати, перевіряти й очищати сповіщення, зокрема опубліковані іншими програмами."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прив’язуватися до служби читання сповіщень"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня служби читання сповіщень. Ніколи не застосовується для звичайних програм."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"підключитися до служби постачання умов"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Додаток зможе підключатися до інтерфейсу верхнього рівня служби постачання умов. Звичайні додатки ніколи не використовують цей дозвіл."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"викликати надану оператором програму конфігурації"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозволяє власнику викликати надану оператором програму конфігурації. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"прослуховувати дані спостережень за станом мережі"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Дозволяє програмі прослуховувати дані спостережень за станом мережі. Ніколи не застосовується для звичайних програм."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"змінювати калібрування пристрою введення"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Програма може змінювати параметри калібрування сенсорного екрана. Ніколи не застосовується для звичайних програм."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"отримувати доступ до сертифікатів DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Дозволяє додатку надавати та використовувати сертифікати DRM. Ніколи не застосовується для звичайних додатків."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Устан. правила пароля"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролювати довжину паролів для розблокування екрана та дозволені в них символи."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Відстежув. спроби розблок. екрана"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Дозволяє програмі отримувати доступ до безпечного сховища через клавіатуру."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Керувати відображенням і хованням клавіатури"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Дозволяє програмі керувати клавіатурою."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Відстежувати зміни в стані довіри."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Дозволяє додатку відстежувати зміни в стані довіри."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Прив’язуватися до служби довірчих агентів"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Дозволяє додатку прив’язуватися до служби довірчих агентів."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Взаємодіяти з оновленнями системи та системою відновлення."</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Дозволяє додатку взаємодіяти із системою відновлення й оновленнями системи."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Двічі торкніться, щоб керувати масштабом"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновий мал."</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Змінити фоновий малюнок"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба читання сповіщень"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Постачальник умов"</string>
<string name="vpn_title" msgid="19615213552042827">"Мережу VPN активовано"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Мережу VPN активовано програмою <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Торкніться, щоб керувати мережею."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 545b92e..e774e8e 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> ngày"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> ngày <xliff:g id="HOURS">%2$d</xliff:g> giờ"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> ngày <xliff:g id="HOURS">%2$d</xliff:g> giờ"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> giờ"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> giờ <xliff:g id="MINUTES">%2$d</xliff:g> phút"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> giờ <xliff:g id="MINUTES">%2$d</xliff:g> phút"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> phút"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> phút <xliff:g id="SECONDS">%2$d</xliff:g> giây"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> phút <xliff:g id="SECONDS">%2$d</xliff:g> giây"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> giây"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> giây"</string>
<string name="untitled" msgid="4638956954852782576">"<Không có tiêu đề>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Đồng bộ hóa"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Quá nhiều lần xóa <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Bộ nhớ máy tính bảng đã đầy. Hãy xóa một số tệp để tạo thêm dung lượng."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Bộ nhớ đồng hồ đã đầy. Hãy xóa một số tệp để giải phóng dung lượng."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Bộ nhớ điện thoại đã đầy. Hãy xóa một số tệp để tạo thêm dung lượng."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mạng có thể được giám sát"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Bởi một bên thứ ba không xác định"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Bật chuông"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Đang tắt…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Máy tính bảng của bạn sẽ tắt."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Đồng hồ của bạn sẽ tắt."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Điện thoại của bạn sẽ tắt."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Bạn có muốn tắt không?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Khởi động lại ở chế độ an toàn"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Chế độ trên máy bay"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Chế độ trên máy bay BẬT"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Chế độ trên máy bay TẮT"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Cài đặt"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Dịch vụ tính tiền của bạn"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Thực hiện những tác vụ mà bạn có thể phải trả tiền."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Tin nhắn của bạn"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"gỡ cài đặt lối tắt"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Cho phép ứng dụng xóa lối tắt trên Màn hình chính mà không cần sự can thiệp của người dùng."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"định tuyến lại cuộc gọi đi"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Cho phép ứng dụng xem số được gọi trong một cuộc gọi đi với tùy chọn chuyển hướng cuộc gọi đến một số khác hoặc hủy cuộc gọi đó hoàn toàn."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Cho phép ứng dụng xử lý cuộc gọi đi và thay đổi số được gọi. Quyền này cho phép ứng dụng theo dõi, chuyển hướng hoặc chặn cuộc gọi đi."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"nhận tin nhắn văn bản (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Cho phép ứng dụng nhận và xử lý tin nhắn SMS. Điều này có nghĩa là ứng dụng có thể theo dõi hoặc xóa tin nhắn được gửi đến thiết bị của bạn mà không hiển thị chúng cho bạn."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"nhận tin nhắn văn bản (MMS)"</string>
@@ -331,28 +315,26 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Cho phép ứng dụng truy xuất nội dung của cửa sổ hiện hành. Ứng dụng độc hại có thể truy xuất toàn bộ nội dung của cửa sổ cũng như xem xét toàn bộ văn bản của cửa sổ ngoại trừ mật khẩu."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"tạm thời bật trợ năng"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Cho phép ứng dụng tạm thời bật trợ năng trên thiết bị. Các ứng dụng độc hại có thể bật trợ năng mà không có sự đồng ý của người dùng."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"truy xuất mã thông báo cửa sổ"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Cho phép một ứng dụng truy xuất mã thông báo cửa sổ. Các ứng dụng độc hại có thể thực hiện hoạt động tương tác trái phép với cửa sổ ứng dụng mạo danh hệ thống."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"truy xuất số liệu thống kê về khung"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Cho phép một ứng dụng thu thập số liệu thống kê về khung. Ứng dụng độc hại có thể quan sát số liệu thống kê về khung của cửa sổ từ ứng dụng khác."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"truy xuất thông tin cửa sổ"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Cho phép ứng dụng truy xuất thông tin về các cửa sổ từ trình quản lý cửa sổ. Các ứng dụng độc hại có thể truy xuất thông tin được dành để sử dụng trong hệ thống nội bộ."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"lọc sự kiện"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Cho phép ứng dụng đăng ký bộ lọc dữ liệu nhập để lọc luồng tất cả các sự kiện người dùng trước khi chúng được gửi đi. Ứng dụng độc hại có thể kiểm soát Giao diện người dùng hệ thống mà không cần sự can thiệp của người dùng."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"thu phóng màn hình"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Cho phép ứng dụng thu phóng nội dung trên màn hình. Ứng dụng độc hại có thể biến đổi nội dung trên màn hình theo cách kết xuất thiết bị không thể sử dụng được."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"tắt từng phần"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Đặt trình quản lý hoạt động sang trạng thái tắt. Không thực hiện tắt hoàn toàn."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"ngăn chuyển đổi ứng dụng"</string>
<string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Ngăn người dùng chuyển sang ứng dụng khác."</string>
<string name="permlab_getTopActivityInfo" msgid="2537922311411546016">"truy cập thông tin ứng dụng hiện tại"</string>
<string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"Cho phép chủ sở hữu truy xuất thông tin cá nhân về ứng dụng hiện tại ở nền trước của màn hình."</string>
- <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"giám sát và kiểm soát tất cả hoạt động chạy ứng dụng"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Cho phép ứng dụng giám sát và kiểm soát cách hệ thống chạy các hoạt động. Ứng dụng độc hại hoàn toàn có thể làm tổn hại hệ thống. Quyền này chỉ cần cho mục đích phát triển, không dành cho mục đích sử dụng thông thường."</string>
+ <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"giám sát và kiểm soát tất cả hoạt động khởi chạy ứng dụng"</string>
+ <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Cho phép ứng dụng giám sát và kiểm soát cách hệ thống khởi chạy các hoạt động. Ứng dụng độc hại hoàn toàn có thể làm tổn hại hệ thống. Quyền này chỉ cần cho mục đích phát triển, không dành cho mục đích sử dụng thông thường."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"gửi truyền phát đã xóa của gói"</string>
<string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"Cho phép ứng dụng truyền phát thông báo cho biết rằng gói ứng dụng đã bị xóa. Ứng dụng độc hại có thể sử dụng quyền này để loại bỏ bất kỳ ứng dụng nào khác đang chạy."</string>
<string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"gửi truyền phát SMS nhận được"</string>
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Cho phép ứng dụng truyền phát thông báo cho biết đã nhận được tin nhắn SMS. Ứng dụng độc hại có thể sử dụng quyền này để giả mạo tin nhắn SMS đến."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"gửi truyền phát WAP-PUSH nhận được"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Cho phép ứng dụng truyền phát thông báo cho biết rằng đã nhận được tin nhắn WAP PUSH. Ứng dụng độc hại có thể sử dụng quyền này để giả mạo xác nhận đã nhận được tin nhắn MMS hoặc ngầm thay thế nội dung của bất kỳ trang web nào bằng các biến thể độc hại."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"gửi chương trình phát mạng điểm số"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Cho phép ứng dụng truyền thông báo rằng các mạng cần để được tính điểm. Không bao giờ cần cho ứng dụng thông thường."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"giới hạn số quá trình đang chạy"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Cho phép ứng dụng kiểm soát số quy trình tối đa sẽ chạy. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"buộc ứng dụng nền đóng"</string>
@@ -368,7 +350,7 @@
<string name="permlab_backup" msgid="470013022865453920">"kiểm soát sao lưu và khôi phục hệ thống"</string>
<string name="permdesc_backup" msgid="6912230525140589891">"Cho phép ứng dụng kiểm soát cơ chế sao lưu và khôi phục của hệ thống. Không dành cho các ứng dụng thông thường."</string>
<string name="permlab_confirm_full_backup" msgid="5557071325804469102">"xác nhận bản sao lưu đầy đủ hoặc khôi phục hoạt động"</string>
- <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Cho phép ứng dụng chạy UI xác nhận sao lưu toàn bộ. Không dành cho bất kỳ ứng dụng nào."</string>
+ <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Cho phép ứng dụng khởi chạy UI xác nhận sao lưu toàn bộ. Không dành cho bất kỳ ứng dụng nào."</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"hiển thị các cửa sổ trái phép"</string>
<string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Cho phép ứng dụng tạo các cửa sổ dùng cho giao diện người dùng hệ thống nội bộ. Không dành cho các ứng dụng thông thường."</string>
<string name="permlab_systemAlertWindow" msgid="3543347980839518613">"vẽ trên ứng dụng khác"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ Vpn. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"liên kết với hình nền"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của hình nền. Không cần thiết cho các ứng dụng thông thường."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"liên kết với trình tương tác bằng giọng nói"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ tương tác bằng giọng nói. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"liên kết với màn hình từ xa"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của màn hình từ xa. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"liên kết với dịch vụ tiện ích con"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ tiện ích con. Không cần thiết cho các ứng dụng thông thường."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"liên kết với dịch vụ nhà cung cấp định tuyến"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Cho phép chủ sở hữu liên kết với bất kỳ nhà cung cấp định tuyến đã đăng ký nào. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"tương tác với quản trị viên thiết bị"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Cho phép chủ sở hữu gửi các ý định đến quản trị viên thiết bị. Không cần thiết cho các ứng dụng thông thường."</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"liên kết với đầu vào TV"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của đầu vào TV. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"thêm hoặc xóa quản trị viên thiết bị"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Cho phép chủ sở hữu thêm hoặc xóa quản trị viên thiết bị đang hoạt động. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"thay đổi hướng màn hình"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Cho phép ứng dụng sử dụng bất kỳ trình giải mã phương tiện nào đã cài đặt nhằm giải mã để phát lại."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"quản lý thông tin xác thực đáng tin cậy"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Cho phép ứng dụng cài đặt và gỡ cài đặt chứng chỉ CA dưới dạng thông tin xác thực đáng tin cậy."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"chạy ứng dụng trong thời gian rảnh"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Quyền này cho phép hệ thống Android chạy ứng dụng trong nền khi thiết bị không được sử dụng."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"liên kết với dịch vụ không dùng đến"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Quyền này cho phép hệ thống Android liên kết với các dịch vụ ở trạng thái rảnh của ứng dụng."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"đọc/ghi vào tài nguyên do chẩn đoán sở hữu"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Cho phép ứng dụng đọc và ghi vào bất kỳ tài nguyên nào do nhóm chẩn đoán sở hữu; ví dụ: các tệp trong /dev. Quyền này có thể ảnh hưởng đến sự ổn định và tính bảo mật của hệ thống. CHỈ nên sử dụng quyền này cho các chẩn đoán phần cứng cụ thể của nhà sản xuất hoặc nhà cung cấp."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"bật hoặc tắt cấu phần ứng dụng"</string>
@@ -465,8 +441,8 @@
<string name="permlab_writeGservices" msgid="2149426664226152185">"sửa đổi bản đồ dịch vụ của Google"</string>
<string name="permdesc_writeGservices" msgid="1287309437638380229">"Cho phép ứng dụng sửa đổi bản đồ dịch vụ của Google. Không dành cho ứng dụng thông thường."</string>
<string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"chạy khi khởi động"</string>
- <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Cho phép ứng dụng tự chạy ngay khi hệ thống khởi động xong. Quyền này có thể khiến máy tính bảng mất nhiều thời gian khởi động hơn và cho phép ứng dụng làm chậm toàn bộ máy tính bảng do ứng dụng luôn chạy."</string>
- <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Cho phép ứng dụng tự chạy ngay khi hệ thống khởi động xong. Quyền này có thể khiến điện thoại mất nhiều thời gian khởi động hơn và cho phép ứng dụng làm chậm toàn bộ điện thoại do ứng dụng luôn chạy."</string>
+ <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Cho phép ứng dụng tự khởi chạy ngay khi hệ thống khởi động xong. Quyền này có thể khiến máy tính bảng mất nhiều thời gian khởi động hơn và cho phép ứng dụng làm chậm toàn bộ máy tính bảng do ứng dụng luôn chạy."</string>
+ <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Cho phép ứng dụng tự khởi chạy ngay khi hệ thống khởi động xong. Quyền này có thể khiến điện thoại mất nhiều thời gian khởi động hơn và cho phép ứng dụng làm chậm toàn bộ điện thoại do ứng dụng luôn chạy."</string>
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"gửi truyền phát hấp dẫn người xem"</string>
<string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Cho phép ứng dụng gửi nội dung truyền phát hấp dẫn người xem. Nội dung này sẽ vẫn còn sau khi quá trình truyền phát kết thúc. Việc sử dụng quá mức có thể làm cho máy tính bảng bị chậm hoặc không ổn định do khiến máy tính bảng sử dụng quá nhiều bộ nhớ."</string>
<string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Cho phép ứng dụng gửi nội dung truyền phát hấp dẫn người xem. Nội dung này sẽ vẫn còn sau khi quá trình truyền phát kết thúc. Việc sử dụng quá mức có thể làm cho điện thoại bị chậm hoặc không ổn định do khiến điện thoại sử dụng quá nhiều bộ nhớ."</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Cho phép ứng dụng đọc thông tin tiểu sử cá nhân được lưu trữ trên thiết bị, chẳng hạn như tên và thông tin liên hệ của bạn. Điều này có nghĩa là ứng dụng có thể xác định danh tính của bạn và gửi thông tin tiểu sử của bạn cho người khác."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"sửa đổi thẻ liên hệ của riêng bạn"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Cho phép ứng dụng thay đổi hoặc thêm vào thông tin tiểu sử cá nhân được lưu trữ trên thiết bị, chẳng hạn như tên và thông tin liên hệ của bạn. Điều này có nghĩa là ứng dụng có thể xác định danh tính của bạn và gửi thông tin tiểu sử của bạn cho người khác."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"cảm biến cơ thể (như máy đo nhịp tim)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Cho phép ứng dụng truy cập dữ liệu từ cảm biến mà bạn sử dụng để đo những gì đang diễn ra bên trong cơ thể của bạn, chẳng hạn như nhịp tim."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"đọc luồng xã hội của bạn"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Cho phép ứng dụng truy cập và đồng bộ hóa các cập nhật xã hội của bạn và bạn bè bạn. Hãy cẩn trọng khi chia sẻ thông tin -- việc này có thể cho phép ứng dụng đọc thông tin liên lạc giữa bạn và bạn bè bạn trên các mạng xã hội, bất kể tính bí mật là gì. Lưu ý: quyền này có thể không được thực thi trên tất cả các mạng xã hội."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"ghi luồng xã hội của bạn"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Cho phép ứng dụng kiểm soát các tính năng điện thoại của thiết bị. Ứng dụng có quyền này có thể chuyển đổi mạng, bật và tắt radio điện thoại cũng như thực hiện các tác vụ tương tự mà không cần thông báo cho bạn."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"đọc trạng thái và nhận dạng của điện thoại"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Cho phép ứng dụng truy cập vào các tính năng điện thoại của thiết bị. Quyền này cho phép ứng dụng xác định số điện thoại và ID thiết bị, cho dù cuộc gọi có hiện hoạt hay không và số từ xa có được kết nối bằng một cuộc gọi hay không."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"đọc trạng thái điện thoại chính xác"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Cho phép ứng dụng truy cập trạng thái điện thoại chính xác. Quyền này cho phép ứng dụng xác định trạng thái cuộc gọi thực, cuộc gọi đang hoạt động hay trong nền, cuộc gọi không thành công, trạng thái kết nối dữ liệu chính xác và kết nối dữ liệu không thành công."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ngăn máy tính bảng chuyển sang chế độ ngủ"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ngăn điện thoại chuyển sang chế độ ngủ"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Cho phép ứng dụng ngăn máy tính bảng chuyển sang chế độ ngủ."</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Thay đổi trạng thái WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Cho phép ứng dụng kết nối máy tính bảng và ngắt kết nối máy tính bảng khỏi mạng WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Cho phép ứng dụng kết nối điện thoại và ngắt kết nối điện thoại khỏi mạng WiMAX."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"mạng điểm số"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Cho phép ứng dụng xếp hạng mạng và ảnh hưởng đến việc máy tính bảng nên ưu tiên mạng nào."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Cho phép ứng dụng xếp hạng các mạng và ảnh hưởng đến việc điện thoại nên ưu tiên mạng nào."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"ghép nối với thiết bị Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Cho phép ứng dụng xem cấu hình của Bluetooth trên máy tính bảng và tạo và chấp nhận các kết nối với các thiết bị được ghép nối."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Cho phép ứng dụng xem cấu hình của Bluetooth trên điện thoại, tạo và chấp nhận các kết nối với các thiết bị được ghép nối."</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Cho phép ứng dụng truy xuất, kiểm tra và xóa thông báo, bao gồm những thông báo được đăng bởi các ứng dụng khác."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"liên kết với dịch vụ trình xử lý thông báo"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ trình xử lý thông báo. Không cần thiết cho các ứng dụng thông thường."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"liên kết với dịch vụ trình cung cấp điều kiện"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ trình cung cấp điều kiện. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"gọi ra ứng dụng cấu hình do nhà cung cấp dịch vụ cung cấp"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Cho phép chủ sở hữu gọi ra ứng dụng cấu hình do nhà cung cấp dịch vụ cung cấp. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"quan sát các điều kiện mạng"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Cho phép ứng dụng quan sát các điều kiện mạng. Không bao giờ cần cho ứng dụng thông thường."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"thay đổi hiệu chỉnh thiết bị đầu vào"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Cho phép ứng dụng sửa đổi các thông số hiệu chỉnh của màn hình cảm ứng. Không cần cho ứng dụng thông thường."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"truy cập chứng chỉ DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Cho phép ứng dụng cung cấp và sử dụng chứng chỉ DRM. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Đặt quy tắc mật khẩu"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Kiểm soát độ dài và ký tự được phép trong mật khẩu mở khóa màn hình."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Giám sát những lần thử mở khóa màn hình"</string>
@@ -1186,7 +1149,7 @@
<string name="webpage_unresponsive" msgid="3272758351138122503">"Trang không phản hồi.\n\nBạn có muốn đóng trang không?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Đã chuyển hướng ứng dụng"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> hiện đang chạy."</string>
- <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> được chạy trước tiên."</string>
+ <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> được khởi chạy trước tiên."</string>
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Tỷ lệ"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Luôn hiển thị"</string>
<string name="screen_compat_mode_hint" msgid="1064524084543304459">"Bật lại chế độ này trong cài đặt Hệ thống > Ứng dụng > Đã tải xuống."</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Cho phép ứng dụng truy cập bộ nhớ an toàn khóa"</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Kiểm soát việc hiển thị và ẩn tính năng bảo vệ phím"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Cho phép ứng dụng kiểm soát tính năng bảo vệ phím."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Quan sát các thay đổi ở trạng thái đáng tin cậy."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Cho phép ứng dụng quan sát các thay đổi ở trạng thái đáng tin cậy."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Liên kết với một dịch vụ của đại lý đáng tin cậy"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Cho phép ứng dụng liên kết với một dịch vụ của đại lý đáng tin cậy."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Tương tác với hệ thống khôi phục và bản cập nhật"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Cho phép ứng dụng tương tác với hệ thống khôi phục và bản cập nhật hệ thống."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Chạm hai lần để kiểm soát thu phóng"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Hình nền"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Thay đổi hình nền"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Trình xử lý thông báo"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Trình cung cấp điều kiện"</string>
<string name="vpn_title" msgid="19615213552042827">"Đã kích hoạt VPN"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN được <xliff:g id="APP">%s</xliff:g> kích hoạt"</string>
<string name="vpn_text" msgid="3011306607126450322">"Chạm để quản lý mạng."</string>
@@ -1472,7 +1430,7 @@
<string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
<string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
<string name="activitychooserview_choose_application" msgid="2125168057199941199">"Chọn một ứng dụng"</string>
- <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Không thể chạy <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Không thể khởi chạy <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Chia sẻ với"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Chia sẻ với <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Tay trượt. Chạm & giữ."</string>
@@ -1521,7 +1479,7 @@
<string name="share_action_provider_share_with" msgid="5247684435979149216">"Chia sẻ với"</string>
<string name="list_delimeter" msgid="3975117572185494152">", "</string>
<string name="sending" msgid="3245653681008218030">"Đang gửi…"</string>
- <string name="launchBrowserDefault" msgid="2057951947297614725">"Chạy trình duyệt?"</string>
+ <string name="launchBrowserDefault" msgid="2057951947297614725">"Khởi chạy trình duyệt?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Chấp nhận cuộc gọi?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Luôn chọn"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Chỉ một lần"</string>
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 44e258d..8d82a17 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -21,9 +21,8 @@
for watch products. Do not translate. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Only show power and settings items due to smaller real estate. -->
+ <!-- Only show settings item due to smaller real estate. -->
<string-array translatable="false" name="config_globalActionsList">
- <item>power</item>
<item>settings</item>
</string-array>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 3476692..035c5b6 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g>天"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g>天<xliff:g id="HOURS">%2$d</xliff:g>小时"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g>天<xliff:g id="HOURS">%2$d</xliff:g>小时"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g>小时"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g>小时<xliff:g id="MINUTES">%2$d</xliff:g>分钟"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g>小时<xliff:g id="MINUTES">%2$d</xliff:g>分钟"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g>分钟"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g>分钟<xliff:g id="SECONDS">%2$d</xliff:g>秒"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g>分钟<xliff:g id="SECONDS">%2$d</xliff:g>秒"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g>秒"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g>秒"</string>
<string name="untitled" msgid="4638956954852782576">"<未命名>"</string>
<string name="ellipsis" msgid="7899829516048813237">"..."</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -87,15 +76,15 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"默认显示本机号码,在下一次通话中也显示"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"未提供服务。"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"您无法更改来电显示设置。"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"网络可用情况发生变化"</string>
- <string name="RestrictedOnData" msgid="8653794784690065540">"数据网络服务已停用。"</string>
- <string name="RestrictedOnEmergency" msgid="6581163779072833665">"紧急服务已停用。"</string>
- <string name="RestrictedOnNormal" msgid="4953867011389750673">"语音服务已停用。"</string>
- <string name="RestrictedOnAllVoice" msgid="3396963652108151260">"所有语音服务都已停用。"</string>
- <string name="RestrictedOnSms" msgid="8314352327461638897">"短信服务已停用。"</string>
- <string name="RestrictedOnVoiceData" msgid="996636487106171320">"语音/数据服务已停用。"</string>
- <string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"语音/短信服务已停用。"</string>
- <string name="RestrictedOnAll" msgid="5643028264466092821">"所有语音/数据/短信服务都已停用。"</string>
+ <string name="RestrictedChangedTitle" msgid="5592189398956187498">"访问受限情况已发生变化"</string>
+ <string name="RestrictedOnData" msgid="8653794784690065540">"数据服务已禁用。"</string>
+ <string name="RestrictedOnEmergency" msgid="6581163779072833665">"紧急服务已禁用。"</string>
+ <string name="RestrictedOnNormal" msgid="4953867011389750673">"已禁用语音服务。"</string>
+ <string name="RestrictedOnAllVoice" msgid="3396963652108151260">"已停用所有语音服务。"</string>
+ <string name="RestrictedOnSms" msgid="8314352327461638897">"已禁用短信服务。"</string>
+ <string name="RestrictedOnVoiceData" msgid="996636487106171320">"已停用语音/数据服务。"</string>
+ <string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"已禁用语音/短信服务。"</string>
+ <string name="RestrictedOnAll" msgid="5643028264466092821">"已停用所有语音/数据/短信服务。"</string>
<string name="serviceClassVoice" msgid="1258393812335258019">"语音"</string>
<string name="serviceClassData" msgid="872456782077937893">"数据"</string>
<string name="serviceClassFAX" msgid="5566624998840486475">"传真"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"同步"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"太多<xliff:g id="CONTENT_TYPE">%s</xliff:g>删除项。"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"平板电脑存储空间已满。请删除一些文件以腾出空间。"</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"手表存储空间已满。请删除一些文件以腾出空间。"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"手机存储空间已满。请删除一些文件以腾出空间。"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"网络可能会受到监控"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"受到不明第三方的监控"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"振铃器开启"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"正在关机..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"您的平板电脑会关闭。"</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"您的手表即将关机。"</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"您的手机将会关机。"</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"您要关机吗?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"重新启动并进入安全模式"</string>
@@ -183,13 +170,10 @@
<string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"声音已开启"</string>
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飞行模式"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"已开启飞行模式"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"未开启飞行模式"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"设置"</string>
+ <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"已关闭飞行模式"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"需要您付费的服务"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"执行可能需要您付费的操作。"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"您的信息"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"卸载快捷方式"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"允许应用自行删除主屏幕快捷方式。"</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"重新设置外拨电话的路径"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"允许应用在拨出电话时查看拨打的电话号码,并选择改为拨打其他号码或完全中止通话。"</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"允许该应用处理外拨电话以及更改要拨打的号码。此权限可让该应用监视、重定向或阻止外拨电话。"</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"接收讯息(短信)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"允许该应用接收和处理短信。这就意味着,该应用可能会监视发送到您设备的短信,或删除发送到您设备的短信而不向您显示。"</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"接收讯息(彩信)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"允许应用检索活动窗口的内容。恶意应用可能会检索整个窗口的内容,并检查其中除密码以外的所有文字。"</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"暂时启用辅助功能"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"允许应用在设备上暂时启用辅助功能。恶意应用可能会在未经用户同意的情况下擅自启用辅助功能。"</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"检索窗口令牌"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"允许应用检索窗口令牌。恶意软件可能会借此在未经授权的情况下冒充系统与应用窗口进行互动。"</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"检索框架统计信息"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"允许应用收集框架统计信息。恶意应用可能会借此监测其他应用的窗口框架统计信息。"</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"检索窗口信息"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"允许应用通过窗口管理器检索窗口信息。恶意应用可能会检索供内部系统使用的信息。"</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"过滤事件"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"允许应用注册输入过滤器,这类过滤器会在所有用户事件分派之前对用户事件流进行过滤。恶意应用可能会在没有用户干预的情况下控制系统用户界面。"</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"放大显示内容"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"允许应用放大显示内容。恶意应用可能会以特定方式改变显示内容,使得设备无法使用。"</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"部分关机"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"使活动管理器进入关闭状态。不执行彻底关机。"</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"禁止切换应用"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"允许应用广播一条有关已收到短信的通知。恶意应用可能借此伪造接到的短信。"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"发送 WAP-PUSH 收到的广播"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"允许应用广播一条有关已收到 WAP PUSH 短信的通知。恶意应用可能借此伪造短信接收,或在后台将任意网页的内容替换为恶意内容。"</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"发送网络评分广播通知"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"允许应用广播“需要为网络评分”的通知。普通应用绝不需要此权限。"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"限制运行的进程个数"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"允许应用控制将运行的进程数上限。普通应用绝不需要此权限。"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"强制关闭后台应用"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"允许用户绑定到 VPN 服务的顶级接口。普通应用绝不需要此权限。"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"绑定到壁纸"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允许用户绑定到壁纸的顶级接口。普通应用绝不需要此权限。"</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"绑定到语音互动器"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"允许应用绑定到语音互动服务的顶级接口。普通应用绝不需要此权限。"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"绑定至远程显示屏"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允许应用绑定至远程显示屏的顶级接口。普通应用绝不需要此权限。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"绑定到小部件服务"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允许应用绑定到小部件服务的顶级接口。普通应用绝不需要此权限。"</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"绑定到路由程序服务"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"允许应用绑定到任何已注册的路由程序。普通应用绝不需要此权限。"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"与设备管理器交互"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允许用户将意向发送给设备管理员。普通应用绝不需要此权限。"</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"绑定至电视输入设备"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"允许应用绑定至电视输入设备的顶级接口。普通应用绝不需要此权限。"</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"添加或删除设备管理员"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"允许应用添加或删除有效的设备管理员。普通应用绝不需要此权限。"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"更改屏幕显示方向"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允许该应用使用任何已安装的媒体解码器进行解码,以便播放媒体。"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理受信任的凭据"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允许应用安装和卸载 CA 证书(作为受信任的凭据)。"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"在设备处于闲置状态时运行应用"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"当设备处于闲置状态时,此权限允许Android系统在后台运行该应用。"</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"绑定到闲置服务"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"此权限允许Android系统绑定至应用的闲置服务。"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"读取/写入诊断所拥有的资源"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"允许应用读取/写入诊断组拥有的所有资源(例如 /dev 中的文件)。这可能会影响系统的稳定性和安全性。此权限仅供制造商或运营商诊断硬件方面的问题时使用。"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"启用或停用应用组件"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"允许该应用读取您设备上存储的个人资料信息,例如您的姓名和联系信息。这意味着该应用可以识别您的身份,并可能将您的个人资料信息发送给他人。"</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"修改您自己的名片"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"允许该应用更改或添加您设备上存储的个人资料信息,例如您的姓名和联系信息。这意味着该应用可以识别您的身份,并可能将您的个人资料信息发送给他人。"</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"人体传感器(如心跳速率检测器)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"允许应用访问您用于测量身体状况(如心跳速率)的传感器中的数据。"</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"读取您的社交信息流"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"允许该应用访问并同步您和朋友的社交动态信息。在分享信息时一定要小心,因为此权限可让该应用读取您与社交网络上的朋友之间的交流信息。"</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"写入您的社交信息流"</string>
@@ -505,9 +479,9 @@
<string name="permlab_installLocationProvider" msgid="6578101199825193873">"允许安装位置信息提供程序"</string>
<string name="permdesc_installLocationProvider" msgid="9066146120470591509">"创建用于测试的模拟位置源或安装新的位置提供程序。此权限可让该应用覆盖由其他位置源(如 GPS)或位置提供程序返回的位置和/或状态信息。"</string>
<string name="permlab_accessFineLocation" msgid="1191898061965273372">"精确位置(基于 GPS 和网络)"</string>
- <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"允许该应用通过全球定位系统(GPS)或网络位置信息源(例如基站和WLAN)获取您的精确位置信息。您必须在设备上开启这些位置信息服务,应用才能获得位置信息。应用会使用此类服务确定您的位置,这可能会消耗更多电量。"</string>
+ <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"允许该应用通过全球定位系统 (GPS) 或网络位置信息源(例如基站和 WLAN)获取您的精确位置信息。您必须在设备上开启这些位置服务,应用才能获得位置信息。应用会使用此类服务确定您的位置,这可能会消耗更多电量。"</string>
<string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"大致位置(基于网络)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"允许该应用获取您的大致位置信息。这类位置信息来自于使用网络位置信息源(例如基站和WLAN)的位置信息服务。您必须在设备上开启这些位置信息服务,应用才能获得位置信息。应用会使用此类服务确定您的大概位置。"</string>
+ <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"允许该应用获取您的大致位置信息。这类位置信息来自于使用网络位置信息源(例如基站和 WLAN)的位置服务。您必须在设备上开启这些位置服务,应用才能获得位置信息。应用会使用此类服务确定您的大概位置。"</string>
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"访问 SurfaceFlinger"</string>
<string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"允许应用使用 SurfaceFlinger 低级功能。"</string>
<string name="permlab_readFrameBuffer" msgid="6690504248178498136">"读取帧缓冲区"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"允许应用控制设备的电话功能。拥有此权限的应用可在不通知您的情况下执行切换网络、开关手机无线装置等此类操作。"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"读取手机状态和身份"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"允许该应用访问设备的电话功能。此权限可让该应用确定本机号码和设备 ID、是否正处于通话状态以及拨打的号码。"</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"读取确切的手机状态"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"允许应用获取确切的手机状态。此权限可让应用确定实际通话状态、通话是在界面上进行还是在后台进行、通话未接通情况、确切的数据网络连接状态,以及数据网络连接失败情况。"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"阻止平板电脑进入休眠状态"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手机休眠"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"允许应用阻止平板电脑进入休眠状态。"</string>
@@ -624,8 +596,8 @@
<string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"允许该应用获取手机已知的帐户列表,其中可能包括由已安装的应用创建的所有帐户。"</string>
<string name="permlab_authenticateAccounts" msgid="5265908481172736933">"创建帐户并设置密码"</string>
<string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"允许应用使用 AccountManager 的帐户身份验证程序功能,包括创建帐户以及获取和设置其密码。"</string>
- <string name="permlab_manageAccounts" msgid="4983126304757177305">"添加或移除帐户"</string>
- <string name="permdesc_manageAccounts" msgid="8698295625488292506">"允许应用执行添加帐户、移除帐户、删除帐户密码等操作。"</string>
+ <string name="permlab_manageAccounts" msgid="4983126304757177305">"添加或删除帐户"</string>
+ <string name="permdesc_manageAccounts" msgid="8698295625488292506">"允许应用执行添加帐户、删除帐户、删除帐户密码等操作。"</string>
<string name="permlab_useCredentials" msgid="235481396163877642">"使用设备上的帐户"</string>
<string name="permdesc_useCredentials" msgid="7984227147403346422">"允许应用请求身份验证令牌。"</string>
<string name="permlab_accessNetworkState" msgid="4951027964348974773">"查看网络连接"</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"更改 WiMAX 状态"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"允许该应用建立和断开平板电脑与 WiMAX 网络之间的连接。"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"允许该应用建立和断开手机与 WiMAX 网络之间的连接。"</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"为网络评分"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"允许应用为网络评分,并控制平板电脑应优先使用的网络。"</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"允许应用为网络评分,并控制手机应优先使用的网络。"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"与蓝牙设备配对"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"允许该应用查看平板电脑上的蓝牙配置,以及建立和接受与配对设备的连接。"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"允许该应用查看手机上的蓝牙配置,以及建立和接受与配对设备的连接。"</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"允许该应用检索、检查并清除通知,包括其他应用发布的通知。"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"绑定到通知侦听器服务"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允许应用绑定到通知侦听器服务的顶级接口(普通应用绝不需要此权限)。"</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"绑定到条件提供程序服务"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允许应用绑定到条件提供程序服务的顶级接口。普通应用绝不需要此权限。"</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"调用运营商提供的配置应用"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允许应用调用运营商提供的配置应用。普通应用绝不需要此权限。"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"监听网络状况的观测信息"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"允许应用监听网络状况的观测信息。普通应用绝不需要此权限。"</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"更改输入设备校准设置"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"允许应用修改触摸屏的校准参数。普通应用绝不需要此权限。"</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"访问DRM证书"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"允许应用配置和使用DRM证书。普通应用绝不需要此权限。"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"设置密码规则"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解锁密码所允许的长度和字符。"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"监视屏幕解锁尝试次数"</string>
@@ -1163,7 +1126,7 @@
<string name="no" msgid="5141531044935541497">"取消"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"注意"</string>
<string name="loading" msgid="7933681260296021180">"正在加载..."</string>
- <string name="capital_on" msgid="1544682755514494298">"开启"</string>
+ <string name="capital_on" msgid="1544682755514494298">"打开"</string>
<string name="capital_off" msgid="6815870386972805832">"关闭"</string>
<string name="whichApplication" msgid="4533185947064773386">"选择要使用的应用:"</string>
<string name="whichHomeApplication" msgid="4616420172727326782">"选择主屏幕应用"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"允许应用访问密钥保护安全存储空间。"</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"控制是显示还是隐藏锁屏"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"允许应用控制锁屏。"</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"检测信任状态的变化。"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"允许应用检测信任状态的变化。"</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"绑定至信任的代理服务"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允许应用绑定至信任的代理服务。"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"与更新和恢复系统互动"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"允许应用与恢复系统和系统更新互动。"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"触摸两次可进行缩放控制"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"壁纸"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"更改壁纸"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知侦听器"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"条件提供程序"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN 已激活"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"“<xliff:g id="APP">%s</xliff:g>”已激活 VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"触摸可管理网络。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index fdd02a7..90632f0 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> 天"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> 天 <xliff:g id="HOURS">%2$d</xliff:g> 小時"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> 天 <xliff:g id="HOURS">%2$d</xliff:g> 小時"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> 小時"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> 小時 <xliff:g id="MINUTES">%2$d</xliff:g> 分鐘"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> 小時 <xliff:g id="MINUTES">%2$d</xliff:g> 分鐘"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> 分鐘"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> 分鐘 <xliff:g id="SECONDS">%2$d</xliff:g> 秒"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> 分鐘 <xliff:g id="SECONDS">%2$d</xliff:g> 秒"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> 秒"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> 秒"</string>
<string name="untitled" msgid="4638956954852782576">"<未命名>"</string>
<string name="ellipsis" msgid="7899829516048813237">"..."</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Google Sync"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"同時刪除太多 <xliff:g id="CONTENT_TYPE">%s</xliff:g>。"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"平板電腦的儲存空間已滿。請刪除一些檔案,以騰出可用空間。"</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"手錶的儲存空間已滿。請刪除一些檔案,以騰出可用空間。"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"手機的儲存空間已滿。請刪除一些檔案,以騰出可用空間。"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"網絡可能會受到監控"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"由不明的第三方監管"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"鈴聲開啟"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"正在關機..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"您的平板電腦將會關機。"</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"您的手錶即將關機。"</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"您的手機即將關機。"</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"您要關機嗎?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"重新啟動進入安全模式"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飛行模式"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"飛航模式為 [開啟]"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"飛行模式為 [關閉]"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"設定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"付費服務"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"執行需付費的操作或服務。"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"您的訊息"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"解除安裝捷徑"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"允許應用程式繞過用戶授權直接移除主畫面捷徑。"</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"重新設定撥出電話的路徑"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"允許應用程式在撥出電話時查看所撥打的電話號碼,並選擇將電話重新導向至另一個號碼或完全中斷通話。"</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"允許應用程式處理撥出電話及更改撥打的號碼。這項權限允許應用程式監控、轉接或阻止撥出的電話。"</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"接收短訊 (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"允許應用程式接收和處理短訊。這表示應用程式可監控傳送至您裝置的訊息,或在您閱讀訊息前擅自刪除訊息。"</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"接收短訊 (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"允許應用程式擷取使用中的視窗內容。惡意應用程式可能會擷取整個視窗的內容,以及檢視密碼除外的所有文字。"</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"暫時啟用協助工具"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"允許應用程式在裝置上暫時啟用協助工具。惡意應用程式可能藉此在未經用戶同意的情況下擅自啟用協助工具。"</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"擷取視窗憑證"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"允許應用程式擷取視窗憑證。惡意應用程式可能會在未經授權的情況下,與冒充系統的應用程式視窗互動。"</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"擷取畫格統計資料"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"允許應用程式收集畫格統計資料。惡意應用程式可能會透過其他應用程式監察視窗畫格統計資料。"</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"擷取視窗資訊"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"允許應用程式從視窗管理程式擷取視窗的相關資訊。惡意應用程式可能會擷取專供內部系統使用的資訊。"</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"篩選活動"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"允許應用程式註冊輸入篩選器,在分派所有用戶活動的串流前先行篩選。惡意應用程式可能會繞過用戶操作,直接控制系統用戶介面。"</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"放大畫面"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"允許應用程式放大畫面內容。惡意應用程式可能會改變顯示內容,導致裝置失靈。"</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"部分關機"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"讓活動管理員進入關機狀態,而不執行完整的關機程序。"</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"防止切換應用程式"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"允許應用程式在收到短訊時發出通知。惡意應用程式可能會藉此偽造外來短訊。"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"傳送可由 WAP PUSH 接收的廣播"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"允許應用程式在收到 WAP PUSH 訊息時發送通知。惡意應用程式可能會藉此偽造 MMS 訊息回條或私自以惡意內容更換網頁。"</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"傳送網絡計分廣播"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"允許應用程式廣播網絡需要計分的通知,但一般應用程式並不需要使用。"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"執行程序數目上限"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"允許應用程式控制可執行程序的數量上限 (不建議一般應用程式使用)。"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"強制關閉背景應用程式"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"允許應用程式繫結至 VPN 服務的頂層介面 (不建議一般應用程式使用)。"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"繫結至桌布"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允許應用程式繫結至桌布的頂層介面 (不建議一般應用程式使用)。"</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"繫結至語音互動器"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"允許應用程式繫結至語音互動服務的頂層介面,但一般應用程式並不需要使用。"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"繫結至遠端螢幕"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允許應用程式繫結至遠端屏螢的頂層介面 (不建議一般應用程式使用)。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"繫結至小工具服務"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (不建議一般應用程式使用)。"</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"繫結至路由供應商服務"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"允許應用程式繫結至任何已註冊的路由供應商,但一般應用程式並不需要使用。"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允許應用程式將調用請求傳送至裝置管理員 (不建議一般應用程式使用)。"</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"繫結至電視訊號輸入裝置"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允許應用程式使用任何已安裝的媒體解碼器為播放解碼。"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理信任的憑證"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允許應用程式安裝 CA 憑證為信任的憑證及解除安裝 CA 憑證。"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"當裝置閒置時執行應用程式"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"當您不使用裝置時,此權限允許 Android 系統在背景執行應用程式。"</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"繫結至閒置服務"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"此權限允許 Android 系統繫結至應用程式的閒置服務。"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"讀取/寫入由診斷應用程式擁有的資源"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"允許應用程式讀取及寫入診斷群組所擁有的任何資源 (例如:位於 /dev 中的檔案)。這可能會影響系統的穩定性及安全性,只應對製造商或網絡供應商所使用的硬件專用診斷程式開放這項權限。"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"啟用或停用應用程式元件"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"允許應用程式讀取裝置上儲存的個人資料,例如您的姓名和聯絡資訊。這表示應用程式可以識別您的身份,並將您的個人資料傳送給他人。"</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"修改自己的聯絡資料"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"允許應用程式新增或更改裝置上儲存的個人資料,例如您的姓名和聯絡資訊。這表示應用程式可以識別您的身份,並將您的個人資料傳送給他人。"</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"身體感應器 (例如心跳監視器)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"允許應用程式存取用於測量身體狀況感應器的資料,例如心跳。"</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"讀取您的社交串流"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"允許應用程式存取並同步處理您和好友的最新動態。當您分享資訊時,請務必小心,因為這項權限允許應用程式讀取您和好友在社交網絡上的私人通訊,不論是否機密。注意:這項權限可能不適用於所有社交網絡。"</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"寫入您的社交串流"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"允許應用程式控制裝置上的電話功能。具備此權限的應用程式可在未通知您的情況下,進行切換網絡以及開關手機無線電之類的操作。"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"讀取手機狀態和識別碼"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"允許應用程式使用裝置的電話功能。這項權限允許應用程式確定手機號碼和裝置編號、是否正在通話中,以及所撥打的對方號碼。"</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"讀取精確的手機狀態"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"允許應用程式存取精確的手機狀態。此權限可讓應用程式判斷實際的通話狀態、是否正在通話或在背景中運作、無法通話次數、精確的數據連線狀態和數據連線失敗次數。"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"防止平板電腦進入休眠狀態"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手機進入休眠狀態"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"允許應用程式防止平板電腦進入休眠狀態。"</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"更改 WiMAX 狀態"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"允許應用程式建立或中斷平板電腦與 WiMAX 網絡的連線。"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"允許應用程式建立或中斷手機與 WiMAX 網絡的連線。"</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"為網絡計分"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"允許應用程式為網絡排名,及決定平板電腦偏好使用的網絡。"</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"允許應用程式為網絡排名,及決定手機偏好使用的網絡。"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"與藍牙裝置配對"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"允許應用程式查看平板電腦的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"允許應用程式查看手機的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允許應用程式繫結至通知接聽器服務的頂層介面 (不建議一般應用程式使用)。"</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"繫結至條件供應商服務"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允許應用程式繫結至條件供應商服務的頂層介面,但一般應用程式並不需要使用。"</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"調用流動網絡供應商提供的設定應用程式"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允許應用程式調用流動網絡供應商提供的設定應用程式 (不建議一般應用程式使用)。"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"監聽對網絡狀況的觀察"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"允許應用程式監聽對網絡狀況的觀察 (不建議一般應用程式使用)。"</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"變更輸入裝置校正設定"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"允許應用程式修改觸控式螢幕的校正參數,而一般應用程式並不需要作出類似修改。"</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"存取 DRM 憑證"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"允許應用程式準備和使用 DRM 憑證,但一般應用程式並不需要使用。"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解鎖密碼所允許的長度和字元。"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"監控屏幕解鎖嘗試次數"</string>
@@ -998,7 +963,7 @@
<string name="permlab_setAlarm" msgid="1379294556362091814">"設定鬧鐘"</string>
<string name="permdesc_setAlarm" msgid="316392039157473848">"允許應用程式在安裝的鬧鐘應用程式中設定鬧鐘,某些鬧鐘應用程式可能沒有這項功能。"</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"新增留言"</string>
- <string name="permdesc_addVoicemail" msgid="6604508651428252437">"允許應用程式將訊息加到您的留言信箱收件箱。"</string>
+ <string name="permdesc_addVoicemail" msgid="6604508651428252437">"允許應用程式將訊息加到您的留言信箱收件匣。"</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"修改瀏覽器地理資訊的權限"</string>
<string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"允許應用程式修改瀏覽器的地理資訊權限。惡意應用程式可能會藉此允許將您的位置資訊任意傳送給某些網站。"</string>
<string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"驗證套件"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"允許應用程式存取 Keyguard 安全儲存空間。"</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"控制顯示或隱藏鍵盤鎖"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"允許應用程式控制鍵盤鎖。"</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"聽取信任狀態變更。"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"允許應用程式聽取信任狀態的變更。"</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"繫結至信任的代理程式服務"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允許應用程式繫結至信任的代理程式服務。"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"與更新和復原系統互動"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"允許應用程式與復原系統和系統更新互動。"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"輕觸兩下即可控制縮放"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"桌布"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知接聽器"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"條件供應商"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN 已啟用。"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> 已啟用 VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"輕觸即可管理網絡。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 4a67538..6c3f1c4 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> 天"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> 天 <xliff:g id="HOURS">%2$d</xliff:g> 小時"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> 天 <xliff:g id="HOURS">%2$d</xliff:g> 小時"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> 小時"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> 小時 <xliff:g id="MINUTES">%2$d</xliff:g> 分鐘"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> 小時 <xliff:g id="MINUTES">%2$d</xliff:g> 分鐘"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> 分鐘"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> 分鐘 <xliff:g id="SECONDS">%2$d</xliff:g> 秒"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> 分鐘 <xliff:g id="SECONDS">%2$d</xliff:g> 秒"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> 秒"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> 秒"</string>
<string name="untitled" msgid="4638956954852782576">"<未命名>"</string>
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"同步處理"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"同時刪除太多 <xliff:g id="CONTENT_TYPE">%s</xliff:g>。"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"平板電腦的儲存空間已滿。請刪除一些檔案,以釋放出可用空間。"</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"手錶儲存空間已用盡,請刪除一些檔案以釋出可用空間。"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"手機儲存空間已滿。請刪除一些檔案,以釋放可用空間。"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"網路可能會受到監控"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"受到不明的第三方監控"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"鈴聲開啟"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"關機中…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"您的平板電腦將會關機。"</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"您的手錶即將關機。"</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"手機即將關機。"</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"您要關機嗎?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"重新啟動進入安全模式"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飛航模式"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"飛航模式為 [開啟]"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"飛航模式為 [關閉]"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"設定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"超過 999"</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="permgrouplab_costMoney" msgid="5429808217861460401">"需要額外費用的服務。"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"執行需付費的作業或服務。"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"您的簡訊"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"解除安裝捷徑"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"允許應用程式自動移除主螢幕捷徑。"</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"重設撥號路徑"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"允許應用程式在撥打電話期間查看撥出的電話號碼,並可選擇改撥其他號碼或中斷通話。"</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"允許應用程式處理撥出電話及更改撥打的號碼。這項權限可讓應用程式監控、轉接或阻止撥出的電話。"</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"接收簡訊 (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"允許應用程式接收和處理簡訊。這項設定可讓應用程式監控傳送至您裝置的訊息,或在您閱讀訊息前擅自刪除訊息。"</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"接收簡訊 (MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"允許應用程式擷取使用中的視窗內容。請注意,惡意應用程式可能利用此功能擷取完整視窗內容,並檢視密碼之外的所有文字。"</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"暫時啟用協助工具"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"允許應用程式在裝置上暫時啟用協助工具。惡意應用程式可能藉此在未經使用者同意的情況下擅自啟用協助工具。"</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"擷取視窗符記"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"允許應用程式擷取視窗符記。惡意應用程式可能會藉此在未經授權的情況下與模擬系統的應用程式視窗互動。"</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"擷取畫格統計資料"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"允許應用程式收集畫格統計資料。惡意應用程式可能會藉此得知其他應用程式的視窗畫格統計資料。"</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"擷取視窗資訊"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"允許應用程式透過視窗管理程式擷取視窗的相關資訊。請注意,惡意應用程式可能藉此擷取僅限內部系統使用的資訊。"</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"篩選活動"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"允許應用程式註冊輸入篩選器,在分派所有使用者活動的串流前先行篩選。請注意,惡意應用程式可能藉此擅自控制系統使用者介面。"</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"放大畫面"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"允許應用程式放大畫面內容。請注意,惡意應用程式可能會藉此利用不正常的方式改變顯示內容,導致裝置失靈。"</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"部分關機"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"讓活動管理員進入關機狀態,而不執行完整的關機程序。"</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"防止切換應用程式"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"允許應用程式在收到 SMS 簡訊時發出通知。請注意,惡意應用程式可能利用此功能偽造外來的 SMS 簡訊。"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"送出「WAP PUSH 已接收」廣播"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"允許應用程式在收到 WAP PUSH 訊息時發送通知。請注意,惡意應用程式可能利用此功能偽造 MMS 簡訊回條,或私自將網頁內容更換為惡意陷阱。"</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"傳送網路計分廣播通知"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"允許應用程式廣播「網路需計分」的通知訊息 (一般應用程式並不需要)。"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"執行程序限制數"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"允許應用程式控制可執行程序的數量上限 (一般應用程式不需使用)。"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"強制關閉背景應用程式"</string>
@@ -400,18 +382,12 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"允許應用程式聯繫至 VPN 服務的頂層介面 (一般應用程式不需使用)。"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"連結至桌布"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允許應用程式繫結至桌布的頂層介面 (一般應用程式不需使用)。"</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"繫結至語音互動器"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"允許應用程式繫結至語音互動服務的頂層介面 (一般應用程式並不需要)。"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"繫結至遠端螢幕"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允許應用程式繫結至遠端螢幕的頂層介面 (一般應用程式不需使用)。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"繫結至小工具服務"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (一般應用程式不需使用)。"</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"繫結至路由供應商服務"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"允許應用程式繫結至任何已註冊的路由供應商 (一般應用程式並不需要)。"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允許應用程式將調用請求傳送至裝置管理員 (一般應用程式不需使用)。"</string>
- <string name="permlab_bindTvInput" msgid="5601264742478168987">"繫結至電視訊號輸入裝置"</string>
- <string name="permdesc_bindTvInput" msgid="2371008331852001924">"允許應用程式繫結至電視訊號輸入裝置的頂層介面 (一般應用程式並不需要)。"</string>
<string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"新增或移除裝置管理員"</string>
<string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"允許應用程式新增或移除有效的裝置管理員 (一般應用程式並不需要)。"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"變更螢幕顯示方向"</string>
@@ -447,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允許應用程式使用任何已安裝的媒體解碼器進行解碼以播放影片。"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理信任的憑證"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允許應用程式安裝 CA 憑證 (做為信任的憑證) 及解除安裝 CA 憑證。"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"當裝置閒置時執行應用程式"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"當裝置處於未使用狀態時,此權限允許 Android 系統在背景執行應用程式。"</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"繫結至閒置服務"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"此權限允許 Android 系統繫結至應用程式的閒置服務。"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"讀寫 diag 擁有的資源"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"允許應用程式讀取或寫入診斷群組擁有的任何資源,例如 /dev 底下的檔案。這可能會影響系統的穩定性和安全性,因此應由製造商或電信業者操作,且只用在特定硬體診斷。"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"啟用或停用應用程式元件"</string>
@@ -486,8 +462,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"允許應用程式讀取裝置上儲存的個人資料,例如您的姓名和聯絡資訊。這表示應用程式可以識別您的身分,並將您的個人資料傳送給他人。"</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"修改自己的聯絡資訊"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"允許應用程式新增或變更裝置上儲存的個人資料,例如您的姓名和聯絡資訊。這項設定可讓應用程式識別您的身分,並可能將您的個人資料傳送給他人。"</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"身體感應器 (例如心律監測器)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"允許應用程式存取感應器從您的身體測得的資料,例如心跳頻率。"</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"讀取您的社交串流"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"允許應用程式存取並同步處理您和好友的最新動態。因此,當您分享資訊時請小心,因為這項權限可讓應用程式讀取您和好友在社交網路上的私人通訊,包括機密通訊。注意:並非所有社交網路皆適用於這項權限。"</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"寫入您的社交串流"</string>
@@ -589,8 +563,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"允許應用程式控制裝置的電話功能。擁有這項權限的應用程式可在未通知您的情況下,任意切換網路、開啟或關閉手機無線電等。"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"讀取手機狀態和識別碼"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"允許應用程式使用裝置的電話功能。這項權限可讓應用程式判讀手機號碼和裝置 ID、是否正在通話中,以及所撥打的對方號碼。"</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"讀取手機精確狀態"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"允許應用程式存取手機的精確狀態。這項權限可讓應用程式判別實際通話狀態,包括通話正在進行中或是在背景運作、通話失敗次數、精確數據連線狀態和數據連線失敗次數。"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"防止平板電腦進入休眠狀態"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手機進入待命狀態"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"允許應用程式防止平板電腦進入休眠狀態。"</string>
@@ -658,9 +630,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"變更 WiMAX 狀態"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"允許應用程式建立或中斷平板電腦與 WiMAX 網路的連線。"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"允許應用程式建立或中斷手機與 WiMAX 網路的連線。"</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"為網路計分"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"允許應用程式建立網路排名,決定平板電腦偏好使用的網路。"</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"允許應用程式建立網路排名,決定手機偏好使用的網路。"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"與藍牙裝置配對"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"允許應用程式查看平板電腦的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"允許應用程式查看手機的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
@@ -714,16 +683,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允許應用程式繫結至通知接聽器服務的頂層介面 (一般應用程式不需使用)。"</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"繫結至條件提供者服務"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允許應用程式繫結至條件提供者服務的頂層介面 (一般應用程式並不需要)。"</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"叫用行動通訊業者提供的設定應用程式"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允許應用程式叫用行動通訊業者提供的設定應用程式 (一般應用程式並不需要)。"</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"監聽網路狀況觀察資訊"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"允許應用程式監聽網路狀況觀察資訊 (一般應用程式並不需要)。"</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"變更輸入裝置校正設定"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"允許應用程式修改觸控螢幕的校正參數 (一般應用程式並不需要)。"</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"存取 DRM 憑證"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"允許應用程式佈建及使用 DRM 憑證 (一般應用程式並不需要)。"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"控制螢幕解鎖密碼所允許的長度和字元。"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"監視螢幕解鎖嘗試次數"</string>
@@ -1169,11 +1132,11 @@
<string name="whichHomeApplication" msgid="4616420172727326782">"選取主螢幕應用程式"</string>
<string name="alwaysUse" msgid="4583018368000610438">"設為預設應用程式。"</string>
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"前往 [系統設定] > [應用程式] > [下載] 清除預設值。"</string>
- <string name="chooseActivity" msgid="7486876147751803333">"選擇分享方式"</string>
+ <string name="chooseActivity" msgid="7486876147751803333">"選擇一種動作"</string>
<string name="chooseUsbActivity" msgid="6894748416073583509">"選取要以 USB 裝置存取的應用程式"</string>
<string name="noApplications" msgid="2991814273936504689">"沒有應用程式可執行這項操作。"</string>
<string name="aerr_title" msgid="1905800560317137752"></string>
- <string name="aerr_application" msgid="932628488013092776">"很抱歉,<xliff:g id="APPLICATION">%1$s</xliff:g>已停止運作。"</string>
+ <string name="aerr_application" msgid="932628488013092776">"很抱歉,<xliff:g id="APPLICATION">%1$s</xliff:g> 已停止。"</string>
<string name="aerr_process" msgid="4507058997035697579">"很抱歉,處理程序 <xliff:g id="PROCESS">%1$s</xliff:g> 已停止。"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
<string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> 沒有回應。\n\n您要結束嗎?"</string>
@@ -1356,10 +1319,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"允許應用程式存取 Keyguard 安全儲存空間。"</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"控制鍵盤鎖的顯示和隱藏"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"允許應用程式控制鍵盤鎖。"</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"接聽信任狀態變更。"</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"允許應用程式接聽信任狀態變更。"</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"繫結至信任的代理程式服務"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允許應用程式繫結至信任的代理程式服務。"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"與更新和還原系統互動"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"允許應用程式與還原系統及系統更新互動。"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"輕觸兩下即可控制縮放"</string>
@@ -1386,7 +1345,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"桌布"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知接聽器"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"條件提供者"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN 已啟用"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> 已啟用 VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"輕觸即可管理網路。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 58fdb1c..342d7c1 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -27,17 +27,6 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="9164292791500531949">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> izinsuku"</string>
- <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> usuku <xliff:g id="HOURS">%2$d</xliff:g> amahora"</string>
- <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> usuku <xliff:g id="HOURS">%2$d</xliff:g> ihora"</string>
- <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> amahora"</string>
- <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> ihora <xliff:g id="MINUTES">%2$d</xliff:g> amaminithi"</string>
- <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> ihora <xliff:g id="MINUTES">%2$d</xliff:g> iminithi"</string>
- <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> amaminithi"</string>
- <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> iminithi <xliff:g id="SECONDS">%2$d</xliff:g> amasekhondi"</string>
- <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> iminithi <xliff:g id="SECONDS">%2$d</xliff:g> isekhondi"</string>
- <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> amasekhondi"</string>
- <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> isekhondi"</string>
<string name="untitled" msgid="4638956954852782576">"<Akunasihloko>"</string>
<string name="ellipsis" msgid="7899829516048813237">"..."</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
@@ -146,7 +135,6 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Vumelanisa"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Kunokususa <xliff:g id="CONTENT_TYPE">%s</xliff:g> okuningi kakhulu."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Isilondolozi sethebhulethi sigcwele! Susa amanye amafayela ukukhulula isikhala."</string>
- <string name="low_memory" product="watch" msgid="4415914910770005166">"Isitoreji sokubuka sigcwele. Susa amanye amafayela ukukhulula isikhala."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Isilondolozi sefoni sigcwele! Susa amanye amafayela ukukhulula isikhala."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Inethiwekhi ingase inganyelwe"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Ngenkampani yangaphandle engaziwa"</string>
@@ -164,7 +152,6 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Iringa iyasebenza"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Ivala shaqa..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Ithebhulethi yakho izocima."</string>
- <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ukubuka kwakho kuzocima."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Ifoni yakho izocima."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Ingabe ufuna ukucisha?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Qala kabusha emodini ephephile"</string>
@@ -184,12 +171,9 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Imodi yendiza"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Imodi yendiza IVULIWE"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Imodi yendiza IVALIWE"</string>
- <string name="global_action_settings" msgid="1756531602592545966">"Izilungiselelo"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</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="permgrouplab_costMoney" msgid="5429808217861460401">"Amasevisi abiza imali"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Yenza izinto ezingakudla imali."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Imiyalezo yakho"</string>
@@ -272,7 +256,7 @@
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"khipha izinqamuleli"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Ivumela uhlelo lokusebenza ukususa izinqamuleli zesikrini sasekhaya ngaphandle kokungenela komsebenzisi."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"thumela amakholi aphumayo kabusha"</string>
- <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Ivumela uhlelo lokusebenza ukubona inombolo eshayelwayo ngesikhathi sekholi ephumayo ngenketho yokuqondisa kabusha ikholi kwinombolo ehlukile noma ukuyekisa ikholi yonke."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5331318931937402040">"Ivumela uhlelo lokusebenza ukucubungula amakholi aphumayo futhi ishintshe inombolo ezoshayelwa. Le mvume ivumela uhlelo lokusebenza ukwengamela, liqondise kabusha, noma livikele amakholi aphumayo."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"thola imiyalezo ebhaliwe (i-SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Ivumela uhlelo lokusebenza ukuthola nokucubungula imilayezo ye-SMS. Loku kuchaza ukuthi uhlelo lokusebenza lungangamela noma lesuse imilayezo ethunyelwe kudivayisi yakho ngaphandle kokukubonisa yona."</string>
<string name="permlab_receiveMms" msgid="1821317344668257098">"thola imiyalezo ebhaliwe (i-MMS)"</string>
@@ -331,12 +315,12 @@
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Ivumela uhlelo lokusebenza ukuthi ithole okuqukethe kwi-Window. Izuhlelo lokusebenza ezinobungozi zingathola kabush iwindi eliphelele bese ibheka konke okuqukethwe ngaphandle kwaaaphasiwedi."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"nika amandla okwesikhashana ukufinyelela"</string>
<string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Ivumela uhlelo lokusebenza ukunika amandla ukufinyelela kwesikhashana kuvidayisi. Izinhlelo zokusebenza ezingalungile zinganika amandla ukufinyelela ngaphandle kwemvume yomsebenzisi."</string>
- <string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"buyisa ithokheni yewindi"</string>
- <string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Ivumela uhlelo lokusebenza ukuletha ithokheni yewindi. Izinhlelo zokusebenza ezinonya zingenza izenzo ezingagunyaziwe ngewindi lohlelo lokusebenza lizenze isistimu."</string>
- <string name="permlab_frameStats" msgid="7056374987314361639">"buyisa izibalo zefreyimu"</string>
- <string name="permdesc_frameStats" msgid="4758001089491284919">"Ivumela uhlelo lokusebenza ukuthi luqoqe izibalo zefreyimu. Izinhlelo zokusebenza ezinonya zingabona izibalo zefreyimu zamawindi kusuka kwezinye izinhlelo zokusebenza."</string>
+ <string name="permlab_retrieve_window_info" msgid="8532295199112519378">"buyisa ulwazi lewindi"</string>
+ <string name="permdesc_retrieve_window_info" msgid="4998836370424186849">"Ivumela uhlelo lokusebenza ukubuyisa ulwazi mayelana namawindi avela kumphathi wewindi. Izinhlelo zokusebenza zingabuyisa ulwazi olubhekiswe ukusetshenziselwa kohlelo lwangaphakathi."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"hlunga imicimbi"</string>
<string name="permdesc_filter_events" msgid="8006236315888347680">"Ivumela uhlelo lokusebenza ukubhalisa isihlungi sokufaka ukusakaza kwazo zonke izehlakalo zomsebenzisi ngaphambi kokuthunyelwa. Izinhlelo zokusebenza zingalawula i-UI yohlelo ngaphandle kokungena komsebenzisi."</string>
+ <string name="permlab_magnify_display" msgid="5973626738170618775">"lungisa ukubuka"</string>
+ <string name="permdesc_magnify_display" msgid="7121235684515003792">"Ivumela uhlelo lokusebenza ukusondeza okuqukethwe kokubukwa. Izinhlelo zokusebenza ezingalungile zidlulisela okuqukethwe kokubuka ngendlela eyenza idivayisi ingasebenziseki."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"ukuvala shaqa kwengxenye"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Ibeka imeneja yomsebenzi kwisimo sokuvala shaqa. Ayenzi ukuvala shaqa okuphelele."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"gwema ukushintsha kohlelo lokusebenza"</string>
@@ -351,8 +335,6 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Ivumela uhlelo lokusebenza ukuthi isakaze isaziso sokuthi umyalezo we-SMS utholakele. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukufoja imiyalezo ye-SMS engenayo."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"thumela umsakazo otholwe nge-WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Ivumela uhlelo lokusebenza ukuthi isakaze isaziso sokuthi umyalezo we-WAP PUSH utholakele. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukufoja ukutholakala kwemiyalezo ye-S noma zisuse okuqukethwe kwanoma iliphi ikhasi lewebhu eliqukethe okunobungozi."</string>
- <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"thumela ukusakaza kwamanethiwekhi ayisikolo"</string>
- <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Ivumela uhlelo lokusebenza ukusakaza isaziso sokuthi amanethiwekhi adinga isikolo. Awadingeki kuzinhlelo zokusebenza ezivamile."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"khawula inani lezinqubo ezisebenzayo"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Ivumela uhlelo lokusebenza ukuthi ilawule isibalo esikhulu sezinto eziqhubekayo eziyosebenza. Ayidingakeli izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"phoqa izinhlelo zokusebenza ezingemuva ukuthi zivaleke"</string>
@@ -400,14 +382,10 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Ivumela umnini ukuthi abophele kwissekelo esingaphezulu sesevisi ye-Vpm. Ayidingakeli izinhlelo zokusebenza ezejwayelekile."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"hlanganisa kwiphephadonga"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lwephephadonga. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
- <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"hlanganisa kusisebenzisani sezwi"</string>
- <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Ivumela umbambi ukuhlanganisa isixhumi esibonakalayo sesevisi yokusebenzisana yezwi. Akufanele kudingekele izinhlelo zokusebenza ezivamile."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bophezela kusibonisi sesilawuli kude"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ivumela umbambi ukuhlanganisa isixhumi esibonakalayo esisezingeni eliphezulu sesibonisi sesilawuli kude. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bophezela kube isevisi yesinqunjana"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lensizakalo yesinqunjwana. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
- <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bophezela kusevisi yomhlinzeki womzila"</string>
- <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Ivumela isibambi ukubophezela kunoma yimuphi umhlinzeki womzila obhalisiwe. Akufanele kudingeke izinhlelo zokusebenza ezivamile."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"xhumana nomphathi wedivaysi"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ivumela ummeli ukuthumela okuqukethwe kumphathi wedivaysi. Akusoze kwadingeka kwizinhlelo zokusebenza ezivamile."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"bophezela kokokufaka kwe-TV"</string>
@@ -447,8 +425,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ivumela uhlelo lokusebenza ukusebenzisa noma isiphi isiqophi semidiya esifakiwe ukuqopha ukudlala."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"phatha ukuqinisekisa okuthenjiwe"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ivumela uhlelo lokusebenza ukuthi lifake liphinde likhiphe izitifiketi ze-CA njengokuqinisekiswa okuthenjiwe."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"qalisa uhlelo lokusebenza ngesikhathi sokungenzi lutho"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Le mvume ivumela isistimu ye-Android ukuthi iqalise uhlelo lokusebenza ngemuva ngenkathi idivayisi ingasebenzi."</string>
+ <string name="permlab_bindIdleService" msgid="7521398788076342815">"bophezela kumasevisi angenzi lutho"</string>
+ <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Le mvume ivumela isistimu ye-Android ukuthi ibophezeleke kumasevisi angenzi lutho wohlelo lokusebenza."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"funda/bhalela emithombweni ephethwe idayegi"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Ivumela uhlelo lokusebenza ukufunda nokubhala kunoma yimuphi umthombo weqembu ledayegi; ngokwesibonelo, amafayela akwi/dev. Lokhu kungase kuthinte kakhulu ukuba nokuphepha kohlelo. Lokhu kumele kusebenziselwe KUPHELA ukuhlola ihadiwe okucacile ngumkhiqizi noma u-opheretha."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"vumela noma vimbela izingxenye zensiza"</string>
@@ -486,8 +464,6 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"Ivumela uhlelo lokusebenza ukuthi lifunde ulwazi lephrofayela lomuntu siqu olugcinwe kudivayisi yakho njengegama lakho kanye nolwazi lokuxhumana. Lokhu kuchaza ukuthi uhlelo lokusebenza lingakuhlonza bese lithumelela abanye ulwazi lakho lephrofayela."</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"guqula ikhadi lakho lokuxhumana"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"Ivumela uhlelo lokusebenza ukushintsha noma ingeze ulwazi lomuntu siqu lwephrofayela olulondolozwe kudivayisi yakho, njengegama lakho kanye nolwazi lokuxhumana. Lokhu kuchaza ukuthi ezinye izinhlelo zokusebenza zingakuhlonza bese zithumelela abanye ulwazi lephrofayela yakho."</string>
- <string name="permlab_bodySensors" msgid="4871091374767171066">"izinzwa zomzimba (njengeziqaphi zokulinganisela inhliziyo)"</string>
- <string name="permdesc_bodySensors" product="default" msgid="2998865085124153531">"Ivumela uhlelo lokusebenza ukuze lufinyelele kudatha esuka kuzinzwa ozisebenzisayo ukuze lulinganise ukuthi kwenzakalani phakathi komzimba wakho, njengokulinganisela kwenhliziyo."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"funda ngezindlela zakho zokuxhumana nabanye abantu"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"Ivumela uhlelo lokusebenza ukufinyelela nokuvumelanisa izibuyekezo zomphakathi ezivela kuwe nakubangani bakho. Qaphela uma waba ulwazi -- lokhu kuvumela uhlelo lokusebenza ukufunda ukuxhumana phakathi kwakho nabangani bakho kumanethiwekhi omphakathi, ngaphandle kokugcinwa kuyimfihlo. Qaphela: le mvume ingaphoqelelwa kuwo onke amanethiwekhi omphakathi."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"bhala indlela yakho yokuxhumana nabantu"</string>
@@ -589,8 +565,6 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Ivumela ukuthi uhlelo lokusebenza ilawule okuqukethwe ocingweni edivayisini. Insiza enalemvume ingaguquguqula amanethwekhi, ivule umsakazo wocingo iphinde iwucishe kanye nokunye okufana nalokho ngaphandle kokukwazisa."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"funda isimo sefoni kanye nesazisi"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ivumela uhlelo lokusebenza ukufinyelela izici zefoni zedivayisi. Le mvume ivumela uhlelo lokusebenza ukucacisa inombolo yefoni nobunikazi bedivayisi, ukuthi noma ikholi iyasebenza, futhi nenombolo yesilawuli kude zixhunywe ngekholi."</string>
- <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"funda izimo zefoni ezinembile"</string>
- <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Ivumelanisa uhlelo lokusebenza ukuthi lufinyelele kuzimo ezinembile zefoni. Le mvume ivumela uhlelo lokusebenza ukuthi linqume isimo sekholi sangempela, noma ikholi isebenza noma ingemuva, ikholi ihluleka, isimo esinembile sokuxhumeka kwedatha nokuhluleka kokuxhumeka kwedatha."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"gwema ithebhulethi ukuba ingalali"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"gwema ifoni ukuba ingalali"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ivumela uhlelo lokusebenza ukuthi linqande ithebulethi yakho ukuthi ilale."</string>
@@ -658,9 +632,6 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Shintsha isimo se-WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Ivumela uhlelo lokusebenza ukuxhuma ithebhulethi nokunqamula ithebhulethi kumanethiwekhi e-WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Ivumela uhlelo lokusebenza ukuxhuma ifoni nokuyinqamula kumanethiwekhi e-WiMAX."</string>
- <string name="permlab_scoreNetworks" msgid="6445777779383587181">"amanethiwekhi ayisikolo"</string>
- <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Ivumela uhlelo lokusebenza ukuthi lilinganise amanethiwekhi futhi lithuthukise ukuthi imaphi amanethiwekhi ithebhulethi okufanele iwakhethe."</string>
- <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Ivumela uhlelo lokusebenza ukuthi lilinganise amanethiwekhi futhi lithuthukise ukuthi imaphi amanethiwekhi ifoni okufanele iwakhethe."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"matanisa namadivayisi e-Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Ivumela uhlelo lokusebenza ukubuka ukucushwa kwe-Bluetooth kuthebhulethi, nokwenza futhi nokwamukela uxhumo namadivayisi amatanisiwe."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Ivumela uhlelo lokusebenza ukubuka ukucushwa kwe-Bluetooth efonini, ukwenza futhi nokwamukela uxhumo namadivayisi amatanisiwe."</string>
@@ -714,16 +685,10 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Ivumela uhlelo lokusebenza ukuthi lithole, lihlole, liphinde lisuse izaziso, ezifaka lezo ezithunyelwe ezinye izinhlelo zokusebenza."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"bophezela kwisevisi yomlaleli wesaziso"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Ivumela umbambi ukubophezela kwisixhumi esibonakalayo sezinga eliphezulu lesevisi yomlaleli wesaziso. Akusoze kwadingeka kwizinhlelo zokusebenza ezivamile."</string>
- <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"hlanganisa kwisevisi yomhlinzeki wesimo"</string>
- <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ivumela umbambi ukuhlanganisa isixhumi esibonakalayo seleveli ephezulu sesevisi yomhlinzeki wesimo. Akufanele kudingekele izinhlelo zokusebenza ezivamile."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"buyisela uhlelo lokusebenza lokulungiselelwa okunikezwe yinkampani yenethiwekhi"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ivumela umnikazi ukuthi abuyisele uhlelo lokusebenza lokulungiselelwa. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Lalela okubonwayo kuzimo zenethiwekhi"</string>
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Ivumela uhlelo lokusebenza ukuthi lulalele okubonwa kuzimo zenethiwekhi. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
- <string name="permlab_setInputCalibration" msgid="4902620118878467615">"guqula ukulinganisa kokufaka kwedivayisi"</string>
- <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Ivumela uhlelo lokusebenza ukuthi lushintshe imingcele yokulinganisa yesikrini esithintwayo. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"finyelela izitifiketi ze-DRM"</string>
- <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Ivumela uhlelo lokusebenza ekunikezweni nokusetshenziswa kwezitifiketi ze-DRM. Akufanele kudingeke kuzinhlelo zokusebenza ezivamile."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Misa imithetho yephasiwedi"</string>
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Lawula ubude nezinhlamvu ezivunyelwe kumaphasiwedi okuvula isikrini"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Gaka imizamo yokuvula isikrini"</string>
@@ -833,7 +798,7 @@
<string name="imProtocolYahoo" msgid="8271439408469021273">"i-Yahoo"</string>
<string name="imProtocolSkype" msgid="9019296744622832951">"i-Skype"</string>
<string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
- <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
+ <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Ama-Hangout"</string>
<string name="imProtocolIcq" msgid="1574870433606517315">"i-ICQ"</string>
<string name="imProtocolJabber" msgid="2279917630875771722">"i-Jabber"</string>
<string name="imProtocolNetMeeting" msgid="8287625655986827971">"Umhlangano we-Net"</string>
@@ -1356,10 +1321,6 @@
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Ivumela uhlelo lokusebenza ukuthi lufinyelele kusitoreji esiqashwa ngesikhiya esiphephile."</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Lawula ukubonisa nokufihla ukhiye wokuqapha"</string>
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Ivumela uhlelo lokusebenza ukuthi lulawule ukhiye wokuqapha."</string>
- <string name="permlab_trust_listener" msgid="1765718054003704476">"Lalela izinguquko zesimo sokuthemba."</string>
- <string name="permdesc_trust_listener" msgid="8233895334214716864">"Ivumela uhlelo lokusebenza ukuthi lilalelele izinguquko kusimo sethemba."</string>
- <string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bophezela kusevisi yomenzeli wethemba"</string>
- <string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ivumela uhlelo lokusebenza ukuthi libophezeleke kusevisi yomenzeli wethemba."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Ixhumana nesibuyekezo nesistimu yokutakula"</string>
<string name="permdesc_recovery" msgid="8511774533266359571">"Ivumela uhlelo lokusebenza ukuthi lixhumane nesistimu yokutakula nezibuyekezo zesistimu."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Thinta kabili ukulawula ukusondeza"</string>
@@ -1386,7 +1347,6 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Iphephadonga"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Shintsha iphephadonga"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Umlaleli wesaziso"</string>
- <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Umhlinzeki wesimo"</string>
<string name="vpn_title" msgid="19615213552042827">"I-VPN isiyasebenza"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"i-VPN ivuswe ngu <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Thinta ukuze wengamele inethiwekhi."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d9473ec..d490277 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -955,18 +955,33 @@
<!-- ============= -->
<!-- Color palette -->
<!-- ============= -->
- <attr name="colorPrimaryDark" format="color" />
+ <eat-comment />
+
+ <!-- The primary branding color for the app. By default, this is the color applied to the
+ action bar background and framework controls (via colorControlActivated). -->
<attr name="colorPrimary" format="color" />
+
+ <!-- Dark variant of the primary branding color. By default, this is the color applied to
+ the status bar (via statusBarColor) and navigation bar (via navigationBarColor). -->
+ <attr name="colorPrimaryDark" format="color" />
+
+ <!-- Light variant of the primary branding color. TODO: Not used? -->
<attr name="colorPrimaryLight" format="color" />
+
+ <!-- Bright complement to the primary branding color. TODO: Not used? -->
<attr name="colorAccent" format="color" />
+ <!-- The color applied to framework controls in their normal state. -->
<attr name="colorControlNormal" format="color" />
+
+ <!-- The color applied to framework controls in their activated (ex. checked) state. -->
<attr name="colorControlActivated" format="color" />
+ <!-- The color applied to framework buttons in their normal state. -->
<attr name="colorButtonNormal" format="color" />
+
+ <!-- The color applied to framework buttons in their pressed state. -->
<attr name="colorButtonPressed" format="color" />
- <attr name="colorButtonNormalColored" format="color" />
- <attr name="colorButtonPressedColored" format="color" />
</declare-styleable>
<!-- **************************************************************** -->
@@ -1760,6 +1775,35 @@
finishes. Corresponds to
{@link android.view.Window#setAllowExitTransitionOverlap(boolean)}. -->
<attr name="windowAllowExitTransitionOverlap"/>
+
+ <!-- Flag indicating whether this Window is responsible for drawing the background for the
+ system bars. If true and the window is not floating, the system bars are drawn with a
+ transparent background and the corresponding areas in this window are filled with the
+ colors specified in {@link android.R.attr#statusBarColor} and
+ {@link android.R.attr#navigationBarColor}. Corresponds to
+ {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS}. -->
+ <attr name="windowDrawsSystemBarBackgrounds" format="boolean" />
+
+ <!-- The color for the status bar. If the color is not opaque, consider setting
+ {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
+ {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
+ For this to take effect, the window must be drawing the system bar backgrounds with
+ {@link android.R.attr#windowDrawsSystemBarBackgrounds} and the status bar must not
+ have been requested to be translucent with
+ {@link android.R.attr#windowTranslucentStatus}.
+ Corresponds to {@link android.view.Window#setStatusBarColor(int)}. -->
+ <attr name="statusBarColor" format="color" />
+
+ <!-- The color for the navigation bar. If the color is not opaque, consider setting
+ {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
+ {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
+ For this to take effect, the window must be drawing the system bar backgrounds with
+ {@link android.R.attr#windowDrawsSystemBarBackgrounds} and the navigation bar must not
+ have been requested to be translucent with
+ {@link android.R.attr#windowTranslucentNavigation}.
+ Corresponds to {@link android.view.Window#setNavigationBarColor(int)}. -->
+ <attr name="navigationBarColor" format="color" />
+
</declare-styleable>
<!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -1775,6 +1819,7 @@
<attr name="bottomMedium" format="reference|color" />
<attr name="centerMedium" format="reference|color" />
<attr name="layout" />
+ <attr name="buttonPanelSideLayout" format="reference" />
<attr name="listLayout" format="reference" />
<attr name="multiChoiceItemLayout" format="reference" />
<attr name="singleChoiceItemLayout" format="reference" />
@@ -2355,11 +2400,9 @@
view with a theme override will inherit the themed context. -->
<attr name="theme" />
- <!-- Specifies that the shared name of the View to be shared with another Activity.
- When transitioning between Activities, the name links a UI element in the starting
- Activity to UI element in the called Activity. Names should be unique in the
- View hierarchy. -->
- <attr name="sharedElementName" format="string" />
+ <!-- Names a View such that it can be identified for Transitions. Names should be
+ unique in the View hierarchy. -->
+ <attr name="viewName" format="string" />
<!-- Specifies that this view should permit nested scrolling within a compatible
ancestor view. -->
@@ -2463,7 +2506,7 @@
when doing an Activity transition. Typically, the elements inside a
ViewGroup are each transitioned from the scene individually. The default
for a ViewGroup is false unless it has a background. See
- {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
+ {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.app.Activity,
android.view.View, String)} for more information. Corresponds to
{@link android.view.ViewGroup#setTransitionGroup(boolean)}.-->
<attr name="transitionGroup" format="boolean" />
@@ -3343,6 +3386,8 @@
<attr name="thumb" format="reference" />
<!-- An offset for the thumb that allows it to extend out of the range of the track. -->
<attr name="thumbOffset" format="dimension" />
+ <!-- Whether to split the track and leave a gap for the thumb drawable. -->
+ <attr name="splitTrack" format="boolean" />
</declare-styleable>
<declare-styleable name="StackView">
@@ -4239,6 +4284,58 @@
<attr name="autoMirrored"/>
</declare-styleable>
+ <!-- Drawable used to render several states with animated transitions. Each state
+ is represented by a child drawable with an optional keyframe ID. -->
+ <declare-styleable name="AnimatedStateListDrawable">
+ <!-- Indicates whether the drawable should be initially visible. -->
+ <attr name="visible" />
+ <!-- If true, allows the drawable's padding to change based on the
+ current state that is selected. If false, the padding will
+ stay the same (based on the maximum padding of all the states).
+ Enabling this feature requires that the owner of the drawable
+ deal with performing layout when the state changes, which is
+ often not supported. -->
+ <attr name="variablePadding" />
+ <!-- If true, the drawable's reported internal size will remain
+ constant as the state changes; the size is the maximum of all
+ of the states. If false, the size will vary based on the
+ current state. -->
+ <attr name="constantSize" />
+ <!-- Enables or disables dithering of the bitmap if the bitmap does not have the
+ same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with
+ an RGB 565 screen). -->
+ <attr name="dither" />
+ <!-- Amount of time (in milliseconds) to fade in a new state drawable. -->
+ <attr name="enterFadeDuration" />
+ <!-- Amount of time (in milliseconds) to fade out an old state drawable. -->
+ <attr name="exitFadeDuration" />
+ <!-- Indicates if the drawable needs to be mirrored when its layout direction is
+ RTL (right-to-left). -->
+ <attr name="autoMirrored"/>
+ </declare-styleable>
+
+ <!-- Transition used to animate between states with keyframe IDs. -->
+ <declare-styleable name="AnimatedStateListDrawableItem">
+ <!-- Reference to a drawable resource to use for the frame. If not
+ given, the drawable must be defined by the first child tag. -->
+ <attr name="drawable" />
+ <!-- Keyframe identifier for use in specifying transitions. -->
+ <attr name="id" />
+ </declare-styleable>
+
+ <!-- Transition used to animate between states with keyframe IDs. -->
+ <declare-styleable name="AnimatedStateListDrawableTransition">
+ <!-- Keyframe identifier for the starting state. -->
+ <attr name="fromId" format="reference" />
+ <!-- Keyframe identifier for the ending state. -->
+ <attr name="toId" format="reference" />
+ <!-- Reference to a animation drawable resource to use for the frame. If not
+ given, the animation drawable must be defined by the first child tag. -->
+ <attr name="drawable" />
+ <!-- Whether this transition is reversible. -->
+ <attr name="reversible" format="boolean" />
+ </declare-styleable>
+
<!-- Drawable used to render several animated frames. -->
<declare-styleable name="AnimationDrawable">
<attr name="visible" />
@@ -4921,6 +5018,15 @@
<attr name="startDelay" format="integer" />
<!-- Interpolator to be used in the animations spawned by this transition. -->
<attr name="interpolator" />
+ <!-- The match order to use for the transition. This is a comma-separated
+ list of values, containing one or more of the following:
+ id, itemId, viewName, instance. These correspond to
+ {@link android.transition.Transition#MATCH_ID},
+ {@link android.transition.Transition#MATCH_ITEM_ID},
+ {@link android.transition.Transition#MATCH_VIEW_NAME}, and
+ {@link android.transition.Transition#MATCH_INSTANCE}, respectively.
+ This corresponds to {@link android.transition.Transition#setMatchOrder(int...)}. -->
+ <attr name="matchOrder" format="string" />
</declare-styleable>
<!-- Use <code>fade</code>as the root tag of the XML resource that
@@ -4968,10 +5074,14 @@
<attr name="targetId" format="reference" />
<!-- The id of a target to exclude from this transition. -->
<attr name="excludeId" format="reference" />
- <!-- The fully-qualified name of the Class to exclude from this transition. -->
- <attr name="excludeClass" format="string" />
<!-- The fully-qualified name of the Class to include in this transition. -->
<attr name="targetClass" />
+ <!-- The fully-qualified name of the Class to exclude from this transition. -->
+ <attr name="excludeClass" format="string" />
+ <!-- The viewName of the target on which this transition will animation changes. -->
+ <attr name="targetViewName" format="string" />
+ <!-- The viewName of the target to exclude from this transition. -->
+ <attr name="excludeViewName" format="string" />
</declare-styleable>
<!-- Use <code>set</code> as the root tag of the XML resource that
@@ -6341,6 +6451,8 @@
<attr name="switchMinWidth" format="dimension" />
<!-- Minimum space between the switch and caption text -->
<attr name="switchPadding" format="dimension" />
+ <!-- Whether to split the track and leave a gap for the thumb drawable. -->
+ <attr name="splitTrack" />
</declare-styleable>
<declare-styleable name="Pointer">
@@ -6553,4 +6665,8 @@
<attr name="layout_gravity" />
</declare-styleable>
+ <!-- Used as a filter array on the theme to pull out only the EdgeEffect-relevant bits. -->
+ <declare-styleable name="EdgeEffect">
+ <attr name="colorPrimaryLight" />
+ </declare-styleable>
</resources>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 7d3fb44..ad29505 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -120,6 +120,9 @@
<color name="micro_text_light">#434343</color>
+ <color name="leanback_dark_gray">#ff333333</color>
+ <color name="leanback_light_gray">#ff888888</color>
+
<drawable name="notification_template_icon_bg">#3333B5E5</drawable>
<drawable name="notification_template_icon_low_bg">#0cffffff</drawable>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f39155b..463dda2 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -462,6 +462,19 @@
provide full support for multiple displays. -->
<integer name="config_undockedHdmiRotation">-1</integer>
+ <!-- HDMI-CEC logical device types allowed on the system. Logical device types
+ are defined in HDMI-CEC standard 1.4 as follows:
+ 0 TV
+ 1 Recording Device
+ 2 Reserved
+ 3 Tuner
+ 4 Playback
+ 5 Audio System
+ 6 Pure CEC Switch
+ 7 Video Processor -->
+ <integer-array name="config_hdmiCecLogicalDeviceType">
+ </integer-array>
+
<!-- Control the default UI mode type to use when there is no other type override
happening. One of the following values (See Configuration.java):
1 UI_MODE_TYPE_NORMAL
@@ -1393,8 +1406,11 @@
<item>com.android.inputmethod.latin</item>
</string-array>
- <string-array name="config_notificationScorers">
- <item>com.android.internal.notification.PeopleNotificationScorer</item>
+ <!-- The list of classes that should be added to the notification ranking pipline.
+ See {@link com.android.server.notification.NotificationSignalExtractor} -->
+ <string-array name="config_notificationSignalExtractors">
+ <item>com.android.server.notification.ValidateNotificationPeople</item>
+ <item>com.android.server.notification.NotificationIntrusivenessExtractor</item>
</string-array>
<!-- Flag indicating that this device does not rotate and will always remain in its default
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6b2c788..69b11cd 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -143,10 +143,16 @@
<!-- Preferred width of the search view. -->
<dimen name="search_view_preferred_width">320dip</dimen>
+ <!-- Dialog padding for round display -->
+ <dimen name="alert_dialog_round_padding">27dip</dimen>
<!-- Dialog title height -->
<dimen name="alert_dialog_title_height">64dip</dimen>
<!-- Dialog button bar height -->
<dimen name="alert_dialog_button_bar_height">48dip</dimen>
+ <!-- Leanback dialog vertical margin -->
+ <dimen name="leanback_alert_dialog_vertical_margin">27dip</dimen>
+ <!-- Leanback dialog horizontal margin -->
+ <dimen name="leanback_alert_dialog_horizontal_margin">54dip</dimen>
<!-- Default height of an action bar. -->
<dimen name="action_bar_default_height">48dip</dimen>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 889c368..6ea0fae 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -82,7 +82,6 @@
<item type="id" name="action_bar_spinner" />
<item type="id" name="current_scene" />
<item type="id" name="scene_layoutid_cache" />
- <item type="id" name="shared_element_name" />
<item type="id" name="mask" />
<item type="id" name="shared_element" />
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4e584c0..7cd242b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2114,7 +2114,7 @@
<public type="attr" name="controlY1" />
<public type="attr" name="controlX2" />
<public type="attr" name="controlY2" />
- <public type="attr" name="sharedElementName" />
+ <public type="attr" name="viewName" />
<public type="attr" name="transitionGroup" />
<public type="attr" name="viewportWidth" />
<public type="attr" name="viewportHeight" />
@@ -2136,8 +2136,6 @@
<public type="attr" name="colorControlActivated" />
<public type="attr" name="colorButtonNormal" />
<public type="attr" name="colorButtonPressed" />
- <public type="attr" name="colorButtonNormalColored" />
- <public type="attr" name="colorButtonPressedColored" />
<public type="attr" name="persistable" />
<public type="attr" name="titleTextAppearance" />
<public type="attr" name="subtitleTextAppearance" />
@@ -2166,6 +2164,16 @@
<public type="attr" name="documentLaunchMode" />
<public type="attr" name="autoRemoveFromRecents" />
<public type="attr" name="stateListAnimator" />
+ <public type="attr" name="toId" />
+ <public type="attr" name="fromId" />
+ <public type="attr" name="reversible" />
+ <public type="attr" name="splitTrack" />
+ <public type="attr" name="targetViewName" />
+ <public type="attr" name="excludeViewName" />
+ <public type="attr" name="matchOrder" />
+ <public type="attr" name="windowDrawsSystemBarBackgrounds" />
+ <public type="attr" name="statusBarColor"/>
+ <public type="attr" name="navigationBarColor"/>
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
@@ -2174,7 +2182,6 @@
<public-padding type="id" name="l_resource_pad" end="0x01020040" />
- <public type="id" name="shared_element_name" />
<public type="id" name="mask" />
<public type="id" name="shared_element" />
@@ -2266,6 +2273,12 @@
<public type="style" name="Theme.Quantum.Light.NoActionBar.TranslucentDecor" />
<public type="style" name="Theme.Quantum.Light.Panel" />
+ <public type="style" name="ThemeOverlay" />
+ <public type="style" name="ThemeOverlay.Quantum" />
+ <public type="style" name="ThemeOverlay.Quantum.Light" />
+ <public type="style" name="ThemeOverlay.Quantum.Dark" />
+ <public type="style" name="ThemeOverlay.Quantum.ActionBarWidget" />
+
<public type="style" name="Widget.Quantum" />
<public type="style" name="Widget.Quantum.ActionBar" />
<public type="style" name="Widget.Quantum.ActionBar.Solid" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 97400b2..8286ef9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -953,10 +953,11 @@
Malicious apps may use this to forge MMS message receipt or to
silently replace the content of any webpage with malicious variants.</string>
+ <!-- TODO: Mark these as translatable when API is finalized. -->
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_broadcastScoreNetworks">send score networks broadcast</string>
+ <string name="permlab_broadcastScoreNetworks" translatable="false">send score networks broadcast</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_broadcastScoreNetworks">Allows the app
+ <string name="permdesc_broadcastScoreNetworks" translatable="false">Allows the app
to broadcast a notification that networks need to be scored.
Never needed for normal apps.
</string>
diff --git a/core/res/res/values/styles_leanback.xml b/core/res/res/values/styles_leanback.xml
new file mode 100644
index 0000000..a37da4e
--- /dev/null
+++ b/core/res/res/values/styles_leanback.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <style name="DialogWindowTitle.Leanback" parent="DialogWindowTitle.Holo">
+ <item name="android:textAppearance">@style/TextAppearance.Leanback.DialogWindowTitle</item>
+ </style>
+
+ <style name="TextAppearance.Leanback.DialogWindowTitle" parent="TextAppearance.Holo.DialogWindowTitle">
+ <item name="android:fontFamily">sans-serif-condensed</item>
+ <item name="android:textColor">?attr/textColorPrimary</item>
+ </style>
+
+ <style name="Leanback.ButtonBar" parent="Holo.ButtonBar">
+ <item name="showDividers">none</item>
+ </style>
+
+ <style name="AlertDialog.Leanback" parent="AlertDialog.Holo">
+ <item name="layout">@android:layout/alert_dialog_leanback</item>
+ <item name="buttonPanelSideLayout">@android:layout/alert_dialog_leanback_button_panel_right</item>
+ <item name="progressLayout">@android:layout/progress_dialog_leanback</item>
+ <item name="fullDark">@android:color/background_dark</item>
+ <item name="topDark">@android:color/background_dark</item>
+ <item name="centerDark">@android:color/background_dark</item>
+ <item name="bottomDark">@android:color/background_dark</item>
+ <item name="fullBright">@android:color/background_dark</item>
+ <item name="topBright">@android:color/background_dark</item>
+ <item name="centerBright">@android:color/background_dark</item>
+ <item name="bottomBright">@android:color/background_dark</item>
+ <item name="bottomMedium">@android:color/background_dark</item>
+ <item name="centerMedium">@android:color/background_dark</item>
+ </style>
+
+ <style name="AlertDialog.Leanback.Light">
+ <item name="fullDark">@android:color/leanback_light_gray</item>
+ <item name="topDark">@android:color/leanback_light_gray</item>
+ <item name="centerDark">@android:color/leanback_light_gray</item>
+ <item name="bottomDark">@android:color/leanback_light_gray</item>
+ <item name="fullBright">@android:color/leanback_light_gray</item>
+ <item name="topBright">@android:color/leanback_light_gray</item>
+ <item name="centerBright">@android:color/leanback_light_gray</item>
+ <item name="bottomBright">@android:color/leanback_light_gray</item>
+ <item name="bottomMedium">@android:color/leanback_light_gray</item>
+ <item name="centerMedium">@android:color/leanback_light_gray</item>
+ </style>
+
+</resources>
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index bdaa49d..5bac1f9 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -15,6 +15,16 @@
-->
<resources>
<style name="AlertDialog.Micro" parent="AlertDialog.Holo.Light">
+ <item name="fullDark">@null</item>
+ <item name="topDark">@null</item>
+ <item name="centerDark">@null</item>
+ <item name="bottomDark">@null</item>
+ <item name="fullBright">@null</item>
+ <item name="topBright">@null</item>
+ <item name="centerBright">@null</item>
+ <item name="bottomBright">@null</item>
+ <item name="bottomMedium">@null</item>
+ <item name="centerMedium">@null</item>
<item name="layout">@layout/alert_dialog_micro</item>
</style>
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index 88a2a9f..e693673 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -455,10 +455,10 @@
<style name="Widget.Quantum.CompoundButton.Switch">
<item name="track">@drawable/switch_track_quantum</item>
<item name="thumb">@drawable/switch_inner_quantum</item>
+ <item name="splitTrack">true</item>
<item name="switchTextAppearance">@style/TextAppearance.Quantum.Widget.Switch</item>
<item name="textOn"></item>
<item name="textOff"></item>
- <item name="thumbTextPadding">12dip</item>
<item name="switchMinWidth">72dip</item>
<item name="switchPadding">16dip</item>
<item name="background">?attr/selectableItemBackground</item>
@@ -572,10 +572,8 @@
<item name="indeterminateOnly">false</item>
<item name="progressDrawable">@drawable/scrubber_progress_horizontal_quantum</item>
<item name="indeterminateDrawable">@drawable/scrubber_progress_horizontal_quantum</item>
- <item name="minHeight">13dip</item>
- <item name="maxHeight">13dip</item>
<item name="thumb">@drawable/scrubber_control_selector_quantum</item>
- <item name="thumbOffset">16dip</item>
+ <item name="splitTrack">true</item>
<item name="focusable">true</item>
<item name="paddingStart">16dip</item>
<item name="paddingEnd">16dip</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2bf72e8..84c9023 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -120,6 +120,7 @@
<java-symbol type="id" name="overlay_display_window_title" />
<java-symbol type="id" name="package_label" />
<java-symbol type="id" name="packages_list" />
+ <java-symbol type="id" name="parentPanel" />
<java-symbol type="id" name="pause" />
<java-symbol type="id" name="perms_list" />
<java-symbol type="id" name="perm_icon" />
@@ -325,6 +326,7 @@
<java-symbol type="color" name="tab_indicator_text_v4" />
<java-symbol type="dimen" name="accessibility_touch_slop" />
+ <java-symbol type="dimen" name="alert_dialog_round_padding"/>
<java-symbol type="dimen" name="config_prefDialogWidth" />
<java-symbol type="dimen" name="config_viewConfigurationTouchSlop" />
<java-symbol type="dimen" name="config_viewMinFlingVelocity" />
@@ -1301,6 +1303,7 @@
<java-symbol type="anim" name="dock_right_enter" />
<java-symbol type="anim" name="dock_right_exit" />
+ <java-symbol type="array" name="config_hdmiCecLogicalDeviceType" />
<java-symbol type="array" name="config_keyboardTapVibePattern" />
<java-symbol type="array" name="config_longPressVibePattern" />
<java-symbol type="array" name="config_safeModeDisabledVibePattern" />
@@ -1628,6 +1631,7 @@
<java-symbol type="string" name="wifi_display_notification_disconnect" />
<java-symbol type="style" name="Theme.Dialog.AppError" />
<java-symbol type="style" name="Theme.Micro.Dialog.Alert" />
+ <java-symbol type="style" name="Theme.Leanback.Dialog.Alert" />
<java-symbol type="style" name="Theme.Toast" />
<java-symbol type="xml" name="storage_list" />
<java-symbol type="bool" name="config_dreamsSupported" />
@@ -1653,7 +1657,7 @@
<java-symbol type="id" name="button_always" />
<java-symbol type="integer" name="config_globalActionsKeyTimeout" />
<java-symbol type="integer" name="config_maxResolverActivityColumns" />
- <java-symbol type="array" name="config_notificationScorers" />
+ <java-symbol type="array" name="config_notificationSignalExtractors" />
<java-symbol type="layout" name="notification_quantum_action" />
<java-symbol type="layout" name="notification_quantum_action_list" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 34ef508..743ad61 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -189,6 +189,9 @@
<item name="windowCloseOnTouchOutside">false</item>
<item name="windowTranslucentStatus">false</item>
<item name="windowTranslucentNavigation">false</item>
+ <item name="windowDrawsSystemBarBackgrounds">false</item>
+ <item name="statusBarColor">@android:color/black</item>
+ <item name="navigationBarColor">@android:color/black</item>
<!-- Define these here; ContextThemeWrappers around themes that define them should
always clear these values. -->
@@ -1811,12 +1814,7 @@
<item name="android:windowCloseOnTouchOutside">false</item>
</style>
- <!-- Holo theme for alert dialog windows, which is used by the
- {@link android.app.AlertDialog} class. This is basically a dialog
- but sets the background to empty so it can do two-tone backgrounds.
- For applications targeting Honeycomb or newer, this is the default
- AlertDialog theme. -->
- <style name="Theme.Holo.Dialog.Alert">
+ <style name="Theme.Holo.Dialog.BaseAlert">
<item name="windowBackground">@android:color/transparent</item>
<item name="windowTitleStyle">@android:style/DialogWindowTitle.Holo</item>
<item name="windowContentOverlay">@null</item>
@@ -1824,6 +1822,13 @@
<item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
</style>
+ <!-- Holo theme for alert dialog windows, which is used by the
+ {@link android.app.AlertDialog} class. This is basically a dialog
+ but sets the background to empty so it can do two-tone backgrounds.
+ For applications targeting Honeycomb or newer, this is the default
+ AlertDialog theme. -->
+ <style name="Theme.Holo.Dialog.Alert" parent="Theme.Holo.Dialog.BaseAlert"/>
+
<!-- Holo theme for the TimePicker dialog windows, which is used by the
{@link android.app.TimePickerDialog} class. -->
<style name="Theme.Holo.Dialog.TimePicker">
@@ -1934,12 +1939,7 @@
parent="@android:style/Theme.Holo.Light.NoActionBar">
</style>
- <!-- Holo light theme for alert dialog windows, which is used by the
- {@link android.app.AlertDialog} class. This is basically a dialog
- but sets the background to empty so it can do two-tone backgrounds.
- For applications targeting Honeycomb or newer, this is the default
- AlertDialog theme. -->
- <style name="Theme.Holo.Light.Dialog.Alert">
+ <style name="Theme.Holo.Light.Dialog.BaseAlert">
<item name="windowBackground">@android:color/transparent</item>
<item name="windowTitleStyle">@android:style/DialogWindowTitle.Holo.Light</item>
<item name="windowContentOverlay">@null</item>
@@ -1947,6 +1947,13 @@
<item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
</style>
+ <!-- Holo light theme for alert dialog windows, which is used by the
+ {@link android.app.AlertDialog} class. This is basically a dialog
+ but sets the background to empty so it can do two-tone backgrounds.
+ For applications targeting Honeycomb or newer, this is the default
+ AlertDialog theme. -->
+ <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Holo.Light.Dialog.BaseAlert"/>
+
<!-- Holo Light theme for the TimePicker dialog windows, which is used by the
{@link android.app.TimePickerDialog} class. -->
<style name="Theme.Holo.Light.Dialog.TimePicker">
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index dbc3d9e..aee35ef 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -174,7 +174,7 @@
<item name="actionBarTabTextStyle">@style/Widget.DeviceDefault.ActionBar.TabText</item>
<item name="actionModeStyle">@style/Widget.DeviceDefault.ActionMode</item>
<item name="actionModeCloseButtonStyle">@style/Widget.DeviceDefault.ActionButton.CloseMode</item>
- <item name="actionBarStyle">@style/Widget.DeviceDefault.ActionBar</item>
+ <item name="actionBarStyle">@style/Widget.DeviceDefault.ActionBar.Solid</item>
<item name="actionModePopupWindowStyle">@style/Widget.DeviceDefault.PopupWindow.ActionMode</item>
<item name="buttonBarStyle">@style/DeviceDefault.ButtonBar</item>
@@ -435,7 +435,7 @@
<item name="actionBarTabTextStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabText</item>
<item name="actionModeStyle">@style/Widget.DeviceDefault.Light.ActionMode</item>
<item name="actionModeCloseButtonStyle">@style/Widget.DeviceDefault.Light.ActionButton.CloseMode</item>
- <item name="actionBarStyle">@style/Widget.DeviceDefault.Light.ActionBar</item>
+ <item name="actionBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.Solid</item>
<item name="actionModePopupWindowStyle">@style/Widget.DeviceDefault.Light.PopupWindow.ActionMode</item>
<item name="buttonBarStyle">@style/DeviceDefault.Light.ButtonBar</item>
@@ -469,18 +469,7 @@
<!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
inverse color profile. -->
- <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Quantum.Light.DarkActionBar" >
- <item name="actionBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.Solid.Inverse</item>
- <item name="actionDropDownStyle">@style/Widget.DeviceDefault.Spinner.DropDown.ActionBar</item>
- <item name="actionButtonStyle">@style/Widget.DeviceDefault.ActionButton</item>
- <item name="actionOverflowButtonStyle">@style/Widget.DeviceDefault.ActionButton.Overflow</item>
- <item name="actionBarTabStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabView.Inverse</item>
- <item name="actionBarTabBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabBar.Inverse</item>
- <item name="actionBarTabTextStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabText.Inverse</item>
- <item name="actionModeStyle">@style/Widget.DeviceDefault.Light.ActionMode.Inverse</item>
- <item name="actionModeCloseButtonStyle">@style/Widget.DeviceDefault.ActionButton.CloseMode</item>
- <item name="actionModePopupWindowStyle">@style/Widget.DeviceDefault.PopupWindow.ActionMode</item>
- </style>
+ <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Quantum.Light.DarkActionBar" />
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
<style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Quantum.Light.NoActionBar" />
diff --git a/core/res/res/values/themes_leanback.xml b/core/res/res/values/themes_leanback.xml
new file mode 100644
index 0000000..eba8dec
--- /dev/null
+++ b/core/res/res/values/themes_leanback.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <style name="Theme.Leanback.Dialog.Alert" parent="Theme.Holo.Dialog.BaseAlert">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Leanback</item>
+ <item name="alertDialogStyle">@style/AlertDialog.Leanback</item>
+ <item name="buttonBarStyle">@style/Leanback.ButtonBar</item>
+ <item name="listDividerAlertDialog">@null</item>
+ </style>
+
+ <style name="Theme.Leanback.Light.Dialog.Alert" parent="Theme.Holo.Light.Dialog.BaseAlert">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Leanback</item>
+ <item name="alertDialogStyle">@style/AlertDialog.Leanback.Light</item>
+ <item name="buttonBarStyle">@style/Leanback.ButtonBar</item>
+ <item name="listDividerAlertDialog">@null</item>
+ </style>
+
+ <style name="Theme.Leanback.Light.Dialog" parent="Theme.Holo.Light.Dialog">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Leanback</item>
+ </style>
+
+ <style name="Theme.Leanback.Dialog" parent="Theme.Holo.Dialog">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Leanback</item>
+ </style>
+
+ <style name="Theme.Leanback.Dialog.AppError" parent="Theme.Leanback.Dialog">
+ <item name="windowFrame">@null</item>
+ <item name="windowBackground">@color/transparent</item>
+ <item name="windowIsFloating">true</item>
+ <item name="windowContentOverlay">@null</item>
+ <item name="windowCloseOnTouchOutside">false</item>
+ <item name="alertDialogStyle">@style/AlertDialog.Leanback</item>
+ </style>
+</resources>
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index 39df700..9647947 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -47,10 +47,15 @@
<item name="textAppearanceInverse">@style/TextAppearance.Micro</item>
</style>
- <style name="Theme.Micro.Dialog.Alert" parent="Theme.Holo.Light.Dialog.Alert">
+ <style name="Theme.Micro.Dialog.Alert">
<item name="windowTitleStyle">@style/DialogWindowTitle.Micro</item>
<item name="alertDialogStyle">@style/AlertDialog.Micro</item>
<item name="windowIsFloating">false</item>
+ <item name="windowBackground">@android:color/transparent</item>
+ <item name="windowOverscan">true</item>
+ <item name="windowContentOverlay">@null</item>
+ <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
+ <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
</style>
<style name="Theme.Micro.Dialog.AppError" parent="Theme.Micro.Dialog">
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index 768fd9a..ccae90f 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -122,8 +122,8 @@
<item name="listDivider">@drawable/list_divider_quantum</item>
<item name="listSeparatorTextViewStyle">@style/Widget.Quantum.TextView.ListSeparator</item>
- <item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum</item>
- <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum</item>
+ <item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum_anim</item>
+ <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum_anim</item>
<item name="listChoiceBackgroundIndicator">@drawable/list_selector_quantum</item>
@@ -161,6 +161,9 @@
<item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
<item name="windowActionBar">true</item>
<item name="windowActionModeOverlay">false</item>
+ <item name="windowDrawsSystemBarBackgrounds">true</item>
+ <item name="statusBarColor">?attr/colorPrimaryDark</item>
+ <item name="navigationBarColor">?attr/colorPrimaryDark</item>
<!-- Dialog attributes -->
<item name="dialogTheme">@style/Theme.Quantum.Dialog</item>
@@ -303,8 +306,8 @@
<item name="actionBarStyle">@style/Widget.Quantum.ActionBar.Solid</item>
<item name="actionBarSize">@dimen/action_bar_default_height_quantum</item>
<item name="actionModePopupWindowStyle">@style/Widget.Quantum.PopupWindow.ActionMode</item>
- <item name="actionBarWidgetTheme">@null</item>
- <item name="actionBarTheme">@style/ThemeOverlay.Quantum.ActionBarWidget</item>
+ <item name="actionBarWidgetTheme">@style/ThemeOverlay.Quantum.ActionBarWidget</item>
+ <item name="actionBarTheme">@null</item>
<item name="actionBarItemBackground">@drawable/item_background_quantum</item>
<item name="actionModeCutDrawable">@drawable/ic_menu_cut_quantum</item>
@@ -377,9 +380,6 @@
<item name="colorControlActivated">?attr/colorPrimary</item>
<item name="colorButtonNormal">@color/quantum_grey_700</item>
<item name="colorButtonPressed">@color/quantum_grey_500</item>
- <!-- TODO: Remove these attrs and move into button style. -->
- <item name="colorButtonNormalColored">?attr/colorPrimary</item>
- <item name="colorButtonPressedColored">?attr/colorPrimaryLight</item>
</style>
<!-- Quantum Paper theme (light version). -->
@@ -466,8 +466,8 @@
<item name="listDivider">@drawable/list_divider_quantum</item>
<item name="listSeparatorTextViewStyle">@style/Widget.Quantum.Light.TextView.ListSeparator</item>
- <item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum</item>
- <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum</item>
+ <item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum_anim</item>
+ <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum_anim</item>
<item name="listChoiceBackgroundIndicator">@drawable/list_selector_quantum</item>
@@ -504,6 +504,9 @@
<item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
<item name="windowActionBar">true</item>
<item name="windowActionModeOverlay">false</item>
+ <item name="windowDrawsSystemBarBackgrounds">true</item>
+ <item name="statusBarColor">?attr/colorPrimaryDark</item>
+ <item name="navigationBarColor">?attr/colorPrimaryDark</item>
<!-- Dialog attributes -->
<item name="dialogTheme">@style/Theme.Quantum.Light.Dialog</item>
@@ -649,8 +652,8 @@
<item name="actionBarStyle">@style/Widget.Quantum.Light.ActionBar.Solid</item>
<item name="actionBarSize">@dimen/action_bar_default_height_quantum</item>
<item name="actionModePopupWindowStyle">@style/Widget.Quantum.Light.PopupWindow.ActionMode</item>
- <item name="actionBarWidgetTheme">@null</item>
- <item name="actionBarTheme">@style/ThemeOverlay.Quantum.Light.ActionBarWidget</item>
+ <item name="actionBarWidgetTheme">@style/ThemeOverlay.Quantum.ActionBarWidget</item>
+ <item name="actionBarTheme">@null</item>
<item name="actionBarItemBackground">@drawable/item_background_quantum</item>
<item name="actionModeCutDrawable">@drawable/ic_menu_cut_quantum</item>
@@ -721,29 +724,93 @@
<item name="colorButtonPressed">@color/quantum_grey_500</item>
</style>
- <style name="ThemeOverlay" />
- <style name="ThemeOverlay.Quantum" />
- <style name="ThemeOverlay.Quantum.Light" />
-
- <!-- Variant of the quantum theme that replaces the activated control color
- (which by default is identical to the action bar background color) with
- the normal control color . -->
- <style name="ThemeOverlay.Quantum.ActionBarWidget">
- <item name="colorControlActivated">?attr/colorControlNormal</item>
- </style>
-
- <!-- Variant of the quantum (light) theme that replaces the activated control
- color (which by default is identical to the action bar background color)
- with the normal control color . -->
- <style name="ThemeOverlay.Quantum.Light.ActionBarWidget">
- <item name="colorControlActivated">?attr/colorControlNormal</item>
- </style>
-
<!-- Variant of the quantum (light) theme that has a solid (opaque) action bar
with an inverse color profile. The dark action bar sharply stands out against
the light content. -->
<style name="Theme.Quantum.Light.DarkActionBar">
- <!-- TODO -->
+ <item name="actionBarWidgetTheme">@style/ThemeOverlay.Quantum.ActionBarWidget</item>
+ <item name="actionBarTheme">@style/ThemeOverlay.Quantum.Dark</item>
+ </style>
+
+ <style name="ThemeOverlay" />
+ <style name="ThemeOverlay.Quantum" />
+
+ <!-- Theme overlay that replaces colors with their light versions but preserves
+ the value of colorAccent, colorPrimary and its variants. -->
+ <style name="ThemeOverlay.Quantum.Light">
+ <item name="colorForeground">@color/bright_foreground_quantum_light</item>
+ <item name="colorForegroundInverse">@color/bright_foreground_quantum_dark</item>
+ <item name="colorBackground">@color/background_quantum_light</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_quantum_light</item>
+
+ <item name="textColorPrimary">@color/primary_text_quantum_light</item>
+ <item name="textColorPrimaryInverse">@color/primary_text_quantum_dark</item>
+ <item name="textColorSecondary">@color/secondary_text_quantum_light</item>
+ <item name="textColorSecondaryInverse">@color/secondary_text_quantum_dark</item>
+ <item name="textColorTertiary">@color/tertiary_text_quantum_light</item>
+ <item name="textColorTertiaryInverse">@color/tertiary_text_quantum_dark</item>
+ <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_quantum_light</item>
+ <item name="textColorPrimaryInverseDisableOnly">@color/primary_text_disable_only_quantum_dark</item>
+ <item name="textColorHint">@color/hint_foreground_quantum_light</item>
+ <item name="textColorHintInverse">@color/hint_foreground_quantum_dark</item>
+ <item name="textColorHighlight">@color/highlighted_text_quantum_light</item>
+ <item name="textColorHighlightInverse">@color/highlighted_text_quantum_dark</item>
+ <item name="textColorLink">@color/quantum_teal_500</item>
+ <item name="textColorLinkInverse">@color/quantum_teal_500</item>
+ <item name="textColorSearchUrl">@color/search_url_text_quantum_light</item>
+ <item name="textColorAlertDialogListItem">@color/primary_text_quantum_light</item>
+
+ <item name="textCheckMark">@drawable/indicator_check_mark_light</item>
+ <item name="textCheckMarkInverse">@drawable/indicator_check_mark_dark</item>
+
+ <item name="windowBackground">@color/background_quantum_light</item>
+
+ <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_light</item>
+ <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_light</item>
+
+ <item name="colorButtonNormal">@color/quantum_grey_100</item>
+ </style>
+
+ <!-- Theme overlay that replaces colors with their dark versions but preserves
+ the value of colorAccent, colorPrimary and its variants. -->
+ <style name="ThemeOverlay.Quantum.Dark">
+ <item name="colorForeground">@color/bright_foreground_quantum_dark</item>
+ <item name="colorForegroundInverse">@color/bright_foreground_quantum_light</item>
+ <item name="colorBackground">@color/background_quantum_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_quantum_dark</item>
+
+ <item name="textColorPrimary">@color/primary_text_quantum_dark</item>
+ <item name="textColorPrimaryInverse">@color/primary_text_quantum_light</item>
+ <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_quantum_dark</item>
+ <item name="textColorSecondary">@color/secondary_text_quantum_dark</item>
+ <item name="textColorSecondaryInverse">@color/secondary_text_quantum_light</item>
+ <item name="textColorTertiary">@color/tertiary_text_quantum_dark</item>
+ <item name="textColorTertiaryInverse">@color/tertiary_text_quantum_light</item>
+ <item name="textColorHint">@color/hint_foreground_quantum_dark</item>
+ <item name="textColorHintInverse">@color/hint_foreground_quantum_light</item>
+ <item name="textColorHighlight">@color/highlighted_text_quantum_dark</item>
+ <item name="textColorHighlightInverse">@color/highlighted_text_quantum_light</item>
+ <item name="textColorLink">@color/quantum_teal_500</item>
+ <item name="textColorLinkInverse">@color/quantum_teal_500</item>
+ <item name="textColorSearchUrl">@color/search_url_text_quantum_dark</item>
+ <item name="textColorAlertDialogListItem">@color/primary_text_quantum_dark</item>
+
+ <item name="textCheckMark">@drawable/indicator_check_mark_dark</item>
+ <item name="textCheckMarkInverse">@drawable/indicator_check_mark_light</item>
+
+ <item name="windowBackground">@color/background_quantum_dark</item>
+
+ <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_dark</item>
+ <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_dark</item>
+
+ <item name="colorButtonNormal">@color/quantum_grey_700</item>
+ </style>
+
+ <!-- Theme overlay that replaces the activated control color (which by default
+ is identical to the action bar background color) with the normal control
+ color. -->
+ <style name="ThemeOverlay.Quantum.ActionBarWidget">
+ <item name="colorControlActivated">?attr/colorControlNormal</item>
</style>
<!-- Variant of the quantum (dark) theme with no action bar. -->
diff --git a/core/tests/coretests/src/android/net/LinkSocketTest.java b/core/tests/coretests/src/android/net/LinkSocketTest.java
deleted file mode 100644
index af77d63..0000000
--- a/core/tests/coretests/src/android/net/LinkSocketTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.net.LinkSocket;
-import android.test.suitebuilder.annotation.SmallTest;
-import junit.framework.TestCase;
-
-/**
- * Test LinkSocket
- */
-public class LinkSocketTest extends TestCase {
-
- @SmallTest
- public void testBasic() throws Exception {
- LinkSocket ls;
-
- ls = new LinkSocket();
- ls.close();
- }
-
- @SmallTest
- public void testLinkCapabilities() throws Exception {
- LinkCapabilities lc;
-
- lc = new LinkCapabilities();
- assertEquals(0, lc.size());
- assertEquals(true, lc.isEmpty());
- }
-}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/AndroidManifest.xml
index d69a63b..6bd47c2 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/AndroidManifest.xml
@@ -7,6 +7,7 @@
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18"/>
<application
+ android:name=".TestApplication"
android:label="multidexlegacytestapp"
>
<activity
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Annotated.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Annotated.java
new file mode 100644
index 0000000..603c573
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Annotated.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.multidexlegacytestapp;
+
+@AnnotationWithEnum2(ReferencedByAnnotationWithOtherReferences.A)
+public class Annotated {
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Annotated2.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Annotated2.java
new file mode 100644
index 0000000..eed6875
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Annotated2.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.multidexlegacytestapp;
+
+@AnnotationWithClass(ReferencedByClassInAnnotation.class)
+public class Annotated2 {
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/AnnotationWithClass.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/AnnotationWithClass.java
new file mode 100644
index 0000000..378a024
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/AnnotationWithClass.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.multidexlegacytestapp;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AnnotationWithClass {
+
+ Class<?> value();
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/AnnotationWithEnum.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/AnnotationWithEnum.java
new file mode 100644
index 0000000..15855d5
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/AnnotationWithEnum.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.multidexlegacytestapp;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AnnotationWithEnum {
+
+ ReferencedByAnnotation value();
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/AnnotationWithEnum2.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/AnnotationWithEnum2.java
new file mode 100644
index 0000000..ce37b18
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/AnnotationWithEnum2.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.multidexlegacytestapp;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AnnotationWithEnum2 {
+
+ ReferencedByAnnotationWithOtherReferences value();
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/InterfaceWithEnum.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/InterfaceWithEnum.java
new file mode 100644
index 0000000..085c0a3
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/InterfaceWithEnum.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.multidexlegacytestapp;
+
+public interface InterfaceWithEnum {
+
+ ReferencedByInterface getEnum();
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/MainActivity.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/MainActivity.java
index 3228825..5bc03f1 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/MainActivity.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/MainActivity.java
@@ -17,7 +17,6 @@
import android.app.Activity;
import android.os.Bundle;
-import android.support.multidex.MultiDex;
import android.util.Log;
import android.widget.TextView;
@@ -36,9 +35,6 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
- Log.i(TAG, "onCreate");
- MultiDex.install(getApplicationContext());
- Log.i(TAG, "Multi dex installation done.");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int value = getValue();
@@ -94,4 +90,8 @@
return value;
}
+ public int getAnnotation2Value() {
+ return ((AnnotationWithEnum2) TestApplication.annotation2).value().get();
+ }
+
}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/ReferencedByAnnotation.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/ReferencedByAnnotation.java
new file mode 100644
index 0000000..0aa6995
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/ReferencedByAnnotation.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.multidexlegacytestapp;
+
+public enum ReferencedByAnnotation {
+
+ A,
+ B;
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/ReferencedByAnnotationWithOtherReferences.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/ReferencedByAnnotationWithOtherReferences.java
new file mode 100644
index 0000000..8cc0d9d
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/ReferencedByAnnotationWithOtherReferences.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.multidexlegacytestapp;
+
+public enum ReferencedByAnnotationWithOtherReferences {
+
+ A {
+ private ReferencedByEnum a = new ReferencedByEnum();
+ @Override
+ public int get() {
+ return a.hashCode();
+ }
+ },
+ B {
+ private ReferencedByEnum b = new ReferencedByEnum();
+ @Override
+ public int get() {
+ return b.hashCode();
+ }
+ };
+
+
+ public abstract int get();
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/ReferencedByClassInAnnotation.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/ReferencedByClassInAnnotation.java
new file mode 100644
index 0000000..06aa560
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/ReferencedByClassInAnnotation.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.multidexlegacytestapp;
+
+public enum ReferencedByClassInAnnotation {
+
+ A {
+ private ReferencedByEnum a = new ReferencedByEnum();
+ @Override
+ public int get() {
+ return a.hashCode();
+ }
+ },
+ B {
+ private ReferencedByEnum b = new ReferencedByEnum();
+ @Override
+ public int get() {
+ return b.hashCode();
+ }
+ };
+
+
+ public abstract int get();
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/ReferencedByEnum.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/ReferencedByEnum.java
new file mode 100644
index 0000000..1ceb3d3
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/ReferencedByEnum.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.multidexlegacytestapp;
+
+public class ReferencedByEnum {
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/ReferencedByInterface.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/ReferencedByInterface.java
new file mode 100644
index 0000000..17f1449
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/ReferencedByInterface.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.multidexlegacytestapp;
+
+public enum ReferencedByInterface {
+
+ A,
+ B;
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Test.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Test.java
index 59cac07..bbdd3e5 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Test.java
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/Test.java
@@ -17,6 +17,11 @@
import android.test.ActivityInstrumentationTestCase2;
+/**
+ * Run the tests with: <code>adb shell am instrument -w
+ com.android.multidexlegacytestapp/android.test.InstrumentationTestRunner
+</code>
+ */
public class Test extends ActivityInstrumentationTestCase2<MainActivity> {
public Test() {
super(MainActivity.class);
@@ -25,4 +30,23 @@
public void testAllClassesAvailable() {
assertEquals(3366, getActivity().getValue());
}
+
+ public void testAnnotation() {
+ assertEquals(ReferencedByAnnotation.B,
+ ((AnnotationWithEnum) TestApplication.annotation).value());
+ assertEquals(ReferencedByAnnotation.B,
+ ((AnnotationWithEnum) TestApplication.getAnnotationWithEnum()).value());
+ // Just to verify that it doesn't crash
+ getActivity().getAnnotation2Value();
+
+ assertEquals(ReferencedByClassInAnnotation.class,
+ ((AnnotationWithClass) TestApplication.annotation3).value());
+ // Just to verify that it doesn't crash
+ ReferencedByClassInAnnotation.A.get();
+ }
+
+ public void testInterface() {
+ assertEquals(InterfaceWithEnum.class,
+ TestApplication.interfaceClass);
+ }
}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/TestApplication.java b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/TestApplication.java
new file mode 100644
index 0000000..c52ad29
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/src/com/android/multidexlegacytestapp/TestApplication.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.multidexlegacytestapp;
+
+import android.support.multidex.MultiDexApplication;
+
+import java.lang.annotation.Annotation;
+
+@AnnotationWithEnum(ReferencedByAnnotation.B)
+public class TestApplication extends MultiDexApplication {
+
+ public static Annotation annotation = getAnnotationWithEnum();
+ public static Annotation annotation2 = getSoleAnnotation(Annotated.class);
+ public static Annotation annotation3 = getSoleAnnotation(Annotated2.class);
+ public static Class<?> interfaceClass = InterfaceWithEnum.class;
+
+ public static Annotation getAnnotationWithEnum() {
+ return getSoleAnnotation(TestApplication.class);
+ }
+
+ public static Annotation getSoleAnnotation(Class<?> annotated) {
+ Annotation[] annot = annotated.getAnnotations();
+ if (annot.length == 1) {
+ return annot[0];
+ }
+
+ throw new AssertionError();
+ }
+
+}
diff --git a/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java b/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
index 59a6314..7d72f3e 100644
--- a/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
+++ b/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
@@ -52,18 +52,21 @@
public void testBuilder() throws Exception {
final int SELECTION_START = 30;
final int SELECTION_END = 40;
- final int CANDIDATES_START = 32;
- final int CANDIDATES_END = 33;
+ final int COMPOSING_TEXT_START = 32;
+ final String COMPOSING_TEXT = "test";
final float INSERTION_MARKER_HORIZONTAL = 10.5f;
final float INSERTION_MARKER_TOP = 100.1f;
final float INSERTION_MARKER_BASELINE = 110.4f;
final float INSERTION_MARKER_BOTOM = 111.0f;
+ final int CHAR_INDEX = 32;
+ final char CHAR_VALUE = 'X';
+ final char DEFAULT_CHAR_VALUE = '!';
Matrix TRANSFORM_MATRIX = new Matrix(Matrix.IDENTITY_MATRIX);
TRANSFORM_MATRIX.setScale(10.0f, 20.0f);
final CursorAnchorInfoBuilder builder = new CursorAnchorInfoBuilder();
builder.setSelectionRange(SELECTION_START, SELECTION_END)
- .setCandidateRange(CANDIDATES_START, CANDIDATES_END)
+ .setComposingText(COMPOSING_TEXT_START, COMPOSING_TEXT)
.setInsertionMarkerLocation(INSERTION_MARKER_HORIZONTAL, INSERTION_MARKER_TOP,
INSERTION_MARKER_BASELINE, INSERTION_MARKER_BOTOM)
.setMatrix(TRANSFORM_MATRIX);
@@ -77,8 +80,8 @@
final CursorAnchorInfo info = builder.build();
assertEquals(SELECTION_START, info.getSelectionStart());
assertEquals(SELECTION_END, info.getSelectionEnd());
- assertEquals(CANDIDATES_START, info.getCandidatesStart());
- assertEquals(CANDIDATES_END, info.getCandidatesEnd());
+ assertEquals(COMPOSING_TEXT_START, info.getComposingTextStart());
+ assertEquals(COMPOSING_TEXT, info.getComposingText());
assertEquals(INSERTION_MARKER_HORIZONTAL, info.getInsertionMarkerHorizontal());
assertEquals(INSERTION_MARKER_TOP, info.getInsertionMarkerTop());
assertEquals(INSERTION_MARKER_BASELINE, info.getInsertionMarkerBaseline());
@@ -93,8 +96,8 @@
final CursorAnchorInfo info2 = builder.build();
assertEquals(SELECTION_START, info2.getSelectionStart());
assertEquals(SELECTION_END, info2.getSelectionEnd());
- assertEquals(CANDIDATES_START, info2.getCandidatesStart());
- assertEquals(CANDIDATES_END, info2.getCandidatesEnd());
+ assertEquals(COMPOSING_TEXT_START, info2.getComposingTextStart());
+ assertEquals(COMPOSING_TEXT, info2.getComposingText());
assertEquals(INSERTION_MARKER_HORIZONTAL, info2.getInsertionMarkerHorizontal());
assertEquals(INSERTION_MARKER_TOP, info2.getInsertionMarkerTop());
assertEquals(INSERTION_MARKER_BASELINE, info2.getInsertionMarkerBaseline());
@@ -111,8 +114,8 @@
final CursorAnchorInfo info3 = cloneViaParcel(info2);
assertEquals(SELECTION_START, info3.getSelectionStart());
assertEquals(SELECTION_END, info3.getSelectionEnd());
- assertEquals(CANDIDATES_START, info3.getCandidatesStart());
- assertEquals(CANDIDATES_END, info3.getCandidatesEnd());
+ assertEquals(COMPOSING_TEXT_START, info3.getComposingTextStart());
+ assertEquals(COMPOSING_TEXT, info3.getComposingText());
assertEquals(INSERTION_MARKER_HORIZONTAL, info3.getInsertionMarkerHorizontal());
assertEquals(INSERTION_MARKER_TOP, info3.getInsertionMarkerTop());
assertEquals(INSERTION_MARKER_BASELINE, info3.getInsertionMarkerBaseline());
@@ -128,13 +131,40 @@
final CursorAnchorInfo uninitializedInfo = builder.build();
assertEquals(-1, uninitializedInfo.getSelectionStart());
assertEquals(-1, uninitializedInfo.getSelectionEnd());
- assertEquals(-1, uninitializedInfo.getCandidatesStart());
- assertEquals(-1, uninitializedInfo.getCandidatesEnd());
+ assertEquals(-1, uninitializedInfo.getComposingTextStart());
+ assertNull(uninitializedInfo.getComposingText());
assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerHorizontal());
assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerTop());
assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBaseline());
assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBottom());
- assertEquals(Matrix.IDENTITY_MATRIX, uninitializedInfo.getMatrix());
+ }
+
+ @SmallTest
+ public void testMatrixIsCopied() throws Exception {
+ final Matrix MATRIX1 = new Matrix();
+ MATRIX1.setTranslate(10.0f, 20.0f);
+ final Matrix MATRIX2 = new Matrix();
+ MATRIX2.setTranslate(110.0f, 120.0f);
+ final Matrix MATRIX3 = new Matrix();
+ MATRIX3.setTranslate(210.0f, 220.0f);
+ final Matrix matrix = new Matrix();
+ final CursorAnchorInfoBuilder builder = new CursorAnchorInfoBuilder();
+
+ matrix.set(MATRIX1);
+ builder.setMatrix(matrix);
+ matrix.postRotate(90.0f);
+
+ final CursorAnchorInfo firstInstance = builder.build();
+ assertEquals(MATRIX1, firstInstance.getMatrix());
+ matrix.set(MATRIX2);
+ builder.setMatrix(matrix);
+ final CursorAnchorInfo secondInstance = builder.build();
+ assertEquals(MATRIX1, firstInstance.getMatrix());
+ assertEquals(MATRIX2, secondInstance.getMatrix());
+
+ matrix.set(MATRIX3);
+ assertEquals(MATRIX1, firstInstance.getMatrix());
+ assertEquals(MATRIX2, secondInstance.getMatrix());
}
@SmallTest
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 97c1b33..452c575 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -33,10 +33,14 @@
endef
##########################################
-# We may only afford small font footprint.
+# The following fonts are distributed as symlink only.
##########################################
$(eval $(call create-font-symlink,DroidSans.ttf,Roboto-Regular.ttf))
$(eval $(call create-font-symlink,DroidSans-Bold.ttf,Roboto-Bold.ttf))
+$(eval $(call create-font-symlink,DroidSerif-Regular.ttf,NotoSerif-Regular.ttf))
+$(eval $(call create-font-symlink,DroidSerif-Bold.ttf,NotoSerif-Bold.ttf))
+$(eval $(call create-font-symlink,DroidSerif-Italic.ttf,NotoSerif-Italic.ttf))
+$(eval $(call create-font-symlink,DroidSerif-BoldItalic.ttf,NotoSerif-BoldItalic.ttf))
################################
# On space-constrained devices, we include a subset of fonts:
@@ -45,14 +49,6 @@
extra_font_files := DroidSans.ttf DroidSans-Bold.ttf
else
include $(CLEAR_VARS)
-LOCAL_MODULE := DroidSansEthiopic-Regular.ttf
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
LOCAL_MODULE := MTLmr3m.ttf
LOCAL_SRC_FILES := $(LOCAL_MODULE)
LOCAL_MODULE_CLASS := ETC
@@ -64,7 +60,6 @@
extra_font_files := \
DroidSans.ttf \
DroidSans-Bold.ttf \
- DroidSansEthiopic-Regular.ttf \
MTLmr3m.ttf
endif # SMALLER_FONT_FOOTPRINT
@@ -102,10 +97,6 @@
Roboto-Bold.ttf \
Roboto-Italic.ttf \
Roboto-BoldItalic.ttf \
- DroidSerif-Regular.ttf \
- DroidSerif-Bold.ttf \
- DroidSerif-Italic.ttf \
- DroidSerif-BoldItalic.ttf \
DroidSansMono.ttf \
Clockopia.ttf \
AndroidClock.ttf \
@@ -135,12 +126,6 @@
RobotoCondensed-BoldItalic.ttf \
RobotoCondensed-Light.ttf \
RobotoCondensed-LightItalic.ttf \
- DroidNaskh-Regular.ttf \
- DroidNaskhUI-Regular.ttf \
- DroidSansHebrew-Regular.ttf \
- DroidSansHebrew-Bold.ttf \
- DroidSansArmenian.ttf \
- DroidSansGeorgian.ttf \
AndroidEmoji.ttf
endif # !MINIMAL_FONT
diff --git a/data/fonts/DroidNaskh-Bold.ttf b/data/fonts/DroidNaskh-Bold.ttf
deleted file mode 100644
index 14d8768..0000000
--- a/data/fonts/DroidNaskh-Bold.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidNaskh-Regular.ttf b/data/fonts/DroidNaskh-Regular.ttf
deleted file mode 100644
index 03662f2..0000000
--- a/data/fonts/DroidNaskh-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidNaskhUI-Regular.ttf b/data/fonts/DroidNaskhUI-Regular.ttf
deleted file mode 100644
index c961de2..0000000
--- a/data/fonts/DroidNaskhUI-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSansArabic.ttf b/data/fonts/DroidSansArabic.ttf
deleted file mode 100644
index bdefaac..0000000
--- a/data/fonts/DroidSansArabic.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSansArmenian.ttf b/data/fonts/DroidSansArmenian.ttf
deleted file mode 100644
index 6fafa54..0000000
--- a/data/fonts/DroidSansArmenian.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSansEthiopic-Bold.ttf b/data/fonts/DroidSansEthiopic-Bold.ttf
deleted file mode 100644
index e06cac2..0000000
--- a/data/fonts/DroidSansEthiopic-Bold.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSansEthiopic-Regular.ttf b/data/fonts/DroidSansEthiopic-Regular.ttf
deleted file mode 100644
index 0adcbbe..0000000
--- a/data/fonts/DroidSansEthiopic-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSansGeorgian.ttf b/data/fonts/DroidSansGeorgian.ttf
deleted file mode 100644
index 3a2e9fb..0000000
--- a/data/fonts/DroidSansGeorgian.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSansHebrew-Bold.ttf b/data/fonts/DroidSansHebrew-Bold.ttf
deleted file mode 100644
index c1acb38..0000000
--- a/data/fonts/DroidSansHebrew-Bold.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSansHebrew-Regular.ttf b/data/fonts/DroidSansHebrew-Regular.ttf
deleted file mode 100644
index af6a58d..0000000
--- a/data/fonts/DroidSansHebrew-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSerif-Bold.ttf b/data/fonts/DroidSerif-Bold.ttf
deleted file mode 100644
index 16a914e..0000000
--- a/data/fonts/DroidSerif-Bold.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSerif-BoldItalic.ttf b/data/fonts/DroidSerif-BoldItalic.ttf
deleted file mode 100644
index 50324fc..0000000
--- a/data/fonts/DroidSerif-BoldItalic.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSerif-Italic.ttf b/data/fonts/DroidSerif-Italic.ttf
deleted file mode 100644
index bb2757c..0000000
--- a/data/fonts/DroidSerif-Italic.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/DroidSerif-Regular.ttf b/data/fonts/DroidSerif-Regular.ttf
deleted file mode 100644
index da0a2cc..0000000
--- a/data/fonts/DroidSerif-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index ede7ef4..c2d5afe 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -31,23 +31,26 @@
<familyset>
<family>
<fileset>
- <file variant="elegant">DroidNaskh-Regular.ttf</file>
+ <file variant="elegant">NotoNaskh-Regular.ttf</file>
+ <file variant="elegant">NotoNaskh-Bold.ttf</file>
</fileset>
</family>
<family>
<fileset>
- <file variant="compact">DroidNaskhUI-Regular.ttf</file>
+ <file variant="compact">NotoNaskhUI-Regular.ttf</file>
+ <file variant="compact">NotoNaskhUI-Bold.ttf</file>
</fileset>
</family>
<family>
<fileset>
- <file>DroidSansEthiopic-Regular.ttf</file>
+ <file>NotoSansEthiopic-Regular.ttf</file>
+ <file>NotoSansEthiopic-Bold.ttf</file>
</fileset>
</family>
<family>
<fileset>
- <file>DroidSansHebrew-Regular.ttf</file>
- <file>DroidSansHebrew-Bold.ttf</file>
+ <file>NotoSansHebrew-Regular.ttf</file>
+ <file>NotoSansHebrew-Bold.ttf</file>
</fileset>
</family>
<family>
@@ -64,12 +67,14 @@
</family>
<family>
<fileset>
- <file>DroidSansArmenian.ttf</file>
+ <file>NotoSansArmenian-Regular.ttf</file>
+ <file>NotoSansArmenian-Bold.ttf</file>
</fileset>
</family>
<family>
<fileset>
- <file>DroidSansGeorgian.ttf</file>
+ <file>NotoSansGeorgian-Regular.ttf</file>
+ <file>NotoSansGeorgian-Bold.ttf</file>
</fileset>
</family>
<family>
@@ -84,6 +89,32 @@
<file variant="compact">NotoSansDevanagariUI-Bold.ttf</file>
</fileset>
</family>
+ <!-- Gujarati should come after Devanagari -->
+ <family>
+ <fileset>
+ <file variant="elegant">NotoSansGujarati-Regular.ttf</file>
+ <file variant="elegant">NotoSansGujarati-Bold.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
+ <file variant="compact">NotoSansGujaratiUI-Regular.ttf</file>
+ <file variant="compact">NotoSansGujaratiUI-Bold.ttf</file>
+ </fileset>
+ </family>
+ <!-- Gurmukhi should come after Devanagari -->
+ <family>
+ <fileset>
+ <file variant="elegant">NotoSansGurmukhi-Regular.ttf</file>
+ <file variant="elegant">NotoSansGurmukhi-Bold.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
+ <file variant="compact">NotoSansGurmukhiUI-Regular.ttf</file>
+ <file variant="compact">NotoSansGurmukhiUI-Bold.ttf</file>
+ </fileset>
+ </family>
<family>
<fileset>
<file variant="elegant">NotoSansTamil-Regular.ttf</file>
@@ -146,6 +177,12 @@
</family>
<family>
<fileset>
+ <file>NotoSansSinhala-Regular.ttf</file>
+ <file>NotoSansSinhala-Bold.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
<file variant="elegant">NotoSansKhmer-Regular.ttf</file>
<file variant="elegant">NotoSansKhmer-Bold.ttf</file>
</fileset>
@@ -170,18 +207,24 @@
</family>
<family>
<fileset>
+ <file variant="elegant">NotoSansMyanmar-Regular.ttf</file>
+ <file variant="elegant">NotoSansMyanmar-Bold.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
+ <file variant="compact">NotoSansMyanmarUI-Regular.ttf</file>
+ <file variant="compact">NotoSansMyanmarUI-Bold.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
<file>NanumGothic.ttf</file>
</fileset>
</family>
<family>
<fileset>
- <file>Padauk-book.ttf</file>
- <file>Padauk-bookbold.ttf</file>
- </fileset>
- </family>
- <family>
- <fileset>
- <file>NotoSansSymbols-Regular.ttf</file>
+ <file>NotoSansSymbols-Regular-Subsetted.ttf</file>
</fileset>
</family>
<family>
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index 293ecc8..2312a04 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -34,17 +34,7 @@
RobotoCondensed-BoldItalic.ttf \
RobotoCondensed-Light.ttf \
RobotoCondensed-LightItalic.ttf \
- DroidNaskh-Regular.ttf \
- DroidNaskhUI-Regular.ttf \
- DroidSansHebrew-Regular.ttf \
- DroidSansHebrew-Bold.ttf \
- DroidSerif-Regular.ttf \
- DroidSerif-Bold.ttf \
- DroidSerif-Italic.ttf \
- DroidSerif-BoldItalic.ttf \
DroidSansMono.ttf \
- DroidSansArmenian.ttf \
- DroidSansGeorgian.ttf \
AndroidEmoji.ttf \
Clockopia.ttf \
AndroidClock.ttf \
diff --git a/data/fonts/system_fonts.xml b/data/fonts/system_fonts.xml
index a8d23ee..97b7fd8 100644
--- a/data/fonts/system_fonts.xml
+++ b/data/fonts/system_fonts.xml
@@ -89,10 +89,10 @@
<name>ITC Stone Serif</name>
</nameset>
<fileset>
- <file>DroidSerif-Regular.ttf</file>
- <file>DroidSerif-Bold.ttf</file>
- <file>DroidSerif-Italic.ttf</file>
- <file>DroidSerif-BoldItalic.ttf</file>
+ <file>NotoSerif-Regular.ttf</file>
+ <file>NotoSerif-Bold.ttf</file>
+ <file>NotoSerif-Italic.ttf</file>
+ <file>NotoSerif-BoldItalic.ttf</file>
</fileset>
</family>
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index fc60e1f..58cf523 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -81,7 +81,7 @@
to: /guide/components/aidl.html
- from: /guide/publishing/publishing.html
- to: /distribute/googleplay/publish/preparing.html
+ to: /distribute/tools/launch-checklist.html
- from: /guide/publishing/...
to: /tools/publishing/...
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index bddb8ec..c61a94b 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -1,4 +1,7 @@
page.title=Dashboards
+page.metaDescription=page.metaDescription=Charts that give you an overview of device characteristics and platform versions that are active in the Android ecosystem.
+page.tags="android, dashboard, platforms, versions"
+meta.tags="ecosystem, versions, whatsnew"
@jd:body
<style>
@@ -22,7 +25,7 @@
<div class="sidebox">
<h2>Google Play Install Stats</h2>
<p>The Google Play Developer Console also provides <a
-href="{@docRoot}distribute/googleplay/about/distribution.html#stats">detailed statistics</a>
+href="{@docRoot}distribute/googleplay/developer-console.html#app-stats">detailed statistics</a>
about your users' devices. Those stats may help you prioritize the device profiles for which
you optimize your app.</p>
</div>
diff --git a/docs/html/design/index.jd b/docs/html/design/index.jd
index 7c7c5d9..cb7dd4f 100644
--- a/docs/html/design/index.jd
+++ b/docs/html/design/index.jd
@@ -1,5 +1,7 @@
page.title=Design
page.viewport_width=970
+section.landing=true
+meta.tags="beautifulapps, design, ux, patterns, holo, appquality, landing"
header.hide=1
footer.hide=1
@jd:body
diff --git a/docs/html/design/patterns/multi-pane-layouts.jd b/docs/html/design/patterns/multi-pane-layouts.jd
index c207006..4e99462 100644
--- a/docs/html/design/patterns/multi-pane-layouts.jd
+++ b/docs/html/design/patterns/multi-pane-layouts.jd
@@ -1,6 +1,7 @@
page.title=Multi-pane Layouts
page.tags="tablet","navigation","layout","fragment"
-page.metaDescription=Android devices come in many different screen sizes and types. Multi-pane layouts help you provide a balanced and aesthetically pleasing layout across the range of Android devices.
+page.metaDescription=Design guide with examples of how to flatten navigation and provide improved layout across the range of Android devices.
+
@jd:body
diff --git a/docs/html/design/patterns/navigation.jd b/docs/html/design/patterns/navigation.jd
index 3edf6ba..703528e 100644
--- a/docs/html/design/patterns/navigation.jd
+++ b/docs/html/design/patterns/navigation.jd
@@ -1,5 +1,6 @@
page.title=Navigation with Back and Up
-page.tags=navigation,activity,task,up navigation,back navigation
+page.tags="navigation","activity","task","up navigation","back navigation"
+page.image=/design/media/navigation_between_siblings_gmail.png
@jd:body
<a class="notice-developers" href="{@docRoot}training/implementing-navigation/index.html">
diff --git a/docs/html/design/patterns/widgets.jd b/docs/html/design/patterns/widgets.jd
index 654cf37..47acc7b 100644
--- a/docs/html/design/patterns/widgets.jd
+++ b/docs/html/design/patterns/widgets.jd
@@ -1,5 +1,6 @@
page.title=Widgets
-page.tags=appwidget,home
+page.tags="appwidget","home"
+page.metaDescription=Design guide to creating widgets that are easy to use and look great.
@jd:body
<a class="notice-developers" href="{@docRoot}guide/topics/appwidgets/index.html">
diff --git a/docs/html/design/style/devices-displays.jd b/docs/html/design/style/devices-displays.jd
index a8f9d6f..6a7234b 100644
--- a/docs/html/design/style/devices-displays.jd
+++ b/docs/html/design/style/devices-displays.jd
@@ -1,7 +1,9 @@
page.title=Devices and Displays
+page.metaDescription=Take advantage of Android's flexible layout system and create apps that gracefully scale from phones to tablets and beyond.
+
@jd:body
-<p>Android powers millions of phones, tablets, and other devices in a wide variety of screen sizes and
+<p>Android powers hundreds of millions of phones, tablets, and other devices in a wide variety of screen sizes and
form factors. By taking advantage of Android's flexible layout system, you can create apps that
gracefully scale from large tablets to smaller phones.</p>
diff --git a/docs/html/design/style/metrics-grids.jd b/docs/html/design/style/metrics-grids.jd
index a553475..e92d57e 100644
--- a/docs/html/design/style/metrics-grids.jd
+++ b/docs/html/design/style/metrics-grids.jd
@@ -1,5 +1,8 @@
page.title=Metrics and Grids
-page.tags=layout,screens
+page.metaDescription=Optimize your app's UI by designing layouts based on density-independent grids.
+page.tags="layout","screens"
+meta.tags="multiple screens, layout, tablets"
+page.image=/design/media/metrics_closeup.png
@jd:body
<p>Devices vary not only in physical size, but also in screen density (<acronym title="Dots per
diff --git a/docs/html/design/style/typography.jd b/docs/html/design/style/typography.jd
index ec6fba2..6923f0b 100644
--- a/docs/html/design/style/typography.jd
+++ b/docs/html/design/style/typography.jd
@@ -1,5 +1,6 @@
page.title=Typography
-page.tags=textview,font
+page.tags="textview","font"
+page.metaDescription=How to use typography in your Android apps.
@jd:body
<div class="layout-content-row">
diff --git a/docs/html/develop/index.jd b/docs/html/develop/index.jd
index eb28da8..bb90cca 100644
--- a/docs/html/develop/index.jd
+++ b/docs/html/develop/index.jd
@@ -1,6 +1,8 @@
fullpage=true
-page.title=Develop
+page.title=Develop Apps
page.viewport_width=970
+meta.tags="develop, getstarted, sdk, appquality, landing"
+section.landing=true
header.hide=1
carousel=1
tabbedList=1
diff --git a/docs/html/distribute/distribute_toc.cs b/docs/html/distribute/distribute_toc.cs
deleted file mode 100644
index 1fabcb3..0000000
--- a/docs/html/distribute/distribute_toc.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-<ul id="nav">
-
- <li class="nav-section">
- <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/index.html">Google Play</a></div>
- <ul>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/about/visibility.html">Visibility</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/about/monetizing.html">Monetizing</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/about/distribution.html">Distribution</a></li>
- </ul>
- </li>
-
- <li class="nav-section">
- <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/publish/index.html">Publishing</a></div>
- <ul>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/register.html">Get Started</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/console.html">Developer Console</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/localizing.html">Localization Checklist</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/preparing.html">Launch Checklist</a></li>
- </ul>
- </li>
-
-<!-- <li class="nav-section">
- <div class="nav-section-header">
- <a href="<?cs var:toroot ?>distribute/googleplay/developer-console.html">The Developer Console</a>
- </div>
- <ul>
- <li class="nav-section"><a href="<?cs var:toroot ?>distribute/googleplay/register.html">Get Started</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/distribution-controls.html">Managing Distribution</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/pricing-billing.html">Pricing and Billing</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/app-data.html">Reviewing App Data</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/advanced-options.html">Advanced Options</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/publishing.html">Publishing and Updating</a></li>
- </ul>
- </li> end of Developer Console -->
-
- <li class="nav-section">
- <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/promote/index.html">Promoting</a>
- </div>
- <ul>
-<!-- <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/product-pages.html">Your Product Pages</a></li> -->
- <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/linking.html">Linking to Your Products</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/badges.html">Google Play Badges</a></li>
- <li><a href="<?cs var:toroot ?>distribute/promote/device-art.html">Device Art Generator</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/brand.html">Brand Guidelines</a></li>
- </ul>
- </li>
-
- <li class="nav-section">
- <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/quality/index.html">App Quality</a></div>
- <ul>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/core.html">Core App Quality</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/tablet.html">Tablet App Quality</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/strategies/app-quality.html">Improving App Quality</a></li>
- </ul>
- </li>
-
- <li class="nav-section">
- <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/policies/index.html">Policies</a></div>
- <ul>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/policies/spam.html">Spam</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/policies/ip.html">Intellectual<br />Property</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/policies/ads.html">Ads</a></li>
- </ul>
- </li>
-
-<!--
- <li class="nav-section">
- <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/after.html">
- After Launch</a>
- </div>
- <ul>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/errors.html.html">Reviewing Errors</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/reviews.html">Tracking User Reviews</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/supporting-users.html">Supporting Users</a></li>
- </ul>
- </li>
--->
-
- <li class="nav-section">
- <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/index.html">Spotlight</a></div>
- <ul>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/tablets.html">Tablet Stories</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/games.html">Game Stories</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/localization.html">Localization Stories</a></li>
- </ul>
- </li>
-
- <li class="nav-section">
- <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/edu/index.html">Google Play for Education</a></div>
- <ul>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/about.html">About</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/start.html">Get Started</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/guidelines.html">Guidelines</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/faq.html">FAQ</a></li>
- <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/contact.html">Sign Up</a></li>
- </ul>
- </li>
-
- <li class="nav-section">
- <div class="nav-section-header empty"><a href="<?cs var:toroot ?>distribute/open.html">Open Distribution</a></div>
- </li>
-</ul>
-
\ No newline at end of file
diff --git a/docs/html/distribute/engage/app-updates.jd b/docs/html/distribute/engage/app-updates.jd
new file mode 100644
index 0000000..6b751b9
--- /dev/null
+++ b/docs/html/distribute/engage/app-updates.jd
@@ -0,0 +1,50 @@
+page.title=Update Your Apps Regularly
+page.metaDescription=Keeping your content fresh gives users a reason to come back.
+page.tags="updates"
+page.image=/images/gp-your-user-0.jpg
+
+@jd:body
+
+<p>
+ Keeping your content fresh gives users a reason to come back. Use any
+ <a href="{@docRoot}distribute/users/know-your-user.html#add-analytics">in-app
+ or game measurement tool</a> to keep an eye on what users respond to. Use
+ <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">alpha-beta
+ testing</a> and <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html#staged-rollouts">staged
+ rollouts</a> to quickly test new features, in-app content, and game
+ characters.
+</p>
+
+<p>
+ Updating regularly also gives you a chance to notify users about new content
+ should users lapse. Notification, email, and social media are several
+ channels to remind users to come back.
+</p>
+
+<p>
+ Check out the video below see how Kiwi uses frequent updates to engage and
+ retain users.
+</p>
+
+<p style="margin-bottom:2em">
+</p>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/kiwi" data-sortorder="-timestamp" data-cardsizes=
+"18x6," data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="related-resources">
+ Related Resources
+ </h1>
+
+ <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/appupdates" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/community.jd b/docs/html/distribute/engage/community.jd
new file mode 100644
index 0000000..035058a
--- /dev/null
+++ b/docs/html/distribute/engage/community.jd
@@ -0,0 +1,43 @@
+page.title=Engage Your Community
+page.metaDescription=Building a community has many benefits, including improving your app and bringing users back to it.
+page.image=/images/gp-engage-9.jpg
+
+
+@jd:body
+
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-engage-9.jpg" style="width:300px;">
+</div>
+
+<p>
+ Building a community has many benefits, including improving your apps and
+ bringing users back to them. Using social media, groups, and forum tools will
+ help you build a rapport with your audience that will drive loyalty and
+ engagement.
+</p>
+
+<p>
+ There are many tactics to bring users back to your apps. In addition to app
+ updates that users want to check out, you can also use communities to
+ announce game tournaments, new content, promotions, and other great content.
+ Any reason to go back to your app is a great post to share with your
+ community.
+</p>
+
+<p>
+ Learn more about how to <a href="{@docRoot}distribute/users/build-community.html">build and manage a community</a>.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="related-resources">
+ Related Resources
+ </h1>
+
+ <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/community" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/deep-linking.jd b/docs/html/distribute/engage/deep-linking.jd
new file mode 100644
index 0000000..cd62f9d
--- /dev/null
+++ b/docs/html/distribute/engage/deep-linking.jd
@@ -0,0 +1,78 @@
+page.title=Deep Link to Bring Users Back
+page.metaDescription=Use deep links to bring your users into your apps from social posts or search.
+page.tags="app indexing, google+ signin"
+page.image=/images/gp-listing-4.jpg
+
+@jd:body
+
+<p>
+ Use deep links to bring your users into your apps from social posts or
+ search.
+</p>
+
+<div class="headerLine">
+<h1>Deep Linking from Google+ Posts</h1><hr>
+</div>
+
+<p>
+ <a href="https://developers.google.com/+/mobile/android/share/deep-link">Deep
+ linking</a> allows the Google+ apps on mobile devices to direct clicks on a
+ shared post that contains deep-link information to a resource within your
+ apps.
+</p>
+
+<p style="margin-bottom:2em;">
+ If the user doesn’t have your app installed, they’re prompted to install it
+ before accessing the resource.
+</p>
+
+<div style="padding:2em, auto;width:550px;">
+ <div style="float:right; width:260px; padding-left:1em;">
+ <img src="{@docRoot}images/gp-engage-5.jpg" class="border-img">
+ <p class="img-caption">
+ G+ Post with Deep Link to Buy
+ </p>
+ </div>
+
+ <div style="width:260px;float:left;">
+ <img src="{@docRoot}images/gp-engage-6.jpg" class="border-img">
+ <p class="img-caption">
+ Purchase page within app
+ </p>
+ </div>
+</div>
+
+
+<div class="headerLine clearfloat">
+<h1>Deep Linking from Google Search — App Indexing</h1><hr>
+</div>
+
+<p>
+ Another way to bring users back to your apps is to apply for app indexing.
+</p>
+
+<p>
+ When a user searches for content available within your app, Google can show
+ an "Open in App" button in in mobile search results. For instance, if a user
+ searches for a restaurant and you’ve got that establishment in your dining
+ app, a link can be shown to open the page within your app. Learn more about
+ <a href="https://developers.google.com/app-indexing/">linking to in-app
+ content</a>.
+</p>
+
+<div>
+ <img src="{@docRoot}images/gp-listing-4.jpg" style="padding-top:1em;">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="related-resources">
+ Related Resources
+ </h1>
+
+ <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/deeplinks" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/easy-signin.jd b/docs/html/distribute/engage/easy-signin.jd
new file mode 100644
index 0000000..92c3ffc
--- /dev/null
+++ b/docs/html/distribute/engage/easy-signin.jd
@@ -0,0 +1,103 @@
+page.title=Make Signing In Easy
+page.metaDescription=Increase conversion rates while helping users minimize typing by letting users sign in with Google+.
+page.tags="google+"
+page.image=/images/google/gps-googleplus.png
+
+
+@jd:body
+
+<div class="sidebox-wrapper" style="float:right;">
+ <div class="sidebox" style="width:360px;">
+ <p>
+ <strong>Tip:</strong> For game developers, Google+ signin is already
+ included as part of Google Play game services.
+ </p>
+ </div>
+</div>
+
+<p>
+ Increase conversion rates while helping users minimize typing by letting
+ users sign in with Google+. The <a href=
+ "{@docRoot}google/play-services/plus.html">Google+ platform for Android</a>
+ authenticates users with their Google credentials safely and securely. With
+ your <a href="https://developers.google.com/+/mobile/android/sign-in">users
+ signing in with Google</a>, you can create more engaging experiences and
+ drive the use of your apps .
+</p>
+
+<div style="width:450px;">
+ <img src="{@docRoot}images/google/gps-googleplus.png" style="padding-top:1em;">
+</div>
+
+<p>
+ Use the Google+ social graph to welcome users by name, display their
+ pictures, connect them with friends and more. Users authenticate once and
+ then are signed-in automatically when they come back, eliminating the need to
+ remember and type names and passwords.
+</p>
+
+<div class="headerLine">
+ <h1>
+ And Spreading the Word a Snap
+ </h1>
+
+ <hr>
+</div>
+
+
+<div class="figure" style="float:right;">
+ <img src="{@docRoot}images/gp-engage-share-plus.png" style=
+ "width:160px;padding-top:1em;">
+ <p class="img-caption">
+ Easy sharing through Google+
+ </p>
+</div>
+
+
+<p>
+ Using Google+ can help users spread the word about your apps to their
+ friends, attracting them to your apps, right from within your apps:
+</p>
+
+<p>
+ Google+ is also a great way to build a community of loyal fans that will help
+ you with <a href=
+ "https://support.google.com/googleplay/android-developer/answer/3131213">beta
+ testing</a>.
+</p>
+
+<ul>
+ <li>Using a <a href=
+ "https://developers.google.com/+/mobile/android/recommend">native +1
+ button</a> to let users make a recommendation for your apps or their content.
+ </li>
+
+ <li>
+ <a href="https://developers.google.com/+/mobile/android/share/">Share rich
+ content</a> to the Google+ stream, including text, photos, URL attachments,
+ and location.
+ </li>
+
+ <li>Create <a href=
+ "https://developers.google.com/+/mobile/android/share/interactive-post">Interactive
+ posts</a> to share your website or apps, users can even invite friends to
+ "listen," "RSVP," "check-in," or one of over 100 actions.
+ </li>
+</ul>
+
+ <div class="headerLine clearfloat">
+ <h1 id="related-resources">
+ Related Resources
+ </h1>
+
+ <hr>
+ </div>
+
+ <div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/engage/gplus"
+ data-sortorder="-timestamp"
+ data-cardsizes="9x3"
+ data-maxresults="6">
+ </div>
+</div>
+
diff --git a/docs/html/distribute/engage/engage_toc.cs b/docs/html/distribute/engage/engage_toc.cs
new file mode 100644
index 0000000..0314f8c
--- /dev/null
+++ b/docs/html/distribute/engage/engage_toc.cs
@@ -0,0 +1,66 @@
+<ul id="nav">
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+ var:toroot?>distribute/engage/widgets.html">
+ <span class="en">Build Useful Widgets</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+ var:toroot?>distribute/engage/notifications.html">
+ <span class="en">Use Rich Notifications</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+ var:toroot?>distribute/engage/gcm.html">
+ <span class="en">Integrate GCM</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+ var:toroot?>distribute/engage/easy-signin.html">
+ <span class="en">Make Signing In Easy</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+ var:toroot?>distribute/engage/deep-linking.html">
+ <span class="en">Deep Link to Bring Users Back</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+ var:toroot?>distribute/engage/game-services.html">
+ <span class="en">Encourage Competition</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+ var:toroot?>distribute/engage/app-updates.html">
+ <span class="en">Update Regularly</span></a>
+ </div>
+ </li>
+
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+ var:toroot?>distribute/engage/community.html">
+ <span class="en">Engage Your Community</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+ var:toroot?>distribute/engage/video.html">
+ <span class="en">Delight with Videos</span></a>
+ </div>
+ </li>
+
+</ul>
+
+<script type="text/javascript">
+<!--
+ buildToggleLists();
+ changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html/distribute/engage/game-services.jd b/docs/html/distribute/engage/game-services.jd
new file mode 100644
index 0000000..5153435
--- /dev/null
+++ b/docs/html/distribute/engage/game-services.jd
@@ -0,0 +1,90 @@
+page.title=Encourage Competition
+page.metaDescription= Bring out the competitor in your users with cloud save, multiplayer game play, and more.
+page.tags="games"
+page.image=/images/google/gps-play_games_logo.png
+
+@jd:body
+
+<div class="figure" style="width:330px;">
+ <img src="{@docRoot}images/google/gps-play_games_logo.png">
+</div>
+
+<p>
+ Increase game installs, in-app revenue, and engagement with <a href=
+ "{@docRoot}google/play-services/games.html">Google Play
+ Game Services</a>. Bring out the competitor in your users with cloud save,
+ multiplayer game play, and more.
+</p>
+
+<ul>
+ <li>
+ <p>
+ <a href=
+ "https://developers.google.com/games/services/android/achievements">Achievements</a>
+ encourage players to try new features, resulting in more time spent in
+ your games.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <a href=
+ "https://developers.google.com/games/services/android/leaderboards">Leaderboards</a>
+ are a fun way to drive competition among your players.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <a href=
+ "https://developers.google.com/games/services/android/cloudsave">Cloud
+ Save</a> allows users to continue where they left off on another device
+ or platform.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Multiplayer features allow users to invite friends to install games and
+ play together in <a href=
+ "https://developers.google.com/games/services/common/concepts/realtimeMultiplayer">
+ real-time</a> or <a href=
+ "https://developers.google.com/games/services/common/concepts/turnbasedMultiplayer">
+ turn-by-turn</a>.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <a href=
+ "https://play.google.com/store/apps/details?id=com.google.android.play.games">
+ Google Play Games App</a> provides additional exposure to increase
+ downloads and gameplay. It helps users play with friends, see what others
+ are playing, and discover featured games.
+ </p>
+ </li>
+</ul>
+
+<p>
+ And there is no need to worrying about device or OS version support. Google
+ Play Game Services is backward compatible, allowing you to reach more
+ users with less effort. Get started on <a href=
+ "{@docRoot}google/play-services/games.html">Google Play
+ Game Services</a>. For more tips on keeping gamers engaged, see the <a href=
+ "{@docRoot}distribute/essentials/best-practices/games.html">
+ Game Developer Best Practices</a>.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="related-resources">
+ Related Resources
+ </h1>
+
+ <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/googleplaygames" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
+
diff --git a/docs/html/distribute/engage/gcm.jd b/docs/html/distribute/engage/gcm.jd
new file mode 100644
index 0000000..d793124e
--- /dev/null
+++ b/docs/html/distribute/engage/gcm.jd
@@ -0,0 +1,51 @@
+page.title=Integrate Google Cloud Messaging
+page.metaDescription=Keep your users in sync with your latest content by delivering lightweight messages over Google's infrastructure.
+page.tags="gcm"
+page.image=/images/gcm/gcm-logo.png
+
+@jd:body
+
+<div class="figure" style="width:330px">
+ <img src="{@docRoot}images/gcm/gcm-logo.png">
+</div>
+
+<p>
+ Keeping app content fresh is important to retaining users. And it’s easy with
+ the popular <a href="{@docRoot}google/gcm/index.html">Google Cloud
+ Messaging</a> for Android, by sending lightweight messages to your apps
+ installed on Android devices anywhere in the world.
+</p>
+
+<p>
+ Push messages from your backend servers to tell your apps that there's new
+ content for the user, or other data to sync.
+</p>
+
+<p>
+ You can use Google Cloud Messaging for two way messaging too. Another
+ possibility is to improve the experience for users with multiple devices, by
+ syncing content through the cloud so users have the same content on all their
+ devices.
+</p>
+
+<p>
+ Google Cloud Messaging lets your users stay in sync with your service without
+ draining the user’s battery, as there's no need for your apps poll a server
+ to discover new content. Best of all, Google Cloud Messaging is available for
+ free and there are no quotas.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="related-resources">
+ Related Resources
+ </h1>
+
+ <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/engage/gcm"
+ data-sortorder="-timestamp"
+ data-cardsizes="9x3"
+ data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/index.jd b/docs/html/distribute/engage/index.jd
new file mode 100644
index 0000000..f8cd1ee
--- /dev/null
+++ b/docs/html/distribute/engage/index.jd
@@ -0,0 +1,36 @@
+page.title=Engage & Retain Users
+page.metaDescription=Engaging and retaining active users is the key to success. Here are some resources to help you build an active user base.
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+<p>
+ Engaging and retaining active users is the key to success. This is specially
+ true for subscription and in-app purchase models. Here are several tools and
+ techniques to keep your users coming back.
+</p>
+
+<div class="dynamic-grid">
+
+ <div class="resource-widget resource-flow-layout landing col-16"
+ data-query="collection:distribute/engagelanding"
+ data-cardSizes="6x6"
+ data-maxResults="9">
+ </div>
+
+ <h3>Related Resources</h3>
+ <div class="resource-widget resource-flow-layout col-16"
+ data-query="type:youtube+tag:engagement"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x3"
+ data-maxResults="3">
+ </div>
+ <div class="resource-widget resource-flow-layout col-16"
+ data-query="type:blog+tag:engagement"
+ data-sortdOrder="-timestamp"
+ data-cardSizes="6x3"
+ data-maxResults="3">
+ </div>
+
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/notifications.jd b/docs/html/distribute/engage/notifications.jd
new file mode 100644
index 0000000..fecfb45
--- /dev/null
+++ b/docs/html/distribute/engage/notifications.jd
@@ -0,0 +1,61 @@
+page.title=Use Rich Notifications to Keep Users Informed
+page.metaDescription=Use Android's notifications to keep users in touch with your content and services — even when the app is not in use.
+page.tags=""
+page.image=/design/media/notifications_pattern_anatomy.png
+
+@jd:body
+
+<div class="figure">
+ <img src="{@docRoot}design/media/notifications_pattern_anatomy.png">
+</div>
+
+<p>
+ The <a href="/design/patterns/notifications.html">notification system</a>
+ allows your app to keep the user informed about events, such as new messages,
+ upcoming calendar appointments, shared photos, and much more. They are a
+ fundamental feature of Android that consumers check frequently to receive
+ important notifications and status updates. Notifications are like a news
+ channel that alerts the user to events as they happen and maintains a list of
+ updates since last review.
+</p>
+
+
+
+<p>
+ In addition to status updates from friends and family, notifications can also
+ be used to help gamers know when a time-based action is completed or another
+ player took their turn.</p>
+
+ <p>Some game developers use notifications to alert users
+ when a new limited time character can be won or a discount on an in-app
+ purchase is available. </p>
+
+<h3>But Use Them Sparingly</h3>
+
+<p>
+ Frequent notifications and spam notifications can turn users off, thereby
+ risking your ratings and user base. Also sure to check our <a href=
+ "https://support.google.com/googleplay/android-developer/answer/4430948">policies</a>
+ to ensure you’re treating your user respectfully.
+</p>
+
+
+ <div class="sidebox" style="width:326px;float:left;margin-left:0">
+ <p><strong>Tip:</strong>
+ Use notifications sparingly — be sure any information presented is
+ useful. Give users the option to turn notifications off.
+ </p>
+ </div>
+
+ <div class="headerLine clearfloat">
+ <h1 id="related-resources">
+ Related Resources
+ </h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/getusers/notifications"
+ data-sortorder="-timestamp"
+ data-cardsizes="9x3"
+ data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/video.jd b/docs/html/distribute/engage/video.jd
new file mode 100644
index 0000000..1a30f3a
--- /dev/null
+++ b/docs/html/distribute/engage/video.jd
@@ -0,0 +1,37 @@
+page.title=Delight Users with Videos
+page.metaDescription=Videos are one of the most effective ways to get users excited about your apps.
+page.tags="engagement"
+page.image=/images/gp-engage-smule.jpg
+
+@jd:body
+<p>
+ Videos are one of the most effective ways to get users excited about your
+ apps. Use videos to showcase your apps on your Google Play Product Details
+ pages. Be sure to build a <a href="http://www.youtube.com/yt/dev/">YouTube</a>
+ page to host new videos so users can see new features or content that will
+ get them excited to return to your apps.
+</p>
+
+<p>
+ Videos let you do more than tell users about your apps — you can
+ <em>show them</em>. One of the most viewed content types is how-to videos.
+ Help users progress to the next level with YouTube <strong>game play
+ videos</strong> in Google Play, on your YouTube channel, and on your website.
+</p>
+
+<div class="center-img">
+ <img src="{@docRoot}images/gp-engage-smule.jpg">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="related-resources">
+ Related Resources
+ </h1>
+
+ <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/video/more" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/widgets.jd b/docs/html/distribute/engage/widgets.jd
new file mode 100644
index 0000000..b17af08
--- /dev/null
+++ b/docs/html/distribute/engage/widgets.jd
@@ -0,0 +1,42 @@
+page.title=Build Useful Widgets
+page.metaDescription=Use widgets to remind users about important information in your apps and games, even when your apps are closed.
+page.tags=""
+page.image=/images/gp-engage-0.jpg
+
+@jd:body
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-engage-0.jpg" style="width:320px;">
+</div>
+<p>
+ <a href=
+ "/design/patterns/widgets.html">Widgets</a> are
+ an essential aspect of home screen customization. They are "at-a-glance"
+ views of an app's <strong>most important data and features</strong>,
+ instantly available from the user's home screen.
+</p>
+
+<p>
+ Use widgets to <strong>remind users</strong> about important information in
+ your apps and games, even when your apps are closed. For instance, if you
+ have a news app, showcase the latest headlines.
+</p>
+
+ <div class="sidebox" style="float:none;margin-left:0">
+ <p><strong>Tip:</strong>
+ Make your widgets useful — provide in-app information like news, game status,
+ or upcoming deadlines. Widgets should serve as more than a launcher icon.</p>
+ </div>
+
+<div class="headerLine clearfloat">
+ <h1 id="related-resources">
+ Related Resources
+ </h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/engage/widgets"
+ data-sortorder="-timestamp"
+ data-cardsizes="9x3"
+ data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/essentials/best-practices/apps.jd b/docs/html/distribute/essentials/best-practices/apps.jd
new file mode 100644
index 0000000..055a349
--- /dev/null
+++ b/docs/html/distribute/essentials/best-practices/apps.jd
@@ -0,0 +1,260 @@
+page.title=App Developer Best Practices
+page.image=/distribute/images/gp-app-practices.png
+page.metaDescription=Essential tips for launching successful apps in Google Play.
+@jd:body
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Best Practices</h2>
+<ol>
+<li><a href="#essentials">Get the Essentials Right</a></li>
+<li><a href="#users">Get Users</a></li>
+<li><a href="#engage">Engage and Retain</a></li>
+<li><a href="#beyond">Beyond the Basics</a></li>
+<li><a href="#related-resources">Related Resources</a></li>
+</ol>
+</div></div>
+
+<p>The following best practices have enabled developers worldwide to build great, successful apps for Google Play.</p>
+
+<div class="headerLine">
+<h1 id="essentials">Get the Essentials Right</h1><hr>
+</div>
+
+<h3>1. Make it Android</h3>
+
+<ul>
+ <li>
+ <p>
+ Build your apps to make best use of the unique Android features, such as
+ <a href="{@docRoot}distribute/engage/widgets.html">widgets</a>, <a href=
+ "{@docRoot}distribute/engage/notifications.html">rich notifications</a>,
+ <a href=
+ "http://android-developers.blogspot.com/2012/02/share-with-intents.html">sharing
+ through Intents</a>, and more.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Add the power of Google features your users already love, such as
+ <a href="https://developers.google.com/maps/documentation/android/">Google
+ Maps</a>, <a href="https://developers.google.com/drive/">Google
+ Drive</a>, and more, all with <a href=
+ "https://developers.google.com/+/mobile/android/sign-in">single sign
+ on</a>.
+ </p>
+ </li>
+</ul>
+
+<h3>
+ 2. Make it quality
+</h3>
+
+<ul>
+ <li>
+ <p>
+ Make sure your apps follow the <a href=
+ "{@docRoot}distribute/essentials/quality/core.html">Core App Quality</a>
+ guidelines.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Create apps that are available on all form factors and screen sizes, by
+ following the <a href=
+ "{@docRoot}distribute/essentials/quality/tablets.html">Tablet App
+ Quality</a> guidelines.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Test and <a href=
+ "{@docRoot}distribute/essentials/optimizing-your-app.html">optimize your
+ quality</a> at every step and make use of the Google Play <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta-testing</a>
+ and <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html#staged-rollouts">staged
+ rollouts</a> features to test with users before launch.
+ </p>
+ </li>
+</ul>
+
+<div class="headerLine">
+ <h1 id="users">
+ Get Users
+ </h1>
+
+ <hr>
+</div>
+
+<h3>
+ 1. Build buzz
+</h3>
+
+<ul>
+ <li>
+ <p>
+ Create a great <a href="{@docRoot}distribute/users/your-listing.html">app
+ listing page</a> to showcase your apps and grab users’ attention. Don’t
+ forget to include a <a href=
+ "{@docRoot}distribute/engage/video.html">YouTube video</a>.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <a href="{@docRoot}distribute/tools/launch-checklist.html">Launch</a> on
+ multiple platforms simultaneously to maximize your reach.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Promote your apps with the official <a href=
+ "{@docRoot}distribute/tools/promote/badges.html">Google Play badge</a>
+ and <a href="{@docRoot}distribute/tools/promote/linking.html">link to
+ your products</a> on Google Play.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Build a community with social media, <a href=
+ "http://groups.google.com/">forums</a>, and <a href=
+ "http://plus.google.com">communities</a> to get and keep users talking.
+ </p>
+ </li>
+</ul>
+
+<h3>
+ 2. Optimize for great ratings
+</h3>
+
+<ul>
+ <li>
+ <p>
+ Get to <a href="{@docRoot}distribute/users/know-your-user.html">know your
+ users</a>, listen to and <a href=
+ "{@docRoot}distribute/engage/app-updates.html">update your apps</a> from
+ their feedback.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Focus on your strength markets first, get these right before expanding.
+ </p>
+ </li>
+</ul>
+
+<div class="headerLine">
+ <h1 id="engage">
+ Engage and Retain
+ </h1>
+
+ <hr>
+</div>
+
+<h3>
+ 1. Keep users coming back
+</h3>
+
+<ul>
+ <li>
+ <p>
+ Use <a href="{@docRoot}google/play/billing/index.html">Google Play In-app
+ Billing</a> to offer subscriptions to extended features.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Hold competitions and offer promotions, then announce them through
+ <a href="{@docRoot}design/patterns/notifications.html">notifications</a>.
+ </p>
+ </li>
+</ul>
+
+<h3>
+ 2. Earn users’ love
+</h3>
+
+<ul>
+ <li>
+ <p>
+ <a href=
+ "http://android-developers.blogspot.com/2013/05/all-google-play-developers-can-now.html">
+ Respond to reviews</a> and get valuable feedback from the community
+ you've built.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <a href=
+ "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html">
+ Measure</a> your campaigns to see what is driving users to install your
+ apps.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <a href=
+ "{@docRoot}distribute/essentials/optimizing-your-app.html#measuring-analyzing-responding">
+ Analyze in-app use</a> to steer content updates and prolong the life of
+ your apps.
+ </p>
+ </li>
+</ul>
+
+<div class="headerLine">
+ <h1 id="beyond">
+ Beyond the Basics
+ </h1>
+
+ <hr>
+</div>
+
+<ul>
+ <li>
+ <p>
+ After you’ve launched in your market of strength, <a href=
+ "{@docRoot}distribute/users/expand-to-new-markets.html">expand into other
+ markets</a> strategically and <a href=
+ "{@docRoot}distribute/tools/localization-checklist.html">localize</a>
+ your apps as you go.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Keep users engaged, and stay ahead of the competition, by continually
+ <a href=
+ "{@docRoot}distribute/essentials/optimizing-your-app.html">optimizing
+ your apps</a> to offer new and better features, or retire those that
+ users aren’t using.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Build educational apps: learn <a href=
+ "{@docRoot}distribute/googleplay/edu/start.html">how to make apps for
+ Google Play for Education</a>.
+ </p>
+ </li>
+</ul>
+
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/toolsreference/bestpractices/apps"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3,9x3"
+ data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/essentials/best-practices/games.jd b/docs/html/distribute/essentials/best-practices/games.jd
new file mode 100644
index 0000000..ac1df44
--- /dev/null
+++ b/docs/html/distribute/essentials/best-practices/games.jd
@@ -0,0 +1,259 @@
+page.title=Game Developer Best Practices
+page.image=/distribute/images/gp-games-practices.png
+page.metaDescription=Essential tips for launching successful games in Google Play.
+
+@jd:body
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Best Practices</h2>
+<ol>
+<li><a href="#users">Get Users</a></li>
+<li><a href="#engage">Engage and Retain</a></li>
+<li><a href="#beyond">Beyond the Basics</a></li>
+<li><a href="#related-resources">Related Resources</a></li>
+</ol>
+</div></div>
+
+<p>
+ The following best practices have enabled developers worldwide to build
+ great, successful games for Google Play.
+</p>
+
+<div class="headerLine">
+ <h1 id="users">
+ Get Users
+ </h1>
+
+ <hr>
+</div>
+
+<h3>
+ 1. Optimize for great ratings
+</h3>
+
+<ul>
+ <li>
+ <p>
+ <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">Beta
+ test</a> to ensure your games are ready and poised for great ratings.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Optimize graphics, frame rates, and responsiveness with the <a href=
+ "http://android-developers.blogspot.com/2013/09/using-hardware-scaler-for-performance.html">
+ Hardware Scaler</a> and <a href=
+ "{@docRoot}training/graphics/opengl/index.html">OpenGL ES</a>.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Be sure your APK is small, then provide game content through over-the-air
+ downloads.
+ </p>
+ </li>
+</ul>
+
+<h3>
+ 2. Build buzz
+</h3>
+
+<ul>
+ <li>
+ <p>
+ Build a community with social media, <a href=
+ "{@docRoot}distribute/users/build-community.html">communities</a> to get
+ and keep users talking.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Promote your games with official <a href=
+ "{@docRoot}distribute/tools/promote/badges.html">Google Play badges</a>
+ and <a href="{@docRoot}distribute/tools/promote/linking.html">links to
+ your products</a> on Google Play.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ If you ship on multiple platforms, doing so at the same time can maximize
+ your marketing impact.
+ </p>
+ </li>
+</ul>
+
+<h3>
+ 3. Get Visibility
+</h3>
+
+<ul>
+ <li>
+ <p>
+ First impressions count: <a href=
+ "{@docRoot}distribute/users/your-listing.html">highlight</a> the game's
+ best features in screenshots, videos, and description.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Integrate Google Play Game Services, so your game is displayed in the
+ <a href=
+ "https://play.google.com/store/apps/details?id=com.google.android.play.games">
+ Google Play Games App</a>.
+ </p>
+ </li>
+</ul>
+
+<div class="headerLine">
+ <h1 id="engage">
+ Engage and Retain
+ </h1>
+
+ <hr>
+</div>
+
+<h3>
+ 1. Keep users coming back
+</h3>
+
+<ul>
+ <li>
+ <p>
+ <a href=
+ "https://developers.google.com/games/services/common/concepts/achievements">
+ Achievements</a>, <a href=
+ "https://developers.google.com/games/services/common/concepts/leaderboards">
+ leaderboards</a>, <a href=
+ "https://developers.google.com/games/services/common/concepts/realtimeMultiplayer">
+ multiplayer</a>, and <a href=
+ "https://developers.google.com/games/services/common/concepts/cloudsave">cloud
+ save</a> help engage users and bring them back.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Hold tournaments and offer promotions, then announce them through
+ <a href="{@docRoot}design/patterns/notifications.html">notifications</a>.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Sign in users early, then automatically. Before their first sign-in, save
+ progress locally.
+ </p>
+ </li>
+</ul>
+
+<h3>
+ 2. Give users a reason to invest their money
+</h3>
+
+<ul>
+ <li>
+ <p>
+ A majority of the top grossing games use in-app purchases. Use them to
+ unlock content and allow players to enhance their game play.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <a href="{@docRoot}google/play/billing/index.html">Google Play In-app
+ Billing</a> makes purchasing easy with several forms of payment.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Provide content updates regularly to give users limited edition items to
+ win or purchase.
+ </p>
+ </li>
+</ul>
+
+<h3>
+ 3. Earn players’ love
+</h3>
+
+<ul>
+ <li>
+ <p>
+ <a href=
+ "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html">
+ Measure</a> your campaigns to see what’s driving quality users to install
+ your games.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <a href=
+ "{@docRoot}distribute/essentials/optimizing-your-app.html#measuring-analyzing-responding">
+ Analyze in-game use</a> to steer content updates and prolong the life of your
+ games.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <a href=
+ "http://android-developers.blogspot.com/2013/05/all-google-play-developers-can-now.html">
+ Respond to reviews</a> and get valuable feedback from the community
+ you’ve built.
+ </p>
+ </li>
+</ul>
+
+<div class="headerLine">
+ <h1 id="beyond">
+ Beyond the Basics
+ </h1>
+
+ <hr>
+</div>
+
+<ul>
+ <li>
+ <p>
+ After you've launched in your market of strength, <a href=
+ "{@docRoot}distribute/users/expand-to-new-markets.html">expand into other
+ markets</a> strategically and <a href=
+ "{@docRoot}distribute/tools/localization-checklist.html">localize</a>
+ your apps as you go.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Provide content <a href=
+ "{@docRoot}distribute/engage/app-updates.html">updates on a regular
+ basis</a> to keep users engaged.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Building educational games? See the <a href=
+ "{@docRoot}distribute/essentials/gpfe-guidelines.html">Education
+ Guidelines</a>.
+ </p>
+ </li>
+</ul>
+
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/toolsreference/bestpractices/games"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3,9x3"
+ data-maxResults="6"></div>
diff --git a/docs/html/distribute/essentials/essentials_toc.cs b/docs/html/distribute/essentials/essentials_toc.cs
new file mode 100644
index 0000000..7084fdd
--- /dev/null
+++ b/docs/html/distribute/essentials/essentials_toc.cs
@@ -0,0 +1,44 @@
+<ul id="nav">
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/quality/core.html">
+ <span class="en">Core App Quality</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/quality/tablets.html">
+ <span class="en">Tablet App Quality</span>
+ </a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/gpfe-guidelines.html">
+ <span class="en">Education Guidelines</span>
+ </a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/optimizing-your-app.html">
+ <span class="en">Optimize Your App</span>
+ </a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/best-practices/apps.html">
+ <span class="en">App Best Practices</span>
+ </a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/best-practices/games.html">
+ <span class="en">Game Best Practices</span>
+ </a>
+ </div>
+ </li>
+
+
+<script type="text/javascript">
+<!--
+ buildToggleLists();
+ changeNavLang(getLangPref());
+//-->
+</script>
diff --git a/docs/html/distribute/essentials/gpfe-guidelines.jd b/docs/html/distribute/essentials/gpfe-guidelines.jd
new file mode 100644
index 0000000..8b47671
--- /dev/null
+++ b/docs/html/distribute/essentials/gpfe-guidelines.jd
@@ -0,0 +1,513 @@
+page.title=Education Guidelines
+page.metaDescription=These guidelines and requirements help you develop great apps for students, which offer compelling content and an intuitive user experience on Android tablets.
+page.image=/distribute/images/edu-guidelines.jpg
+Xnonavpage=true
+
+@jd:body
+
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Guidelines</h2>
+<ol>
+<li><a href="#basic-reqts">Basic Requirements</a></li>
+<li><a href="#monetizing-ads">Monetizing and Ads</a></li>
+<li><a href="#e-value">Educational Value</a></li>
+<li><a href="#quality">App Quality</a></li>
+<li><a href="#related-resources">Related Resources</a></li>
+</ol>
+
+<h2>
+ Testing
+</h2>
+
+<ol>
+ <li>
+ <a href="#test-environment">Setting Up a Test Environment</a>
+ </li>
+</ol>
+
+</div></div>
+
+<div style="margin:0 0 1em 0;">
+ <img src="{@docRoot}distribute/images/edu-guidelines.jpg" style=
+ "width:274px;">
+</div>
+
+<p>
+ These guidelines and requirements help you develop great apps for students,
+ which offer compelling content and an intuitive user experience on Android
+ tablets.
+</p>
+
+<p>
+ You’ll also need to ensure that your apps comply with the terms of the
+ <a href=
+ "https://play.google.com/about/developer-distribution-agreement-addendum.html">
+ Google Play for Education Addendum</a>, <a href=
+ "http://play.google.com/about/developer-content-policy.html">Google Play
+ Developer Program Policies</a>, and <a href=
+ "http://play.google.com/about/developer-distribution-agreement.html">Developer
+ Distribution Agreement</a>.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="basic-reqts">
+ Basic Requirements
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ To participate, your apps must be designed for the K-12 market. The basic
+ requirements that your apps must meet are:
+</p>
+
+<ul>
+ <li>
+ <p>
+ Apps and the ads they contain must not collect personally identifiable
+ information, other than user credentials or data required to operate and
+ improve the app.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Apps must not use student data for purposes unrelated to its educational
+ function.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Apps must have a content rating of "Everyone" or "Low Maturity" (apps
+ with a "Medium Maturity" rating are allowed, if they have that rating
+ solely because they allow communication between students).
+ </p>
+ </li>
+
+ <li>
+ <p>
+ App content, including ads displayed by the app, must be consistent with
+ the app's maturity rating. The app must not display any "offensive"
+ content, as described in the <a href=
+ "http://play.google.com/about/developer-content-policy.html">Google Play
+ Developer Program Policies</a> and <a href=
+ "https://support.google.com/googleplay/android-developer/answer/188189">content-rating
+ guidelines</a>.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Apps must comply with the Children’s Online Privacy Protection Act and
+ all other applicable laws and regulations.
+ </p>
+ </li>
+</ul>
+
+<div class="headerLine">
+ <h1 id="monetizing-ads">
+ Monetizing and Ads
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-edu-monetize.png">
+</div>
+
+<p>
+ In-app purchase is currently not supported with Google Play for Education, so
+ a student device will block any transactions. To avoid confusion, be sure to
+ remove any in-app purchase buttons and related UI elements from your apps.
+ We’re investigating additional purchase mechanisms to enable more flexible
+ pricing models for developers and schools.
+</p>
+
+<p>
+ If your apps are priced In Google Play for Education, you must allow Google
+ Play to offer teachers limited free trials before purchase (you provide this
+ through business terms only, no development work is needed.)
+</p>
+
+<p>
+ You can only choose not to remove in-app purchasing from your apps where all
+ content and services are sold through Google Play for Education using In-app
+ Billing. If you choose not to remove In-app Billing features, ensure that:
+</p>
+
+<ul>
+ <li>
+ <p>
+ Users can access your apps’ core functionality for a classroom setting
+ without an in-app purchase.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ In-app purchases are clearly identifiable in your UI.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ You declare the use of in-app purchases at <a href=
+ "{@docRoot}distribute/googleplay/edu/start.html#publish">opt-in</a>.
+ </p>
+ </li>
+</ul>
+
+<p>
+ For each app that you publish, you can set a single price that applies to
+ both Google Play and Google Play for Education. You can’t set a different
+ price for a given app (based on a single package name) in Google Play for
+ Education.
+</p>
+
+<p>
+ If your apps display ads, you should disable the display of ads if possible,
+ or ensure that:
+</p>
+
+<ul>
+ <li>Ads are not distracting for students or teachers (this includes
+ Flash-based ads, video ads, and ads that flash or move)
+ </li>
+
+ <li>Interstitial ads are not served in the app
+ </li>
+
+ <li>Ad walls do not appear in the app UI
+ </li>
+
+ <li>Ads do not occupy a significant portion of the screen
+ </li>
+
+ <li>Ads content does not exceed the maturity rating of the app.
+ </li>
+
+ <li>
+ <p>
+ You declare the use of ads at <a href=
+ "{@docRoot}distribute/googleplay/edu/start.html#publish">opt-in</a>.
+ </p>
+ </li>
+</ul>
+
+<div class="headerLine">
+ <h1 id="e-value">
+ Educational Value
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-e-value.png" class="border-img">
+</div>
+
+<p>
+ Apps submitted to Google Play for Education will be evaluated by a
+ third-party educator network, which will review them based on alignment with
+ <a href="http://www.corestandards.org/">Common Core Standards</a> and other
+ educational considerations. This will help make your content more
+ discoverable for teachers and administrators as they browse by grade level,
+ subject, core curriculum, and other parameters.
+</p>
+
+<p>
+ Apps with highest educational value will have these characteristics:
+</p>
+
+<ul>
+ <li>
+ <p>
+ Designed for use in K-12 classrooms.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Aligned with a common core standard or support common-core learning.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Simple, easy to use, and intuitive for the grade levels the apps are
+ targeting. Apps are relatively easy to navigate without teacher guidance.
+ Not distracting or overwhelming to students.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Enjoyable and interactive. Apps are engaging to students and lets them
+ control their experience.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Versatile. Apps have features that make them useful for more than one
+ classroom function or lesson throughout the school year.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Supports the "4Cs":
+ </p>
+
+ <ul>
+ <li>
+ <p>
+ <em>Creativity</em> — Allows students to create in order to
+ express understanding of the learning objectives, and try new
+ approaches, innovation, and invention to get things done.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <em>Critical thinking</em> — Allows students to look at
+ problems in a new way, linking learning across subjects and
+ disciplines.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <em>Collaboration</em> — Allows students and (if appropriate)
+ educators to work together to reach a goal.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <em>Communication</em> — Allows students to comprehend,
+ critique and share thoughts, questions, ideas, and solutions.
+ </p>
+ </li>
+ </ul>
+ </li>
+</ul>
+
+<p>
+ As you design and develop your apps, make sure they offer high educational
+ value by addressing as many of these characteristics as possible.
+</p>
+
+<div class="headerLine">
+ <h1 id="quality">
+ App Quality
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-edu-quality.png">
+</div>
+
+<p>
+ Your apps should be designed to perform well and look great on Android
+ tablets, and they should offer the best user experience possible.
+</p>
+
+<p>
+ High quality apps are engaging, intuitive, and offer compelling content.
+ Google Play for Education will highlight high-quality apps for easy discovery
+ in the store. Here are some recommendations for making your app easy for
+ students and teachers to enjoy:
+</p>
+
+<ul>
+ <li>
+ <p>
+ Meet the Core Quality Guidelines:
+ </p>
+
+ <ul>
+ <li>
+ <p>
+ Follow <a href="{@docRoot}design/index.html">Android Design
+ Guidelines</a>. Pay special attention to the sections on <a href=
+ "{@docRoot}design/patterns/actionbar.html">Action Bar</a>, <a href=
+ "{@docRoot}design/patterns/navigation.html">Navigation</a>, and
+ <a href="{@docRoot}design/patterns/pure-android.html">Pure
+ Android</a>.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Test your apps against the <a href=
+ "{@docRoot}distribute/essentials/quality/core.html">Core Quality
+ Guidelines</a>.
+ </p>
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ <p>
+ Meet the Tablet App Quality guidelines:
+ </p>
+
+ <ul>
+ <li>
+ <p>
+ Follow our best practices for tablet app development.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Review the <a href=
+ "{@docRoot}distribute/essentials/quality/tablets.html">Tablet App
+ Quality</a> guidelines and <a href=
+ "http://android-developers.blogspot.com/2012/11/designing-for-tablets-were-here-to-help.html">
+ blog post on designing for tablets.</a>
+ </p>
+
+ <ul>
+ <li>Check your Optimization Tips in the <a href=
+ "https://play.google.com/apps/publish/">Developer Console</a> (if
+ you've already uploaded your apps.)
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ <p>
+ Strive for simplicity and highest usability for students:
+ </p>
+
+ <ul>
+ <li>
+ <p>
+ Design your app so that teachers and students can use all the
+ capabilities of your app without having to sign-in to multiple
+ accounts and remember multiple passwords.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Every student or teacher using a Google Play for Education tablet
+ will already be signed in with a Google account on the device.
+ You can take advantage of that to provide a simple, seamless
+ sign-in experience in your app. A recommended approach is to use
+ <a href="{@docRoot}google/play-services/auth.html">Google OAuth 2
+ authorization</a> through Google Play Services.
+ </p>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+
+<div class="headerLine">
+ <h1 id="test-environment">
+ Test Environment
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ To test your app and assess it against the guidelines in this document, it's
+ recommended that you <a href=
+ "{@docRoot}distribute/essentials/quality/tablets.html#test-environment">set
+ up a test environment</a> that replicates the actual environment in which
+ students and teachers will run your app.
+</p>
+
+<h3>
+ Test conditions
+</h3>
+
+<p>
+ Make sure to test your apps under conditions that simulate those of schools.
+ For example, Google Play for Education lets administrators <a href=
+ "https://support.google.com/a/answer/182442?hl=en">control or disable certain
+ capabilities</a> for students, so it's good to test your app with those
+ capabilities disabled. Below are some conditions to test your apps for, to
+ ensure best results in the Google Play for Education environment:
+</p>
+
+<ul>
+ <li>
+ <p>
+ <em>Android version</em> — Test the apps on devices running Android
+ 4.2. Google Play for Education devices will be running Android 4.2 or
+ higher (API level 17+).
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <em>Proxy server</em> — Test the apps in a network environment that
+ uses proxies. Many schools use proxies.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <em>No location services</em> — Test the apps to make sure they
+ work properly with location services disabled. Many schools will disable
+ location services for student devices.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <em>No In-app Billing</em> — Test the apps to make sure they work
+ properly without access to In-app Billing. In-app purchases are blocked
+ on Google Play for Education devices.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <em>No Bluetooth</em> — Test the apps to make sure they work
+ properly when Bluetooth is disabled. Many schools will disable Bluetooth
+ on student devices.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <em>No access to network</em> — Test the app to make sure it works
+ properly when the device cannot connect to the internet.
+ </p>
+ </li>
+</ul>
+
+<div class="headerLine">
+<h1>Related Resources</h1><hr>
+</div>
+
+<div class="dynamic-grid">
+<h3>FOR DEVELOPERS</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/essentials/eduessentials/developers"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x3,6x3,6x3"
+ data-maxResults="6"></div>
+
+<h3>FOR TEACHERS AND EDUCATORS</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/essentials/eduessentials/educators"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x3,6x3,6x3"
+ data-maxResults="3"></div>
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/essentials/index.jd b/docs/html/distribute/essentials/index.jd
new file mode 100644
index 0000000..ca5442a
--- /dev/null
+++ b/docs/html/distribute/essentials/index.jd
@@ -0,0 +1,34 @@
+page.title=Essentials for a Successful App
+meta.tags="landing, quality"
+page.tags="guidelines", "tablet", "quality"
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+<p>
+ A focus on quality should be part of your entire app delivery process: from
+ initial concept through app and UI design, coding and testing and onto a
+ process of monitoring feedback and making improvement after launch.
+</p>
+
+<div class="dynamic-grid">
+<div class="resource-widget resource-flow-layout landing col-16"
+ data-query="collection:distribute/essentials"
+ data-cardSizes="6x6"
+ data-maxResults="6">
+</div>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-16"
+ data-query="type:blog+tag:quality"
+ data-cardSizes="6x3"
+ data-maxResults="3">
+</div>
+<div class="resource-widget resource-flow-layout col-16"
+ data-query="type:youtube+tag:appquality"
+ data-cardSizes="6x3"
+ data-maxResults="3">
+</div>
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/essentials/optimizing-your-app.jd b/docs/html/distribute/essentials/optimizing-your-app.jd
new file mode 100644
index 0000000..3fe91b28
--- /dev/null
+++ b/docs/html/distribute/essentials/optimizing-your-app.jd
@@ -0,0 +1,517 @@
+page.title=Optimize Your App
+page.metaDescription=A look at how to get the most visibility and the highest ratings possible for your app or game. Optimizing the quality of your apps is a key strategy.
+page.image=/distribute/images/gp-optimize-card.jpg
+
+@jd:body
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>Strategies</h2>
+ <ol>
+ <li><a href="#listen-to-your-users">Listen to Your Users</a></li>
+ <li><a href="#measuring-analyzing-responding">Measuring, Analyzing, and Responding to User Behavior</a></li>
+ <li><a href="#improve-stability">Improve Stability and Eliminate Bugs</a></li>
+ <li><a href="#improve-ui">Improve UI Responsiveness</a></li>
+ <li><a href="#improve-usability">Improve Usability</a></li>
+ <li><a href="#professional-appearance">Professional Appearance and Aesthetics</a></li>
+ <li><a href="#deliver-features">Deliver the Right Set of Features</a></li>
+ <li><a href="#integrate">Integrate with the System and Third-Party Apps</a></li>
+ <li><a href="#related-resources">Related Resources</a></li>
+ </ol>
+ </div>
+</div>
+
+<div class="top-right-float">
+ <img src="{@docRoot}images/gp-optimize.png" class="quality-top-image" style=
+ "width:239px;padding-left:1.5em;">
+</div>
+
+<p>
+ With thousands of new apps being published in Google Play every week, it's
+ important to look for ways to get the most visibility and the highest ratings
+ possible. Optimizing the quality of your apps is a key strategy.
+</p>
+
+<p>
+ A higher quality app can translate to higher user ratings, generally better
+ rankings, more downloads, and higher retention (longer install periods).
+ High-quality apps are much more likely to get positive publicity, such as
+ being featured in Google Play or generating social media buzz.
+</p>
+
+<p>
+ The quality of your apps is something you should consider addressing both
+ before and after launch. Gaining users after the launch of a poor quality app
+ can be hard and recovering costly. On the other hand, maintaining the ranking
+ of high-quality apps is made easier if there are continual improvements, a
+ practice that also fuels the impression-install-ranking cycle.
+</p>
+
+<p>
+ On this page you can find advice on a number of ways in which you can drive
+ improvements to your apps’ quality.
+</p>
+
+<div class="headerLine">
+ <h1 id="listen-to-your-users">
+ Listen to Your Users
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-optimizing-chat-bubbles.png">
+</div>
+
+<p>
+ Listening and hearing your users can be one of your best tools for success.
+ Start listening to your users before launching your apps and continue to
+ listen after launch.
+</p>
+
+<h3>
+ <strong>Listening before you launch</strong>
+</h3>
+
+<p>
+ You can listen to your users during the development of your apps. This
+ process can start with focus groups to review app features, continue into
+ user experience workshops, and onto alpha and beta releases. Listening at
+ these stages has two main benefits: <strong>you’ll build apps with features
+ users want</strong> and <strong>any issues they identify will be cheaper and
+ quicker to fix</strong> than they would be once the app is launched fully.
+</p>
+
+<p>
+ If the practicalities of focus groups and user workshops seem excessive in
+ relation to the development of a particular app, drawing on the feedback of
+ colleagues, friends, and family can be much more useful than getting no
+ feedback at all.
+</p>
+
+<p>
+ It's crucial to conduct user testing before releasing your apps to Google
+ Play. If you can only engage with colleagues, friends, and family you’re
+ already making a good start. For more extensive testing consider a public
+ alpha/beta test or creating your own trusted tester program. You can manage
+ app distribution yourself through email or your own website, or you can use
+ <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta-testing</a>
+ and <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html#staged-rollouts">staged
+ rollouts</a> in conjunction with <a href=
+ "http://www.google.com/+/business/">Google+</a> or <a href=
+ "https://groups.google.com/forum/#!overview">Google Groups</a> to distribute
+ software and gather feedback to a subset of users. <strong>Users on alpha or
+ beta versions cannot leave reviews or ratings</strong>, so there is
+ <strong>no risk to your rating</strong> on Google Play.
+</p>
+
+<p>
+ Unless you have to, don’t restrict the users you involve in these stages in
+ the information they can share through their social networks and blogs -
+ users engaged in these early stages (and listened too) are likely to be great
+ ambassadors for your apps and will help create great social media buzz.
+</p>
+
+<h3>
+ Listening after launch
+</h3>
+
+<p>
+ Once you have launched, the most obvious way to listen to users is by reading
+ and addressing comments on Google Play. Although the comments aren't always
+ productive or constructive, some will provide valuable insight on aspects of
+ your apps. It's important to remember that users have the opportunity to
+ change their ratings and comments as much as they like.
+</p>
+
+<p>
+ There are more interactive ways you can reach users, help them address their
+ concerns, and gather more detailed feedback: by setting up support and
+ discussion forums. There are some great support tools out there that can put
+ you in touch with your users directly, from forums such as <a href=
+ "http://groups.google.com/">Google Groups</a> to comprehensive customer
+ support products and tools like UserVoice. Once you get set up with such a
+ tool, make sure to fill in the support link in your Google Play product
+ details page — users do click through to these.
+</p>
+
+<p>
+ Also don’t forget to use the <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta-testing</a>
+ and <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html#staged-rollouts">staged
+ rollout</a> features of Google Play with app updates.
+</p>
+
+<div class="headerLine" id="measuring-analyzing-responding">
+ <h1>
+ Measuring, Analyzing, and Responding to User Behavior
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-optimize-analytics.png">
+</div>
+
+<p>
+ One of the best ways to spot issues to resolve is by measuring user behavior.
+ Optimizing your app becomes much easier when you analyze performance before
+ and after you launch. Drop off points, low ratings, and high percent of
+ uninstalls can be indicative that there’s a problem. Measuring and responding
+ to user-related metrics such as download sources, retention rates, and in-app
+ behavior regularly is critical to keeping and bringing back your hard earned
+ user base.
+</p>
+
+<p>
+ You can get data from tools in Google Play or third-parties to analyze user
+ behavior. You can identify details such as:
+</p>
+
+<ul>
+ <li>
+ <p>
+ Where installs are coming from.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ The types of users you are acquiring.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ What is causing user churn and how to reduce it.
+ </p>
+ </li>
+</ul>
+
+<h3>
+ Statistics for analyzing installs and ratings
+</h3>
+
+<p>
+ Once you’ve published your app, Google Play makes it easy to see how it’s
+ doing. The <a href="https://play.google.com/apps/publish/">Developer
+ Console</a> gives you access to a variety of anonymized statistics and custom
+ charts that show you the app's installation performance and ratings.
+</p>
+
+<p>
+ You can view data and charts for active, daily, and total installs per unique
+ devices or users, as well as upgrades and uninstalls. You can also view the
+ app's daily average user rating and its cumulative user rating. To help you
+ analyze the data, you can view install and ratings statistics across a
+ variety of different dimensions such as Android version, device, country, app
+ version, and carrier.
+</p>
+
+<div>
+ <img class="border-img" src="{@docRoot}images/gp-dc-stats-mini.png">
+</div>
+
+<p>
+ You can see your app statistics on timeline charts, for all metrics and
+ dimensions. At a glance, the charts highlight your app’s installation and
+ ratings peaks and longer-term trends, which you can correlate to promotions,
+ app improvements, or other factors. You can even focus in on data inside a
+ dimension by highlighting specific data points (such as individual platform
+ versions or languages) on the timeline.
+</p>
+
+<p>
+ You can download all of your installation data as a CSV file for viewing in
+ the business program of your choice.
+</p>
+
+<h3>
+ Tracking and analyzing Marketing campaigns
+</h3>
+
+<p>
+ While you should consider monitoring user behavior data as a part of your
+ normal activities, it’s particularly important when you’re running any form
+ of marketing campaign, to make sure you’re getting the right users at the
+ lowest cost possible.
+</p>
+
+<p>
+ One way to track your marketing campaigns is to link <a href=
+ "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html">
+ Google Analytics with your Google Play account</a> to analyze activity from
+ source to install.
+</p>
+
+<div style="margin-top:1em;">
+ <img src="{@docRoot}images/gp-optimizing-image-4.jpg" class="border-img">
+</div>
+
+<p>
+ You can also use any of the variety of tools on the market to help track your
+marketing success and improvement ROI if you wish. There are also third parties
+who can help automate, measure, and optimize your mobile marketing.
+</p>
+
+<div class="headerLine">
+ <h1 id="improve-stability">
+ Improve Stability and Eliminate Bugs
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ There are many tools and techniques for testing and profiling your app on
+ different devices and user scenarios.
+</p>
+
+<p>
+ One noteworthy and yet relatively underused tool for catching stability
+ issues such as crashes is the <a href=
+ "{@docRoot}tools/help/monkey.html">UI/Application Exerciser Monkey</a>
+ (Monkey). Monkey will send random UI events to your app's activities,
+ allowing you to trigger user flows that can uncover stability problems.
+</p>
+
+<p>
+ Also, with the Google error-reporting features built into most Android
+ devices, users have a way to report application crashes to you. The error
+ reports show up in aggregate in the Google Play Developer Console. Make sure
+ to read these reports often and act on them appropriately.
+</p>
+
+<p>
+ Last, keep an external bug and feature request tracker and let users know how
+ to find it. This will enable them to engage with the app at a closer level,
+ by following features and bugs that affect them. User frustration with app
+ problems can be effectively managed with diligent issue tracking and
+ communication. Several community support tools offer issue tracking features,
+ and if your project is open source, most popular repository hosting sites
+ offer this as well.
+</p>
+
+<div class="headerLine">
+ <h1 id="improve-ui">
+ Improve UI Responsiveness
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-optimize-speed.png">
+</div>
+
+<p>
+ One sure-fire way to lose your users is to give them a slow, unresponsive UI.
+ Research has shown that <a href=
+ "http://googleresearch.blogspot.com/2009/06/speed-matters.html">speed
+ matters</a>, for any interface, on mobile, web, or desktop. In fact, the
+ importance of speed is amplified on mobile devices since users often need
+ their information on the go and in a hurry.
+</p>
+
+<p>
+ You can improve your apps' UI responsiveness by moving long-running
+ operations off the main thread to worker threads. Android offers built-in
+ debugging facilities such as StrictMode for analyzing your app's performance
+ and activities on the main thread. See more recommendations in <a href=
+ "http://www.youtube.com/watch?v=c4znvD-7VDA">Writing Zippy Android Apps</a>,
+ a developer session from Google I/O 2010.
+</p>
+
+<p>
+ A great way to improve UI performance is to minimize the complexity of your
+ layouts. If you open up <a href=
+ "{@docRoot}tools/help/hierarchy-viewer.html">hierarchyviewer</a> and see that
+ your layouts are more than 5 levels deep, it may be time to simplify your
+ layout. Consider refactoring those deeply nested <a href=
+ "{@docRoot}reference/android/widget/LinearLayout.html">LinearLayouts</a> into
+ <a href="{@docRoot}guide/topics/ui/layout/relative.html">RelativeLayout</a>.
+ The impact of View objects is cumulative — each one costs about 1 to 2 KB of
+ memory, so large view hierarchies can be a recipe for disaster, causing
+ frequent VM garbage collection passes which block the main (UI) thread. You
+ can learn more from the Google I/O session <a href=
+ "http://www.youtube.com/watch?v=wDBM6wVEO70">World of ListView</a>.
+</p>
+
+<p>
+ Lastly, as pointed out in the blog post <a href=
+ "http://android-developers.blogspot.com/2010/10/traceview-war-story.html">Traceview
+ War Story</a>, tools like <a href=
+ "{@docRoot}tools/help/traceview.html">traceview and ddms</a> can be your best
+ friends in improving your app by profiling method calls and monitoring VM
+ memory allocations, respectively.
+</p>
+
+<div class="headerLine">
+ <h1 id="improve-usability">
+ Improve Usability
+ </h1>
+
+ <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+ <div class="sidebox">
+ <p>
+ <strong>Tip:</strong> As you’re designing or evaluating your app's UI,
+ make sure to read and become familiar with the <a href=
+ "{@docRoot}design/index.html">Android Design</a> guidelines. Included are
+ many examples of UI patterns, styles, and building blocks, as well as
+ tools for the design process.
+ </p>
+ </div>
+</div>
+
+<p>
+ In usability and in app design too, you should listen carefully to your
+ users. Ask a handful of real Android device users (friends, family, etc.) to
+ try out your app and observe them as they interact with it. Look for cases
+ where they get confused, are unsure of how to proceed, or are surprised by
+ certain behaviors. Minimize these cases by rethinking some of the
+ interactions in your app. See the <a href=
+ "{@docRoot}design/patterns/index.html">Patterns section</a> for tips to
+ improve your design.
+</p>
+
+<p>
+ In the same vein, two problems that can plague some Android user interfaces
+ are small tap targets and excessively small font sizes. These are generally
+ easy to fix and can make a big impact on usability and user satisfaction. As
+ a general rule, optimize for ease of use and legibility, while minimizing, or
+ at least carefully balancing, information density.
+</p>
+
+<p>
+ Another way to incrementally improve usability, based on real-world data, is
+ to implement <a href=
+ "http://code.google.com/mobile/analytics/docs/">Analytics</a> throughout your
+ app to log the use of particular sections. Consider demoting infrequently
+ used sections to the overflow menu in the <a href=
+ "{@docRoot}design/patterns/actionbar.html">Action bar</a>, or removing them
+ altogether. For often-used sections and UI elements, make sure they're
+ immediately obvious and easily accessible in your app's UI so that users can
+ get to them quickly.
+</p>
+
+<div class="headerLine">
+ <h1 id="professional-appearance">
+ Professional Appearance and Aesthetics
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ There's no substitute for a real user interface designer — ideally one who's
+ well-versed in mobile and Android, and handy with both interaction and visual
+ design. One popular venue to post openings for designers is <a href=
+ "http://jobs.smashingmagazine.com/">jobs.smashingmagazine.com</a>, and
+ leveraging social networks can also surface great talent.
+</p>
+
+<p>
+ If you don't have the luxury of working with a UI designer, there are some
+ ways in which you can improve your app's appearance yourself. You can use
+ Adobe Photoshop, Adobe Fireworks, GIMP, Inkscape or other image editing
+ tools. Mastering the art of the pixel in these apps takes time, but honing
+ this skill can help build polish across your interface designs. Also, master
+ the resources framework by studying the framework UI assets and layouts and
+ reading through the <a href=
+ "{@docRoot}guide/topics/resources/index.html">resources documentation</a>.
+ Techniques such as 9-patches and resource directory qualifiers are somewhat
+ unique to Android, and are crucial in building flexible yet aesthetic UIs.
+</p>
+
+<p>
+ Before you get too far in designing your app and writing the code, make sure
+ to visit the <a href="{@docRoot}design/index.html">Android Design section</a>
+ and learn about the vision, the building blocks, and the tools of designing
+ beautiful and inspiring user interfaces.
+</p>
+
+<div class="headerLine">
+ <h1 id="deliver-features">
+ Deliver the Right Set of Features
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Having the <em>right</em> set of features in your app is important. It's
+ often easy to fall into the trap of feature-creep, building as much
+ functionality into your app as possible. Providing instant gratification by
+ immediately showing the most important or relevant information is crucial on
+ mobile devices. Providing too much information can be as frustrating (or even
+ more so) than not providing enough of it.
+</p>
+
+<p>
+ Again, listen to your users by collecting and responding to feature requests.
+ Be careful, though, to take feature requests with a grain of salt. Requests
+ can be very useful in aggregate, to get a sense of what kinds of
+ functionality you should be working on, but not every feature request needs
+ to be implemented.
+</p>
+
+<div class="headerLine">
+ <h1 id="integrate">
+ Integrate with the System and Third-Party apps
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ A great way to deliver a delightful user experience is to integrate tightly
+ with the operating system. Features like <a href=
+ "{@docRoot}guide/topics/appwidgets/index.html">Home screen widgets</a>,
+ <a href="{@docRoot}design/patterns/notifications.html">rich
+ notifications</a>, <a href="{@docRoot}guide/topics/search/index.html">global
+ search integration</a>, and <a href=
+ "{@docRoot}reference/android/widget/QuickContactBadge.html">Quick
+ Contacts</a> are fairly low-hanging fruit in this regard.
+</p>
+
+<p>
+ For some app categories, basic features like home screen widgets are
+ expected. Not including them is a sure-fire way to tarnish an otherwise
+ positive user experience. Some apps can achieve even tighter OS integration
+ with Android's contacts, accounts, and sync APIs.
+</p>
+
+<p>
+ Third-party integrations can provide even more user delight and give the user
+ a feeling of device cohesiveness. It's also a really nice way of adding
+ functionality to your app without writing any extra code (by leveraging other
+ apps' functionality). For example, if you're creating a camera app, you can
+ allow users to edit their photos in another app before saving them to their
+ collection, if they have that third-party application installed. More
+ information on this subject is available in the Android Training class
+ <a href="{@docRoot}training/basics/intents/index.html">Interacting with Other
+ Apps</a>.
+</p>
+
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/essentials/optimizing, tag:addia"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x3"
+ data-maxResults="3"></div>
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="tag:adia"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x3"
+ data-maxResults="3"></div>
+
diff --git a/docs/html/distribute/essentials/quality/core.jd b/docs/html/distribute/essentials/quality/core.jd
new file mode 100644
index 0000000..558b030
--- /dev/null
+++ b/docs/html/distribute/essentials/quality/core.jd
@@ -0,0 +1,1170 @@
+page.title=Core App Quality
+page.metaDescription=App quality directly influences the long-term success of your app—in terms of installs, user rating and reviews, engagement, and user retention.
+page.image=/distribute/images/core-quality-guidelines.jpg
+@jd:body
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Quality Criteria</h2>
+ <ol>
+ <li><a href="#ux">Design and Interaction</a></li>
+ <li><a href="#fn">Functionality</a></li>
+ <li><a href="#ps">Performance and Stability</a></li>
+ <li><a href="#listing">Google Play</a></li>
+
+ </ol>
+
+ <h2>Testing</h2>
+ <ol>
+ <li><a href="#test-environment">Setting Up a Test Environment</a></li>
+ <li><a href="#tests">Test Procedures</a></li>
+ </ol>
+
+ <h2>You Should Also Read</h2>
+ <ol>
+ <li><a href="{@docRoot}distribute/essentials/quality/tablets.html">Tablet App Quality</a></li>
+ <li><a href="{@docRoot}distribute/essentials/optimizing-your-app.html">Optimize Your App</a></li>
+ </ol>
+
+
+</div>
+</div>
+
+<div class="top-right-float">
+ <img src="{@docRoot}images/gp-core-quality.png" style="margin-left: 20px;">
+</div>
+
+<p>
+ Android users expect high-quality apps. App quality directly influences the
+ long-term success of your app—in terms of installs, user rating and reviews,
+ engagement, and user retention.
+</p>
+
+<p>
+ This document helps you assess basic aspects of quality in your app through a
+ compact set of core app quality criteria and associated tests. All Android
+ apps should meet these criteria.
+</p>
+
+<p>
+ Before publishing your apps, test them against these criteria to ensure that
+ they function well on many devices, meets Android standards for navigation
+ and design, and are prepared for promotional opportunities in the Google Play
+ store. Your testing will go well beyond what's described here—the purpose of
+ this document is to specify the essential quality characteristics all apps
+ should display, so that you can cover them in your test plans.
+</p>
+
+<p>
+ If you're creating apps for tablets and or Google Play for Education there
+ are additional quality criteria you should consider, which are defined in the
+ <a href="{@docRoot}distribute/essentials/quality/tablets.html">Tablet App
+ Quality</a> guidelines and <a href=
+ "{@docRoot}distribute/essentials/gpfe-guidelines.html">Education
+ Guidelines</a>.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="ux">
+ Visual Design and User Interaction
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ These criteria ensure that your app provides standard Android visual design
+ and interaction patterns where appropriate, for a consistent and intuitive
+ user experience.
+</p>
+
+<table>
+ <tr>
+ <th style="width:2px;">
+ Area
+ </th>
+ <th style="width:54px;">
+ ID
+ </th>
+
+
+ <th>
+ Description
+ </th>
+ <th style="width:54px;">
+ Tests
+ </th>
+ </tr>
+ <tr id="UX-B1">
+ <td>Standard design</td>
+ <td>
+ UX-B1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ App follows <a href="{@docRoot}design/index.html">Android Design</a>
+ guidelines and uses common <a href=
+ "{@docRoot}design/patterns/index.html">UI patterns and icons</a>:
+ </p>
+
+ <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+ <li>App does not redefine the expected function of a system icon (such
+ as the Back button).
+ </li>
+
+ <li>App does not replace a system icon with a completely different icon
+ if it triggers the standard UI behavior.
+ </li>
+
+ <li>If the app provides a customized version of a standard system icon,
+ the icon strongly resembles the system icon and triggers the standard
+ system behavior.
+ </li>
+
+ <li>App does not redefine or misuse Android UI patterns, such that
+ icons or behaviors could be misleading or confusing to users.
+ </li>
+ </ol>
+ </td>
+ <td>
+ <a href="#core">CR-all</a>
+ </td>
+ </tr>
+
+ <tr>
+ <td rowspan="3">
+ Navigation
+ </td>
+ <td id="UX-N1">
+ UX-N1
+ </td>
+ <td>
+ <p>
+ App supports standard system <a href=
+ "{@docRoot}design/patterns/navigation.html">Back button navigation</a>
+ and does not make use of any custom, on-screen "Back button" prompts.
+ </p>
+ </td>
+ <td>
+ <a href="#core">CR-3</a>
+ </td>
+ </tr>
+
+ <tr>
+ <td id="UX-N2">
+ UX-N2
+ </td>
+ <td>
+ <p>
+ All dialogs are dismissable using the Back button.
+ </p>
+ </td>
+ <td>
+ <a href="#core">CR-3</a>
+ </td>
+ </tr>
+
+ <tr id="UX-N3">
+ <td>
+ UX-N3
+ </td>
+ <td>
+ Pressing the Home button at any point navigates to the Home screen of the
+ device.
+ </td>
+ <td>
+ <a href="#core">CR-1</a>
+ </td>
+ </tr>
+
+ <tr id="UX-S1">
+ <td rowspan="2">
+ Notifications
+ </td>
+ <td>
+ UX-S1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ Notifications follow Android Design <a href=
+ "{@docRoot}design/patterns/notifications.html">guidelines</a>. In
+ particular:
+ </p>
+
+ <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+ <li>Multiple notifications are stacked into a single notification
+ object, where possible.
+ </li>
+
+ <li>Notifications are persistent only if related to ongoing events
+ (such as music playback or a phone call).
+ </li>
+
+ <li>Notifications do not contain advertising or content unrelated to
+ the core function of the app, unless the user has opted in.
+ </li>
+ </ol>
+ </td>
+ <td>
+ <a href="#core">CR-11</a>
+ </td>
+ </tr>
+
+ <tr id="UX-S2">
+ <td>
+ UX-S2
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ App uses notifications only to:
+ </p>
+
+ <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+ <li>Indicate a change in context relating to the user personally (such
+ as an incoming message), or
+ </li>
+
+ <li>Expose information/controls relating to an ongoing event (such as
+ music playback or a phone call).
+ </li>
+ </ol>
+ </td>
+ <td>
+ <a href="#core">CR-11</a>
+ </td>
+ </tr>
+</table>
+
+<h3>
+ Related Resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/essentials/corequalityguidelines/visualdesign"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,6x3,6x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="fn">
+ Functionality
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ These criteria ensure that your app provides expected functional behavior,
+ with the appropriate level of permissions.
+</p>
+
+<table>
+ <tr>
+ <th style="width:2px;">
+ Area
+ </th>
+ <th style="width:54px;">
+ ID
+ </th>
+ <th>
+ Description
+ </th>
+ <th style="width:54px;">
+ Tests
+ </th>
+ </tr>
+
+ <tr id="FN-P1">
+ <td rowspan="2">
+ Permissions
+ </td>
+ <td>
+ FN-P1
+ </td>
+ <td>
+ App requests only the <em>absolute minimum</em> permissions that it needs
+ to support core functionality.
+ </td>
+ <td rowspan="2">
+ <a href="#core">CR-11</a>
+ </td>
+ </tr>
+
+ <tr id="FN-P2">
+ <td>
+ FN-P2
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ App does not request permissions to access sensitive data (such as
+ Contacts or the System Log) or services that can cost the user money
+ (such as the Dialer or SMS), unless related to a core capability of the
+ app.
+ </p>
+ </td>
+ </tr>
+
+ <tr id="FN-L1">
+ <td>
+ Install location
+ </td>
+ <td>
+ FN-L1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ App functions normally when installed on SD card (if supported by app).
+ </p>
+
+ <p style="margin-bottom:.25em;">
+ Supporting installation to SD card is recommended for most large apps
+ (10MB+). See the <a href=
+ "{@docRoot}guide/topics/data/install-location.html">App Install
+ Location</a> developer guide for information about which types of apps
+ should support installation to SD card.
+ </p>
+ </td>
+ <td>
+ <a href="#SD-1">SD-1</a>
+ </td>
+ </tr>
+
+ <tr id="FN-A1">
+ <td rowspan="4">
+ Audio
+ </td>
+ <td>
+ FN-A1
+ </td>
+ <td>
+ Audio does not play when the screen is off, unless this is a core feature
+ (for example, the app is a music player).
+ </td>
+ <td>
+ <a href="#core">CR-7</a>
+ </td>
+ </tr>
+
+ <tr id="FN-A2">
+ <td>
+ FN-A2
+ </td>
+ <td>
+ Audio does not <a href=
+ "http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html">
+ play behind the lock screen</a>, unless this is a core feature.
+ </td>
+ <td>
+ <a href="#core">CR-8</a>
+ </td>
+ </tr>
+
+ <tr id="FN-A3">
+ <td>
+ FN-A3
+ </td>
+ <td>
+ Audio does not play on the home screen or over another app, unless this
+ is a core feature.
+ </td>
+ <td>
+ <a href="#core">CR-1,<br>
+ CR-2</a>
+ </td>
+ </tr>
+
+ <tr id="FN-A4">
+ <td>
+ FN-A4
+ </td>
+ <td>
+ Audio resumes when the app returns to the foreground, or indicates to the
+ user that playback is in a paused state.
+ </td>
+ <td>
+ <a href="#core">CR-1, CR-8</a>
+ </td>
+ </tr>
+
+ <tr id="FN-U1">
+ <td rowspan="3">
+ UI and Graphics
+ </td>
+ <td>
+ FN-U1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ App supports both landscape and portrait orientations (if possible).
+ </p>
+
+ <p style="margin-bottom:.25em;">
+ Orientations expose largely the same features and actions and preserve
+ functional parity. Minor changes in content or views are acceptable.
+ </p>
+ </td>
+ <td>
+ <a href="#core">CR-5</a>
+ </td>
+ </tr>
+
+ <tr id="FN-U2">
+ <td>
+ FN-U2
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ App uses the whole screen in both orientations and does not letterbox
+ to account for orientation changes.
+ </p>
+
+ <p style="margin-bottom:.25em;">
+ Minor letterboxing to compensate for small variations in screen
+ geometry is acceptable.
+ </p>
+ </td>
+ <td>
+ <a href="#core">CR-5</a>
+ </td>
+ </tr>
+
+ <tr id="FN-U3">
+ <td>
+ FN-U3
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ App correctly handles rapid transitions between display orientations
+ without rendering problems.
+ </p>
+ </td>
+ <td>
+ <a href="#core">CR-5</a>
+ </td>
+ </tr>
+
+ <tr id="FN-S1">
+ <td rowspan="2">
+ User/app state
+ </td>
+ <td>
+ FN-S1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ App should not leave any services running when the app is in the
+ background, unless related to a core capability of the app.
+ </p>
+
+ <p style="margin-bottom:.25em;">
+ For example, the app should not leave services running to maintain a
+ network connection for notifications, to maintain a Bluetooth
+ connection, or to keep the GPS powered-on.
+ </p>
+ </td>
+ <td>
+ <a href="#core">CR-6</a>
+ </td>
+ </tr>
+
+ <tr id="FN-S2">
+ <td>
+ FN-S2
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ App correctly preserves and restores user or app state.
+ </p>
+
+ <p style="margin-bottom:.25em;">
+ App preserves user or app state when leaving the foreground and
+ prevents accidental data loss due to back-navigation and other state
+ changes. When returning to the foreground, the app must restore the
+ preserved state and any significant stateful transaction that was
+ pending, such as changes to editable fields, game progress, menus,
+ videos, and other sections of the app or game.
+ </p>
+
+ <ol style="margin-bottom:.25em;list-style-type:lower-alpha">
+ <li>When the app is resumed from the Recents app switcher, the app
+ returns the user to the exact state in which it was last used.
+ </li>
+
+ <li>When the app is resumed after the device wakes from sleep (locked)
+ state, the app returns the user to the exact state in which it was last
+ used.
+ </li>
+
+ <li>When the app is relaunched from Home or All Apps, the app restores
+ the app state as closely as possible to the previous state.
+ </li>
+
+ <li>On Back keypresses, the app gives the user the option of saving any
+ app or user state that would otherwise be lost on back-navigation.
+ </li>
+ </ol>
+ </td>
+ <td>
+ <a href="#core">CR-1, CR-3, CR-5</a>
+ </td>
+ </tr>
+</table>
+
+<h3>
+ Related Resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/essentials/corequalityguidelines/functionality"
+data-sortorder="-timestamp" data-cardsizes="6x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="ps">
+ Performance and Stability
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ These criteria ensure that apps provide the performance, stability, and
+ responsiveness expected by users.
+</p>
+
+<table>
+ <tr>
+ <th style="width:2px;">
+ Area
+ </th>
+ <th style="width:54px;">
+ ID
+ </th>
+ <th>
+ Description
+ </th>
+ <th style="width:54px;">
+ Tests
+ </th>
+ </tr>
+
+ <tr id="PS-S1">
+ <td>
+ Stability
+ </td>
+ <td>
+ PS-S1
+ </td>
+ <td>
+ App does not crash, force close, freeze, or otherwise function abnormally
+ on any targeted device.
+ </td>
+ <td>
+ <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>, <a href=
+ "#HA-1">HA-1</a>
+ </td>
+ </tr>
+
+ <tr id="PS-P1">
+ <td rowspan="2">
+ Performance
+ </td>
+ <td>
+ PS-P1
+ </td>
+ <td>
+ App loads quickly or provides onscreen feedback to the user (a progress
+ indicator or similar cue) if the app takes longer than two seconds to
+ load.
+ </td>
+ <td>
+ <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>
+ </td>
+ </tr>
+
+ <tr id="PS-P2">
+ <td>
+ PS-P2
+ </td>
+ <td>
+ With StrictMode enabled (see <a href="#strictmode">StrictMode
+ Testing</a>, below), no red flashes (performance warnings from
+ StrictMode) are visible when exercising the app, including during game
+ play, animations and UI transitions, and any other part of the app.
+ </td>
+ <td>
+ <a href="#PM-1">PM-1</a>
+ </td>
+ </tr>
+
+ <tr id="PS-M1">
+ <td>
+ Media
+ </td>
+ <td>
+ PS-M1
+ </td>
+ <td>
+ Music and video playback is smooth, without crackle, stutter, or other
+ artifacts, during normal app usage and load.
+ </td>
+ <td>
+ <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>, <a href=
+ "#HA-1">HA-1</a>
+ </td>
+ </tr>
+
+ <tr id="PS-V1">
+ <td rowspan="2">
+ Visual quality
+ </td>
+ <td>
+ PS-V1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ App displays graphics, text, images, and other UI elements without
+ noticeable distortion, blurring, or pixelation.
+ </p>
+
+ <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+ <li>App provides high-quality graphics for all targeted screen sizes
+ and form factors, including for <a href=
+ "{@docRoot}distribute/essentials/quality/tablet.html">larger-screen
+ devices such as tablets</a>.
+ </li>
+
+ <li>No aliasing at the edges of menus, buttons, and other UI elements
+ is visible.
+ </li>
+ </ol>
+ </td>
+ <td rowspan="2">
+ <a href="#core">CR-all</a>
+ </td>
+ </tr>
+
+ <tr id="PS-V2">
+ <td>
+ PS-V2
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ App displays text and text blocks in an acceptable manner.
+ </p>
+
+ <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+ <li>Composition is acceptable in all supported form factors, including
+ for larger-screen devices such as tablets.
+ </li>
+
+ <li>No cut-off letters or words are visible.
+ </li>
+
+ <li>No improper word wraps within buttons or icons are visible.
+ </li>
+
+ <li>Sufficient spacing between text and surrounding elements.
+ </li>
+ </ol>
+ </td>
+ </tr>
+</table>
+
+<h3>
+ Related Resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/essentials/core/performance" data-sortorder="-timestamp"
+data-cardsizes="6x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="listing">
+ Google Play
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ These criteria ensure that your apps are ready to publish on Google Play.
+</p>
+
+<table>
+ <tr>
+ <th style="width:2px;">
+ Area
+ </th>
+ <th style="width:54px;">
+ ID
+ </th>
+ <th>
+ Description
+ </th>
+ <th style="width:54px;">
+ Tests
+ </th>
+ </tr>
+
+ <tr id="GP-P1">
+ <td rowspan="2">
+ Policies
+ </td>
+ <td>
+ GP-P1
+ </td>
+ <td>
+ App strictly adheres to the terms of the <a href=
+ "http://play.google.com/about/developer-content-policy.html">Google Play
+ Developer Content Policy</a> and does not offer inappropriate content,
+ does not use intellectual property or brand of others, and so on.
+ </td>
+ <td>
+ <a href="#gp">GP-all</a>
+ </td>
+ </tr>
+
+ <tr id="GP-P2">
+ <td>
+ GP-P2
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ App maturity level is set appropriately, based on the <a href=
+ "http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=188189">
+ Content Rating Guidelines</a>.
+ </p>
+
+ <p style="margin-bottom:.25em;">
+ Especially, note that apps that request permission to use the device
+ location cannot be given the maturity level "Everyone".
+ </p>
+ </td>
+ <td>
+ <a href="#gp">GP-1</a>
+ </td>
+ </tr>
+
+ <tr id="GP-D1">
+ <td rowspan="3">
+ App Details Page
+ </td>
+ <td>
+ GP-D1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ App feature graphic follows the guidelines outlined in this <a href=
+ "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">
+ blog post</a>. Make sure that:
+ </p>
+
+ <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+ <li>The app listing includes a high-quality feature graphic.
+ </li>
+
+ <li>The feature graphic does not contain device images, screenshots, or
+ small text that will be illegible when scaled down and displayed on the
+ smallest screen size that your app is targeting.
+ </li>
+
+ <li>The feature graphic does not resemble an advertisement.
+ </li>
+ </ol>
+ </td>
+ <td>
+ <a href="#gp">GP-1, GP-2</a>
+ </td>
+ </tr>
+
+ <tr id="GP-D2">
+ <td>
+ GP-D2
+ </td>
+ <td>
+ App screenshots and videos do not show or reference non-Android devices.
+ </td>
+ <td rowspan="2">
+ <a href="#gp">GP-1</a>
+ </td>
+ </tr>
+
+ <tr id="GP-D3">
+ <td>
+ GP-D3
+ </td>
+ <td>
+ App screenshots or videos do not represent the content and experience of
+ your app in a misleading way.
+ </td>
+ </tr>
+
+ <tr id="GP-X1">
+ <td>
+ User Support
+ </td>
+ <td>
+ GP-X1
+ </td>
+ <td>
+ Common user-reported bugs in the Reviews tab of the Google Play page are
+ addressed if they are reproducible and occur on many different devices.
+ If a bug occurs on only a few devices, you should still address it if
+ those devices are particularly popular or new.
+ </td>
+ <td>
+ <a href="#gp">GP-1</a>
+ </td>
+ </tr>
+</table>
+
+<h3>
+ Related Resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/essentials/core/play" data-sortorder="-timestamp"
+data-cardsizes="6x3,6x3,6x3,6x3,6x3,6x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="test-environment">
+ Setting Up a Test Environment
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ To assess the quality of your app, you need to set up a suitable hardware or
+ emulator environment for testing.
+</p>
+
+<p>
+ The ideal test environment would include a small number of actual hardware
+ devices that represent key form factors and hardware/software combinations
+ currently available to consumers. It's not necessary to test on
+ <em>every</em> device that's on the market — rather, you should focus
+ on a small number of representative devices, even using one or two devices
+ per form factor.
+</p>
+
+<p>
+ If you are not able to obtain actual hardware devices for testing, you should
+ <a href="{@docRoot}tools/devices/index.html">set up emulated devices
+ (AVDs)</a> to represent the most common form factors and hardware/software
+ combinations.
+</p>
+
+<p>
+ To go beyond basic testing, you can add more devices, more form factors, or
+ new hardware/software combinations to your test environment. You can also
+ increase the number or complexity of tests and quality criteria.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="tests">
+ Test Procedures
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ These test procedures help you discover various types of quality issues in
+ your app. You can combine the tests or integrate groups of tests together in
+ your own test plans. See the sections above for references that associate
+ specific criteria with specific tests.
+</p>
+
+<table>
+ <tr>
+ <th style="width:2px;">
+ Type
+ </th>
+ <th style="width:54px;">
+ Test
+ </th>
+ <th>
+ Description
+ </th>
+ </tr>
+
+ <tr>
+ <td rowspan="12" id="core">
+ Core Suite
+ </td>
+ <td>
+ CR-0
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ Navigate to all parts of the app — all screens, dialogs,
+ settings, and all user flows.
+ </p>
+
+ <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+ <li>If the application allows for editing or content creation, game
+ play, or media playback, make sure to enter those flows to create or
+ modify content.
+ </li>
+
+ <li>While exercising the app, introduce transient changes in network
+ connectivity, battery function, GPS or location availability, system
+ load, and so on.
+ </li>
+ </ol>
+ </td>
+ </tr>
+
+ <tr id="tg2">
+ <td id="core2">
+ CR-1
+ </td>
+ <td>
+ From each app screen, press the device's Home key, then re-launch the app
+ from the All Apps screen.
+ </td>
+ </tr>
+
+ <tr id="CR-2">
+ <td>
+ CR-2
+ </td>
+ <td>
+ From each app screen, switch to another running app and then return to
+ the app under test using the Recents app switcher.
+ </td>
+ </tr>
+
+ <tr id="CR-3">
+ <td>
+ CR-3
+ </td>
+ <td>
+ From each app screen (and dialogs), press the Back button.
+ </td>
+ </tr>
+
+ <tr id="CR-5">
+ <td>
+ CR-5
+ </td>
+ <td>
+ From each app screen, rotate the device between landscape and portrait
+ orientation at least three times.
+ </td>
+ </tr>
+
+ <tr id="CR-6">
+ <td>
+ CR-6
+ </td>
+ <td>
+ Switch to another app to send the test app into the background. Go to
+ Settings and check whether the test app has any services running while in
+ the background. In Android 4.0 and higher, go to the Apps screen and find
+ the app in the "Running" tab. In earlier versions, use "Manage
+ Applications" to check for running services.
+ </td>
+ </tr>
+
+ <tr id="CR-7">
+ <td>
+ CR-7
+ </td>
+ <td>
+ Press the power button to put the device to sleep, then press the power
+ button again to awaken the screen.
+ </td>
+ </tr>
+
+ <tr id="CR-8">
+ <td>
+ CR-8
+ </td>
+ <td>
+ Set the device to lock when the power button is pressed. Press the power
+ button to put the device to sleep, then press the power button again to
+ awaken the screen, then unlock the device.
+ </td>
+ </tr>
+
+ <tr id="CR-9">
+ <!-- Hardware features -->
+
+ <td>
+ CR-9
+ </td>
+ <td>
+ For devices that have slide-out keyboards, slide the keyboard in and out
+ at least once. For devices that have keyboard docks, attach the device to
+ the keyboard dock.
+ </td>
+ </tr>
+
+ <tr id="CR-10">
+ <td>
+ CR-10
+ </td>
+ <td>
+ For devices that have an external display port, plug-in the external
+ display.
+ </td>
+ </tr>
+
+ <tr id="CR-11">
+ <td>
+ CR-11
+ </td>
+ <td>
+ Trigger and observe in the notications drawer all types of notifications
+ that the app can display. Expand notifications where applicable (Android
+ 4.1 and higher), and tap all actions offered.
+ </td>
+ </tr>
+
+ <tr id="CR-12">
+ <td>
+ CR-12
+ </td>
+ <td>
+ Examine the permissions requested by the app by going to Settings >
+ App Info.
+ </td>
+ </tr>
+
+ <tr id="tg3">
+ <td>
+ Install on SD Card
+ </td>
+ <td>
+ SD-1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ Repeat <em>Core Suite</em> with app installed to <a href=
+ "{@docRoot}guide/topics/data/install-location.html">device SD card</a>
+ (if supported by app).
+ </p>
+
+ <p style="margin-bottom:.25em;">
+ To move the app to SD card, you can use Settings > App Info >
+ Move to SD Card.
+ </p>
+ </td>
+ </tr>
+
+ <tr id="tg32">
+ <td>
+ Hardware acceleration
+ </td>
+ <td>
+ HA-1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ Repeat <em>Core Suite</em> with hardware acceleration enabled.
+ </p>
+
+ <p style="margin-bottom:.25em;">
+ To force-enable hardware acceleration (where supported by device), add
+ <code>hardware-accelerated="true"</code> to the
+ <code><application></code> in the app manifest and recompile.
+ </p>
+ </td>
+ </tr>
+
+ <tr id="tg33">
+ <td>
+ Performance Monitoring
+ </td>
+ <td>
+ PM-1
+ </td>
+ <td>
+ <p style="margin-bottom:.5em;">
+ Repeat <em>Core Suite</em> with StrictMode profiling enabled <a href=
+ "#strictmode">as described below</a>.
+ </p>
+
+ <p style="margin-bottom:.25em;">
+ Pay close attention to garbage collection and its impact on the user
+ experience.
+ </p>
+ </td>
+ </tr>
+
+ <tr id="gp">
+ <td rowspan="3">
+ Google Play
+ </td>
+ <td>
+ GP-1
+ </td>
+ <td>
+ Sign into the <a href="https://play.google.com/apps/publish/">Developer
+ Console</a> to review your developer profile, app description,
+ screenshots, feature graphic, maturity settings, and user feedback.
+ </td>
+ </tr>
+
+ <tr id="GP-2">
+ <td>
+ GP-2
+ </td>
+ <td>
+ Download your feature graphic and screenshots and scale them down to
+ match the display sizes on the devices and form factors you are
+ targeting.
+ </td>
+ </tr>
+
+ <tr id="GP-3">
+ <td>
+ GP-3
+ </td>
+ <td>
+ Review all graphical assets, media, text, code libraries, and other
+ content packaged in the app or expansion file download.
+ </td>
+ </tr>
+
+ <tr id="GP-4">
+ <td>
+ Payments
+ </td>
+ <td>
+ GP-4
+ </td>
+ <td>
+ Navigate to all screens of your app and enter all in-app purchase flows.
+ </td>
+ </tr>
+</table>
+
+<h3 id="strictmode">
+ Testing with StrictMode
+</h3>
+
+<p>
+ For performance testing, we recommend enabling {@link android.os.StrictMode}
+ in your app and using it to catch operations on the main thread and other
+ threads that could affect performance, network accesses, file reads/writes,
+ and so on.
+</p>
+
+<p>
+ You can set up a monitoring policy per thread using {@link
+ android.os.StrictMode.ThreadPolicy.Builder} and enable all supported
+ monitoring in the <code>ThreadPolicy</code> using {@link
+ android.os.StrictMode.ThreadPolicy.Builder#detectAll()}.
+</p>
+
+<p>
+ Make sure to enable <strong>visual notification</strong> of policy violations
+ for the <code>ThreadPolicy</code> using {@link
+ android.os.StrictMode.ThreadPolicy.Builder#penaltyFlashScreen()
+ penaltyFlashScreen()}.
+</p>
diff --git a/docs/html/distribute/essentials/quality/tablets.jd b/docs/html/distribute/essentials/quality/tablets.jd
new file mode 100644
index 0000000..7dfab48
--- /dev/null
+++ b/docs/html/distribute/essentials/quality/tablets.jd
@@ -0,0 +1,867 @@
+page.title=Tablet App Quality
+page.metaDescription=Tablets are a fast-growing part of the Android installed base that offers new opportunities for your apps.
+page.image=/distribute/images/tablet-guidelines-color.jpg
+Xnonavpage=true
+
+@jd:body
+<div id="qv-wrapper"><div id="qv">
+<h2>Checklist</h2>
+<ol>
+<li><a href="#core-app-quality">1. Test for Basic Tablet App Quality</a></li>
+<li><a href="#optimize-layouts">2. Optimize Layouts</a></li>
+<li><a href="#use-extra-space">3. Use Extra Screen Area</a></li>
+<li><a href="#use-tablet-icons">4. Use Assets Designed for Tablets</a></li>
+<li><a href="#adjust-font-sizes">5. Adjust Fonts and Touch Targets</a></li>
+<li><a href="#adjust-widgets">6. Adjust Homescreen Widgets</a></li>
+<li><a href="#offer-full-feature-set">7. Offer Full Feature Set</a></li>
+<li><a href="#android-versions">8. Target Android Versions Properly</a></li>
+<li><a href="#hardware-requirements">9. Declare Dependencies Properly</a></li>
+<li><a href="#support-screens">10. Declare Support for Tablet Screens</a></li>
+<li><a href="#google-play">11. Showcase Your Tablet UI</a></li>
+<li><a href="#google-play-best-practices">12. Follow Best Practices for Publishing in Google Play</a></li>
+
+</ol>
+<h2>Testing</h2>
+<ol>
+<li><a href="#test-environment">Setting Up a Test Environment</a></li>
+</ol>
+</div></div>
+
+<div class="todp-right-float" style="padding-right:0;margin-bottom:1em;">
+ <img src="{@docRoot}distribute/images/tablet-guidelines-color.jpg" style="width:480px;">
+</div>
+
+<p>
+ Tablets are a growing part of the Android installed base and offer new
+ opportunities for <a href="{@docRoot}distribute/stories/tablets.html">user
+ engagement and monetization</a>. The guidelines in this document will help
+ you meet the expectations of tablet users through compelling features and an
+ intuitive, well-designed UI.
+</p>
+
+<p>
+ Although the guidelines are numbered, you can approach them in any order. You
+ should address each guideline’s recommendations to the extent that they’re
+ appropriate for your app, but — in the interest of delivering the best
+ product to your customers — follow them to the greatest extent
+ possible.
+</p>
+
+<p>
+ Through the document you'll find links to resources that can
+ help you address each recommendation included.
+</p>
+
+<div class="headerLine"><h1 id="core-app-quality">1. Test for Basic Tablet App Quality</h1><hr></div>
+
+<p>The first step in delivering a great tablet app experience is making sure
+that it meets the <em>core app quality criteria</em> for all of the devices
+and form factors that the app is targeting. For complete information, see the <a
+href="{@docRoot}distribute/essentials/quality/core.html">Core App Quality Guidelines</a>.
+</p>
+
+<p>
+Before publishing, also ensure that your app passes the basic technical checks and launch criteria, such as:
+</p>
+
+<ul>
+ <li><a href="#android-versions">Targets appropriate Android versions</a></li>
+ <li><a href="#hardware-requirements">Specifies any hardware dependencies properly</a></li>
+ <li><a href="#support-screens">Declares support for appropriate screens</a></li>
+ <li><a href="#use-extra-space">Uses all of the available screen space</a></li>
+ <li><a href="#google-play">Screenshots are uploaded to Google Play</a></li>
+</ul>
+
+<p>If your app is already uploaded to the Google Play Developer Console, you
+ can see how it is doing against these checks
+ by visiting the <a href="#google-play-optimization-tips">Optimization
+ Tips page</a>.</p>
+
+
+<div class="headerLine clearfloat">
+<h1 id="optimize-layouts">2. Optimize Layouts for Larger Screens</h1><hr></div>
+
+<p>
+ Android makes it easy to develop an app that runs well on a wide range of
+ device screen sizes and form factors. This broad compatibility works in your
+ favor, since it helps you design a single app that you can distribute widely
+ to all of your targeted devices. However, to give your users the best
+ possible experience on each screen configuration — in particular on
+ tablets — you need to optimize your layouts and other UI components for
+ each targeted screen configuration. On tablets, optimizing your UI lets you
+ take full advantage of the additional screen available, such as to offer new
+ features, present new content, or enhance the experience in other ways to
+ deepen user engagement.
+</p>
+
+<p>
+ If you developed your app for handsets and now want to distribute it to
+ tablets, you can start by making minor adjustments to your layouts, fonts,
+ and spacing. In some cases — such as for 7-inch tablets or for a game
+ with large canvas — these adjustments may be all you need to make your
+ app look great. In other cases, such as for larger tablets, you can redesign
+ parts of your UI to replace "stretched UI" with an efficient multipane UI,
+ easier navigation, and additional content.
+</p>
+
+
+<div style="width:500px;margin:1.5em;margin-top:-16px;">
+<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-bad.png"
+style="padding:4px;margin-bottom:0em;">
+<p class="img-caption"><span
+style="font-weight:500;">Get rid of "stretched" UI</span>: On tablets, single-pane
+layouts lead to awkward whitespace and excessive line lengths. Use padding to
+reduce the width of UI elements and consider using multi-pane layouts.</p>
+</div>
+
+<p>Here are some suggestions:</p>
+
+
+<ul>
+ <li>Provide custom layouts as needed for <code>large</code> and
+ <code>xlarge</code> screens. You can also provide layouts that are loaded
+ based on the screen's <a href=
+ "{@docRoot}guide/practices/screens_support.html#NewQualifiers">shortest
+ dimension</a> or the <a href=
+ "{@docRoot}guide/practices/screens_support.html#NewQualifiers">minimum
+ available width and height</a>.
+ </li>
+
+ <li>At a minimum, customize dimensions such as font sizes, margins, spacing
+ for larger screens, to improve use of space and content legibility.
+ </li>
+
+ <li>Adjust positioning of UI controls so that they are easily accessible to
+ users when holding a tablet, such as toward the sides when in landscape
+ orientation.
+ </li>
+
+ <li>Padding of UI elements should normally be larger on tablets than on
+ handsets. A <a href="{@docRoot}design/style/metrics-grids.html#48dp-rhythm">
+ 48dp rhythm</a> (and a 16dp grid) is recommended.
+ </li>
+
+ <li>Adequately pad text content so that it is not aligned directly along
+ screen edges. Use a minimum <code>16dp</code> padding around content near
+ screen edges.
+ </li>
+</ul>
+
+<p>In particular, make sure that your layouts do not appear "stretched"
+across the screen:</p>
+
+<ul>
+<li>Lines of text should not be excessively long — optimize for a maximum
+100 characters per line, with best results between 50 and 75.</li>
+<li>ListViews and menus should not use the full screen width.</li>
+<li>Use padding to manage the widths of onscreen elements or switch to a
+multi-pane UI for tablets (see next section).</li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/essentials/tabletguidelines/optimize"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x3"
+ data-maxResults="6"></div>
+
+
+<div class="headerLine clearfloat"><h1 id="use-extra-space">3. Take Advantage of Extra Screen Area</h1><hr></div>
+
+<div style="width:340px;float:right;margin:1.5em;margin-bottom:0;margin-top:0;">
+<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-good.png"
+style="padding:4px;margin-bottom:0em;">
+<p class="img-caption"><span
+style="font-weight:500;">Multi-pane layouts</span> result in a better visual
+balance on tablet screens, while offering more utility and legibility.</p>
+</div>
+
+<p>Tablet screens provide significantly more screen real estate to your app,
+especially when in landscape orientation. In particular, 10-inch tablets offer a
+greatly expanded area, but even 7-inch tablets give you more space for
+displaying content and engaging users. </p>
+
+<p>As you consider the UI of your app when running on tablets, make sure that it
+is taking full advantage of extra screen area available on tablets. Here are
+some suggestions:</p>
+
+<ul>
+<li>Look for opportunities to include additional content or use an alternative
+treatment of existing content.</li>
+<li>Use <a href="{@docRoot}design/patterns/multi-pane-layouts.html">multi-pane
+layouts</a> on tablet screens to combine single views into a compound view. This
+lets you use the additional screen area more efficiently and makes it easier for
+users to navigate your app. </li>
+<li>Plan how you want the panels of your compound views to reorganize when
+screen orientation changes.</li>
+
+<div style="width:490px;margin:1.5em auto 1.5em 0;">
+<div style="">
+<img src="{@docRoot}images/ui-ex-single-panes.png"
+style="width:490px;padding:4px;margin-bottom:0em;" align="middle">
+<img src="{@docRoot}images/ui-ex-multi-pane.png" style="width:490px;padding:4px;margin-bottom:0em;">
+<p class="image-caption" style="padding:.5em"><span
+style="font-weight:500;">Compound views</span> combine several single views from a
+handset UI <em>(above)</em> into a richer, more efficient UI for tablets
+<em>(below)</em>. </p>
+</div>
+</div>
+
+<li>While a single screen is implemented as an {@link android.app.Activity}
+subclass, consider implementing individual content panels as {@link
+android.app.Fragment} subclasses. This lets you
+maximize code reuse across different form factors and across screens that
+share content.</li>
+<li>Decide on which screen sizes you'll use a multi-pane UI, then provide the
+different layouts in the appropriate screen size buckets (such as
+<code>large</code>/<code>xlarge</code>) or minimum screen widths (such as
+<code>sw600dp</code>/<code>sw720</code>).</li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/essentials/tabletguidelines/extrascreen"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x3,6x3,6x3"
+ data-maxResults="6"></div>
+
+<div class="headerLine clearfloat"><h1 id="use-tablet-icons">4. Use Assets Designed for Tablet Screens</h1><hr></div>
+
+<div><img src="{@docRoot}design/media/devices_displays_density@2x.png"></div>
+
+<p>To ensure your app looks its best, provide icons and other bitmap
+assets for each density in the range commonly supported by tablets. Specifically, you should
+design your icons for the action bar, notifications, and launcher according to the
+<a href="{@docRoot}design/style/iconography.html">Iconography</a> guidelines and
+provide them in multiple densities, so they appear at the appropriate size on all screens
+without blurring or other scaling artifacts.</p>
+
+<p class="table-caption"><strong>Table 1</strong>. Raw asset sizes for icon types.<table>
+<tr>
+<th>Density</th>
+<th>Launcher</th>
+<th>Action Bar</th>
+<th>Small/Contextual</th>
+<th>Notification</th>
+</tr>
+<tr>
+<td><code>mdpi</code></td>
+<td>48x48 px</td>
+<td>32x32 px</td>
+<td>16x16 px</td>
+<td>24x24 px</td>
+</tr>
+<tr>
+<td><code>hdpi</code></td>
+<td>72x72 px</td>
+<td>48x48 px</td>
+<td>24x24 px</td>
+<td>36x36 px</td>
+</tr>
+<tr>
+<td><code>tvdpi</code></td>
+<td><em>(use hdpi)</em></td>
+<td><em>(use hdpi)</em></td>
+<td><em>(use hdpi)</em></td>
+<td><em>(use hdpi)</em></td>
+</tr>
+<tr>
+<td><code>xhdpi</code></td>
+<td>96x96 px</td>
+<td>64x64 px</td>
+<td>32x32 px</td>
+<td>48x48 px</td>
+</tr>
+<tr>
+<td><code>xxhdpi</code></td>
+<td>144x144 px</td>
+<td>96x96 px</td>
+<td>48x48 px</td>
+<td>72x72 px</td>
+</tr>
+
+</table>
+
+<p>
+ As a minimum, supply a version of each icon and bitmap asset that's optimized
+ for <strong>at least one</strong> the following common tablet screen
+ densities:
+</p>
+<ul>
+ <li><code>hdpi</code></li>
+ <li><code>xhdpi</code></li>
+ <li><code>xxhdpi</code></li>
+</ul>
+
+<p>Other tips:</p>
+
+<ul>
+<li>Use vector shapes when designing icons, so they scale without loss of either detail or edge crispness.</li>
+<li>Use density-specific <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">
+resource qualifiers</a> to ensure that the proper icons are loaded for each screen density.</li>
+<li>Tablets and other large screen devices often request a launcher icon that is one density
+size larger than the device's actual density, so you should provide your launcher
+icon at the highest density possible. For example, if a tablet has an {@code xhdpi} screen,
+it will request the {@code xxhdpi} version of the launcher icon.</li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/essentials/tabletguidelines/assets"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="6"></div>
+
+<div class="headerLine clearfloat"><h1 id="adjust-font-sizes">5.
+Adjust Font Sizes and Touch Targets</h1><hr></div>
+
+<p>To make sure your app is easy to use on tablets, take some time to adjust the
+font sizes and touch targets in your tablet UI, for all of the screen
+configurations you are targeting. You can adjust font sizes through <a
+href="{@docRoot}guide/topics/ui/themes.html">styleable attributes</a> or <a
+href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">dimension
+resources</a>, and you can adjust touch targets through layouts and bitmap
+drawables, as discussed above. </p>
+
+<p>Here are some considerations:</p>
+<ul>
+<li>Text should not be excessively large or small on tablet screen sizes and
+densities. Make sure that labels are sized appropriately for the UI elements they
+correspond to, and ensure that there are no improper line breaks in labels,
+titles, and other elements.</li>
+<li>The recommended touch-target size for onscreen elements is 48dp (32dp
+minimum) — some adjustments may be needed in your tablet UI. Read <a
+href="{@docRoot}design/style/metrics-grids.html">Metrics and
+Grids
+</a> to learn about implementation strategies to help most of your users. To
+meet the accessibility needs of certain users, it may be appropriate to use
+larger touch targets. </li>
+<li>When possible, for smaller icons, expand the touchable area to more than
+48dp using {@link android.view.TouchDelegate}
+or just centering the icon within the transparent button.</li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/essentials/tabletguidelines/fonts"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3,9x3,6x3,6x3,6x3"
+ data-maxResults="6"></div>
+
+<div class="headerLine clearfloat"><h1 id="adjust-widgets">6. Adjust Sizes of Home Screen Widgets</h1><hr></div>
+
+<p>If your app includes a home screen widget, here are a few points to consider
+to ensure a great user experience on tablet screens: </p>
+
+<ul>
+<li>Set the widget's default height and width appropriately
+for tablet screens, as well as the minimum and maximum resize height and width.
+</li>
+<li>The widget should be resizable to 420dp or more, to span 5 or more home
+screen rows (if this is a vertical or square widget) or columns (if this is a
+horizontal or square widget). </li>
+<li>Make sure that 9-patch images render correctly.</li>
+<li>Use default system margins.</li>
+<li>Set the app's <code>targetSdkVersion</code> to 14 or higher, if
+possible.</li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/essentials/tabletguidelines/widgets"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x3"
+ data-maxResults="6"></div>
+
+
+<div class="headerLine clearfloat"><h1 id="offer-full-feature-set">7. Full Feature Set for Tablet Users</h1><hr></div>
+
+<div class="centered-full-image" style="width:600px;margin:1.5em"><img src="{@docRoot}images/gp-tablets-full-feature-set.png" alt="Tablet feature sets"></div>
+
+<p>Let your tablet users experience the best features of your app. Here are
+some recommendations:</p>
+
+<ul>
+ <li>Design your app to offer at least the same set of features on tablets as
+ it does on phones.
+ </li>
+
+ <li>In exceptional cases, your app might omit or replace certain features on
+ tablets if they are not supported by the hardware or use-case of most
+ tablets. For example:
+ <ul>
+ <li>If the handset uses telephony features but telephony is not available
+ on the current tablet, you can omit or replace the related functionality.
+ </li>
+
+ <li>Many tablets have a GPS sensor, but most users would not normally
+ carry their tablets while running. If your phone app provides
+ functionality to let the user record a GPS track of their runs while
+ carrying their phones, the app would not need to provide that
+ functionality on tablets because the use-case is not compelling.
+ </li>
+ </ul>
+ </li>
+
+ <li>If you will omit a feature or capability from your tablet UI, make sure
+ that it is not accessible to users or that it offers “graceful degradation”
+ to a replacement feature (also see the section below on hardware features).
+ </li>
+</ul>
+
+<div class="headerLine clearfloat"><h1 id="android-versions">8. Target Android Versions Properly</h1><hr></div>
+
+<p>
+ To ensure the broadest possible distribution to tablets, make sure that your
+ app properly targets the Android versions that support tablets. Initial
+ support for tablets was added in <a href=
+ "{@docRoot}about/versions/android-3.0.html">Android 3.0</a> (API level 11).
+ Unified UI framework support for tablets, phones, and other devices was
+ introduced in <a href="{@docRoot}about/versions/android-4.0.html">Android
+ 4.0</a>
+</p>
+
+<p>
+ You can set the app's range of targeted Android versions in the manifest
+ file, in the <a href=
+ "{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code><uses-sdk></code></a>
+ element. In most cases, you can target Android versions properly by setting
+ the element's <code>targetSdkVersion</code> attribute to the highest API
+ level available.
+</p>
+
+<p style="margin-bottom:.5em;">
+ At a minimum, check the <a href=
+ "{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code><uses-sdk></code></a>
+ element to make sure that:
+</p>
+
+<ol style="list-style-type:lower-alpha;margin-top:0em;">
+ <li>
+ <code>targetSdkVersion</code> is declared with value 11 or higher (14 or
+ higher is recommended), OR
+ </li>
+
+ <li>
+ <code>minSdkVersion</code> is declared with value 11 or higher.
+ </li>
+
+ <li>If a <code>maxSdkVersion</code> attribute is declared, it must have a
+ value of 11 or higher. Note that, in general, the use of
+ <code>maxSdkVersion</code> is <em>not recommended</em>.
+ </li>
+</ol>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/essentials/tabletguidelines/versions"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x3"
+ data-maxResults="6"></div>
+
+<div class="headerLine clearfloat"><h1 id="hardware-requirements">9. Declare Hardware Feature Dependencies Properly</h1><hr></div>
+
+<p>
+ Handsets and tablets typically offer slightly different hardware support for
+ sensors, camera, telephony, and other features. For example, many tablets are
+ available in a "Wi-Fi" configuration that does not include telephony support.
+</p>
+
+<p>
+ So that you can distribute a single APK broadly across your full customer
+ base of phones and tablets, make sure that your app doesn't declare
+ requirements for hardware features that aren't commonly available on tablets.
+ Instead, properly declare the hardware features as <em>not required</em> in the app
+ manifest, as described below.
+</p>
+
+<ul>
+<li>In your app manifest, locate any <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code><uses-feature></code></a>
+elements. In particular, look for hardware features that might not be
+available on some tablets, such as:
+
+<ul>
+<li><code>android.hardware.telephony</code></li>
+<li><code>android.hardware.camera</code> (refers to back camera), or</li>
+<li><code>android.hardware.camera.front</code></li>
+</ul></li>
+
+<li>Declare the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code><uses-feature></code></a>
+elements as <em>not required</em> by including the <code>android:required=”false”</code>
+attribute.
+
+<p>
+ For example, here's the proper way to declare a dependency on
+ <code>android.hardware.telephony</code>, such that you can still
+ distribute the app broadly, even to devices that don't offer telephony:
+</p>
+
+<pre><uses-feature android:name="android.hardware.telephony" android:required="false" /></pre></li>
+
+<li>Similarly, check the manifest for <a href="{@docRoot}guide/topics/manifest/permission-element.html"><code><permission></code></a> elements that
+<a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions">imply hardware
+feature requirements</a> that not be appropriate for tablets. If you find such
+permissions, make sure to explicitly declare a corresponding
+<code><uses-feature></code> element for the features and includes the
+<code>android:required=”false”</code> attribute.</li>
+</ul>
+
+
+<p>
+ After declaring hardware features as <em>not required</em>, make sure to test
+ your app on a variety of devices. The app should function normally when the
+ hardware features it uses are not available, and it should offer "graceful
+ degradation" and alternative functionality where appropriate.
+</p>
+
+<p>
+ For example, if an app normally uses GPS to set the location but GPS is not
+ supported on the device, the app could let the user set the location manually
+ instead. The app can check for device hardware capabilities at runtime and handle
+ as needed.
+</p>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/essentials/tabletguidelines/hardware"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="6"></div>
+
+<div class="headerLine clearfloat"><h1 id="support-screens">10. Declare Support for Tablet Screens</h1><hr></div>
+
+<p>To ensure that you can distribute your app to a broad range of tablets, your app should
+declare support for tablet screen sizes in its manifest file, as follows:</p>
+
+<ul>
+ <li>A
+ <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code><supports-screens></code></a>
+ element, if declared, must not specify <code>android:largeScreens="false"</code>
+ or <code>android:xlargeScreens="false"</code>.</li>
+ <li>For apps targeting <code>minSdkVersion</code> value less than 13, a
+ <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code><supports-screens></code></a>
+ element must be declared with both <code>android:largeScreens="true"</code> and
+ <code>android:xlargeScreens="true"</code>.</li>
+</ul>
+
+<p>If the app declares a
+<a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html"><code><compatible-screens></code></a>
+element in the manifest, the element should include attributes that specify
+<em>all of the size and density combinations for tablet screens</em> that the
+app supports. Note that, if possible, you should avoid using the
+<a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html"><code><compatible-screens></code></a>
+element in your app.</p>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/essentials/tabletguidelines/tabletscreens"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3,6x3,6x3"
+ data-maxResults="6"></div>
+
+
+<div class="headerLine clearfloat"><h1 id="google-play">11. Showcase Your Tablet UI in Google Play</h1><hr></div>
+
+<p>
+ After you've done the work to create an rich, optimized UI for your tablet
+ app, make sure that you let your customers know about it! Here are some key
+ ways to promote your tablet app to users on Google Play.
+</p>
+
+<div><img class="border-img" src="{@docRoot}images/gp-tablet-quality-4.jpg"></div>
+
+
+<h4>
+ Upload screenshots of your tablet UI
+</h4>
+
+<p>
+ Tablet users want to know what your app is like on a tablet device, not on a
+ phone. If you developed a tablet app, make sure to upload screenshots
+ of your tablet UI to the Google Play Developer Console. Here are some guidelines:
+ </p>
+
+<ul style="margin-top:0;">
+ <li>Show the core functionality of your app, not a
+ startup or sign-in page. Wherever users will spend most of their time, that's
+ what you should show in your screenshots.
+ </li>
+
+ <li>Add screenshots taken on both 7-inch and 10-inch tablets.
+ </li>
+
+ <li>Add screenshots taken in both landscape and
+ portrait orientations, if possible.
+ </li>
+
+ <li>Use screen captures if possible. Avoid showing actual device hardware in your
+ screenshots.</li>
+
+ <li>The recommended resolution of your tablet screenshots is <strong>1280 x 720</strong>
+ or higher in each orientation.
+ </li>
+
+ <li>Upload as many as 8 screenshots of your tablet UI for 7-inch tablets
+ and an additional 8 for 10-inch tablets.
+ </li>
+</ul>
+
+<h4>
+ Update your app description and release notes
+</h4>
+
+<ul>
+ <li>In your app description, make sure to highlight that your app offers
+ tablet-optimized UI and great features for tablet users. Add some
+ detail about how your tablet UI works and why users will like it.
+ </li>
+
+ <li>Include information about tablet support in the app's release notes and
+ update information.
+ </li>
+</ul>
+
+<h4>
+ Update your promotional video
+</h4>
+
+<p>
+ Many users view an app's promotional video to get an idea of what the app is
+ like and whether they'll enjoy it. For tablet users, capitalize on this
+ interest by highlighting your app's tablet UI in your promotional video. Here
+ are some tips and guidelines:
+</p>
+
+<ul>
+ <li>Add one or more shots of your app running on a tablet. To engage with
+ tablet users most effectively, it's recommended that you promote your tablet
+ UI in approximately equal proportion to your phone UI.
+ </li>
+
+ <li>Show your tablet UI as early as possible in the video. Don't assume that
+ tablet users will wait patiently through a feature walkthrough on a phone UI.
+ Ideally, you should engage them immediately by showing the tablet UI within
+ the first 10 seconds, or at the same point that you introduce the phone UI.
+ </li>
+
+ <li>To make it clear that you are showing a tablet UI, include shots of your
+ app running on a hand-held tablet device.
+ </li>
+
+ <li>Highlight your app's tablet UI in the video's narrative or voiceover.
+ </li>
+</ul>
+
+<h4>
+ Feature your tablet UI in your promotional campaigns
+</h4>
+
+<p>
+ Make sure to let tablet users know about your tablet UI in your promotional
+ campaigns, web site, social posts, advertisements, and elsewhere. Here are
+ some suggestions:
+</p>
+
+<ul>
+ <li>Plan a marketing or advertising campaign that highlights the use of your
+ app on tablets.</li>
+
+ <li>Show your tablet app at its best in your promotional campaigns—use the <a href=
+ "{@docRoot}distribute/tools/promote/device-art.html">Device Art Generator</a> to
+ quickly generate a high-quality promotional image of your app running on a
+ 7-inch or 10-inch tablet, in the orientation of your choice, with or without
+ drop-shadow and screen glare. It's as simple as capture, drag, and drop.
+ </li>
+
+ <li>Include a Google Play badge in your online promotions to let users link
+ directly to your app's store listing. You can generate a badge in a variety
+ of languages using the <a href=
+ "{@docRoot}distribute/tools/promote/badges.html">Badge Generator</a>.
+ </li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/essentials/tabletguidelines/showcase"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3,9x3,9x3,9x3"
+ data-maxResults="6"></div>
+
+<div class="headerLine clearfloat">
+ <h1 id="google-play-best-practices">
+ 12. Follow Best Practices for Publishing in Google Play
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Here are some best practices for delivering a successful tablet app on Google
+ Play.
+</p>
+
+<div>
+ <img class="border-img" src="{@docRoot}images/gp-tablet-quality-5.jpg" style=
+ "1px solid #ddd">
+</div>
+
+<h4 id="google-play-optimization-tips">
+ Check out your app's Optimization Tips
+</h4>
+
+<p>The Google Play Developer Console now offers an Optimization Tips page that
+lets you quickly check how your app is doing against basic guidelines for tablet app
+distribution and quality. To visit the page, sign into the Developer Console,
+load the app from All Applications, and click Optimization Tips in
+the left navigation.</p>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h2>How to send feedback</h2>
+
+<p>Please use the link below to send
+feedback or request a manual review of your Optimization Tips.</p>
+
+<p>Make sure to read the relevant sections of the Tablet App Quality
+Guidelines prior to sending feedback.</p>
+
+<p><strong><a href="https://support.google.com/googleplay/android-developer/contact/tabletq"
+target="_googleplay" style="white-space:nowrap">Designed for Tablets Contact Form »</a></strong></p>
+</div>
+</div>
+
+<p>The Developer Console creates your app's Optimization Tips page
+by running a series of checks to verify basic quality
+criteria. If it finds any issues, it alerts you to them as "To Do"
+items in the Optimization Tips page.</p>
+
+<p>If you've developed a tablet experience for your app, make sure
+to visit the Optimization Tips page to see how your app is doing
+against the basic checks. If there are any issues listed, we
+recommend addressing them in your app and uploading a new binary for
+distribution, if needed. </p>
+
+<p>If the Optimization Tips page lists "To Do" issues that you feel don't
+apply to your app or affect its quality on tablets, please notify us
+using the <a href="https://support.google.com/googleplay/android-developer/contact/tabletq"
+target="_googleplay" style="white-space:nowrap">Designed for Tablets Contact Form »</a>. We
+will review your app and update your Optimization Tips page as
+appropriate.</p>
+
+
+<h4>Confirm the app's filtering</h4>
+
+<p>
+ After you've uploaded the app to the <a href=
+ "https://play.google.com/apps/publish/">Developer Console</a>, check the
+ APK's Supported Devices list to make sure that the app is not filtered from
+ tablet devices that you want to target.
+</p>
+
+<h4>Distribute as a single APK</h4>
+
+<p>
+ It's recommended that you publish your app as a single APK for all screen
+ sizes (phones and tablets), with a single Google Play listing. This approach
+ has several important advantages.
+</p>
+
+<ul style="margin-top:.25em;">
+ <li>Easier for users to find your app from search, browsing, or promotions
+ </li>
+
+ <li>Easier for users to restore your app automatically if they get a new
+ device.
+ </li>
+
+ <li>Your ratings and download stats are consolidated across all devices.
+ </li>
+
+ <li>Publishing a tablet app in a second listing can dilute ratings for your
+ brand.
+ </li>
+</ul>
+
+<p>
+ If necessary, you can alternatively choose to deliver your app using <a href=
+ "{@docRoot}google/play/publishing/multiple-apks.html">Multiple APK Support</a>,
+ although in most cases using a single APK to reach all devices is strongly
+ recommended.
+</p>
+
+<h3 class="clearfloat">Related resources</h3>
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/essentials/tabletguidelines/googleplay"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="6"></div>
+
+
+<div class="headerLine clearfloat">
+ <h1 id="test-environment">
+ Setting Up a Test Environment for Tablets
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Assess the quality of your app on tablets — both for core app quality and
+ tablet app quality — with a suitable hardware or emulator environment
+ for testing.
+</p>
+
+<p>
+ Compared to the <a href=
+ "{@docRoot}distribute/essentials/quality/core.html#test-environment">recommended
+ test environment</a> for testing against the core app quality criteria,
+ include mid-size tablets and tablets with more or fewer hardware/software
+ features.
+</p>
+
+<p class="table-caption"><strong>Table 1</strong>. A typical tablet test environment might
+include one or two devices from each row in the table below, with one of the
+listed platform versions, screen configurations, and hardware feature configurations.</p>
+
+<table>
+<tr>
+<th>Type</th>
+<th>Size</th>
+<th>Density</th>
+<th>Version</th>
+<th>AVD Skin</th>
+</tr>
+
+<tr>
+<td>7-inch tablet</td>
+<td><span style="white-space:nowrap"><code>large</code> or</span><br /><code>-sw600</code></td>
+<td><code>hdpi</code>,<br /><code>tvdpi</code></td>
+<td>Android 4.0+ (API level 14 and higher)</td>
+<td>WXGA800-7in</td>
+</tr>
+<tr>
+<td><span style="white-space:nowrap">10-inch</span> tablet</td>
+<td><span style="white-space:nowrap"><code>xlarge</code> or</span><br /><code>-sw800</code></td>
+<td><code>mdpi</code>,<br /><code>hdpi</code>,<br /><code>xhdpi</code></td>
+<td>Android 3.2+ (API level 13 and higher)</td>
+<td>WXGA800</td>
+</tr>
+</table>
+
+<div class="headerLine clearfloat"><h1 id="related-resources">Related Resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/essentials/tabletguidelines"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/about.jd b/docs/html/distribute/googleplay/about.jd
new file mode 100644
index 0000000..cf0c6d2
--- /dev/null
+++ b/docs/html/distribute/googleplay/about.jd
@@ -0,0 +1,369 @@
+page.title=The Google Play Opportunity
+meta.tags="visibility, growth, distributing"
+page.tags="play, apps, distributing, publishing"
+page.metaDescription=Billons of downloads a month and growing. Get your apps in front of users at Google's scale.
+page.image=/distribute/images/about-play.jpg
+
+@jd:body
+
+ <div id="qv-wrapper">
+ <div id="qv">
+ <h2>About Google Play</h2>
+ <ol style="list-style-type:none;">
+ <li><a href="#reach">Worldwide Reach, Rapid Growth</a></li>
+ <li><a href="#ratings-reviews">User Ratings and Reviews</a></li>
+ <li><a href="#category-browsing">Category Browsing</a></li>
+ <li><a href="#search">Search</a></li>
+ <li><a href="#top-charts-and-lists">Top Charts and Lists</a></li>
+ <li><a href="#featured-staff-picks">Featured, Staff Picks, Collections, and Badges</a></li>
+ <li><a href="#product-detail-pages">Store Listing Pages</a></li>
+ <li><a href="#related-resources">Related Resources</a></li>
+ </ol>
+ </div>
+</div>
+
+<p>
+ Google Play is the premier store for distributing Android apps. When you
+ publish on Google Play, you put your apps in front of Android's huge base of
+ active customers, in more than 130 countries and territories across the
+ world.
+</p>
+
+<div>
+ <img src="{@docRoot}images/gp-about-0.jpg" alt="Google Play on an Android Tablet"
+ style="width:480px;position:relative" />
+</div>
+
+<p>
+ Google Play is a central part of the Android experience. New users
+ personalize their devices with apps, games, and other Google Play content.
+ Existing users return regularly to see what's trending and new. Downloading
+ new apps is extremely convenient and fast— Google Play pushes apps to
+ the user's devices instantly, over the air.
+</p>
+
+<p>
+ Google Play is also a top destination for web users. Anyone with a browser
+ can explore Google Play on the web. Android users can even buy and install
+ the apps they want and Google Play pushes them automatically to their devices
+ with no cables required.
+</p>
+
+<p>
+ The accessibility and convenience of the Google Play web site give you new
+ ways to drive traffic to your products from many sources, such as online ads,
+ web search and cross-linking. Google Play is designed to connect users with
+ great apps and games. It provides key channels to get your app noticed and
+ gain traction in the marketplace.
+</p>
+
+<div class="headerLine">
+ <h1 id="ratings-reviews">
+ User Ratings and Reviews
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Prospective users look at ratings and reviews as key benchmarks of app
+ quality. By rating apps from one to five stars and posting reviews, Android
+ users show their appreciation for the apps they have downloaded.
+</p>
+
+<p>
+ <strong>Your app's rating is one of the most important factors influencing
+ its ranking</strong> in the Google Play lists and search results. It's also
+ one of the key metrics that the editorial staff looks for when curating apps
+ and games for promotion in the store.
+</p>
+
+<div class="img" style="padding: 1em auto;width:96%;">
+ <img src="{@docRoot}images/gp-rating-web.png" style="border:1px solid #ddd;">
+</div>
+
+<div class="headerLine">
+ <h1 id="category-browsing">
+ Category Browsing
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ When you publish an app in Google Play, you pick the category where you want
+ users to find your app. More than 30 categories are available. Inside each
+ category, apps are ranked based on a combination of ratings, reviews,
+ downloads, country, and other factors.
+</p>
+
+<div class="headerLine">
+ <h1 id="search">
+ Search
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Search on Google Play lets users pinpoint an app or game quickly. Search uses
+ powerful heuristics to suggest terms as the user types, and it offers direct
+ links to apps as suggestions. In results, users find the most relevant, most
+ popular apps at the top.
+</p>
+
+<div class="headerLine">
+ <h1 id="top-charts-and-lists">
+ Top Charts and Lists
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-about-top.jpg">
+</div>
+
+<p>
+ Top charts keep users in touch with what’s popular and trending with Android
+ users, right from the Apps and Games home pages. The charts stay fresh,
+ updating several times each day based on recent download activity. As an
+ app's ratings and download activity grow, it can move up in the charts.
+</p>
+
+<p>
+ To make the charts as relevant as possible for users across the world, they
+ are also country-specific in Google Play's most popular countries. As your
+ apps get traction and build momentum in downloads and ratings, they’ll climb
+ one or more of the top charts and gain even more exposure.
+</p>
+
+<table style="width:50%;">
+ <tr>
+ <td>
+ Top Free
+ </td>
+ <td>
+ Free apps and free games lists
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ Top Paid
+ </td>
+ <td>
+ Paid apps and paid games lists
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ Top Grossing
+ </td>
+ <td>
+ Gross proceeds, free or paid
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ Top New Free
+ </td>
+ <td>
+ Less than 30 days old
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ Top New Paid
+ </td>
+ <td>
+ Less than 30 days old
+ </td>
+ </tr>
+
+ <tr>
+ <td>
+ Trending
+ </td>
+ <td>
+ New arrivals growing quickly in installs
+ </td>
+ </tr>
+</table>
+
+<div class="headerLine">
+ <h1 id="featured-staff-picks">
+ Featured, Staff Picks, Collections, and Badges
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ The Google Play editorial team is dedicated to bringing the best apps to the
+ attention of users and setting the tone for app quality throughout the store.
+ It constantly reviews apps from across Google Play to find not only the
+ best-known apps and games, but also the "diamonds in the rough" that they
+ want more people to see. The team promotes great apps in the
+ <em>Featured</em>, <em>Staff Picks</em>, and other collections.
+</p>
+
+<p>
+ You can't nominate your app for featuring, but the team is always monitoring
+ Google Play for great apps. If you build an app that users love and that
+ looks great on Android devices, the editorial team will notice.
+</p>
+
+<h3 id="featured-staff-picks2">
+ Featured and Staff Picks
+</h3>
+
+<p>
+ Each week the Google Play editorial staff selects a new set of apps to
+ promote in its popular <em>Featured</em> and <em>Staff Picks</em>
+ collections.
+</p>
+
+<p>
+ The <em>Featured</em> collections highlight the latest and greatest app and
+ game titles available for Android. The list also includes the best and most
+ popular apps in the top categories are also featured. <em>Staff Picks</em>
+ collects all recently featured apps and games on Google Play. To focus on
+ tablet users, A special <em>Staff Picks</em> collection highlights the best
+ apps for Android tablets.
+</p>
+
+<table style="text-align:center;margin:1.5em 0;">
+ <tr>
+ <td style="border:none;">
+ <img src="{@docRoot}images/gp-about-picks1.jpg">
+ <p>
+ Featured
+ </p>
+ </td>
+ <td style="border:none;">
+ <img src="{@docRoot}images/gp-about-picks2.jpg">
+ <p>
+ Collection
+ </p>
+ </td>
+ <td style="border:none;">
+ <img src="{@docRoot}images/gp-about-picks3.jpg">
+ <p>
+ Editors' Choice
+ </p>
+ </td>
+ </tr>
+</table>
+
+<h3 id="collections">
+ App collections
+</h3>
+
+<p>
+ From time to time the editorial staff puts together a collection of apps and
+ games based on a theme or seasonal event. Users frequently use these lists to
+ select apps, attracted by the timeliness of the collection.
+</p>
+
+<p>
+ The editorial staff chooses apps for collection promotions —
+ high-quality apps that show the best of Android on phones and tablets. The
+ staff also looks for apps that can make an interesting or unique contribution
+ to the collection as a whole.
+</p>
+
+<h3 id="editors-choice">
+ <img style="margin-right:.25em;margin-bottom:.5em;" src=
+ "{@docRoot}images/editorschoice_ann.png"> Editors' Choice
+</h3>
+
+<p>
+ <em>Editors’ Choice</em> is a curated collection of apps that highlights some
+ of the very best apps available on Android. Editors choose these apps for
+ quality and great user interface, long-term popularity and innovative use of
+ Android features.
+</p>
+
+<p>
+ Apps chosen for <em>Editors’ Choice</em> also receive a badge that is
+ displayed wherever the app name is seen in Google Play.
+</p>
+
+<h3 id="top-developer">
+ <img style="margin-right:.25em;margin-bottom:.5em;" src=
+ "{@docRoot}images/topdev_ann.png"> Top Developer
+</h3>
+
+<p>
+ Top Developer is a badge recognizing established, respected developers for
+ their commitment to launching high-quality and innovative apps on Android.
+ The Google Play editorial staff awards a Top Developer badge from
+ time-to-time based on the cumulative work of the developer.
+</p>
+
+<p>
+ The Top Developer badge appears next to the developer name wherever it is
+ displayed in Google Play. The badge means long-term recognition of all of the
+ developer’s apps. It signifies an additional level of trust and confidence
+ users have in a developer’s products.
+</p>
+
+<div class="headerLine">
+ <h1 id="product-detail-pages">
+ Store Listing Pages
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-about-listing.jpg">
+</div>
+
+<p>
+ Your app’s Google Play storefront is its <em>store listing page</em>: a rich
+ and colorful page that lets you promote your app, highlight its ratings and
+ reviews, and show what your app can do.
+</p>
+
+<p>
+ Your store listing is where your users come to find out everything about your
+ app. When they see your app listed in search results, top charts, category
+ listings, and collections, one tap takes them directly to your store listing.
+</p>
+
+<p>
+ Manage your product details page through the <a href=
+ "https://play.google.com/apps/publish/">Google Play Developer Console</a>
+ from any web browser. Sign in to upload or update your brand assets, and
+ enter your product details in the languages of your markets.
+</p>
+
+<p>
+ When you publish, Google Play adds your app’s ratings, reviews, links to your
+ other products, and more. It also makes sure your store listing page looks
+ great on phones, tablets, and in a web browser.
+</p>
+
+<p>
+ You can link web users directly to your product details page from outside
+ Google Play, such as from your web site, an ad campaign, reviews, social
+ media posts, and more. See <a href=
+ "{@docRoot}distribute/tools/promote/linking.html">Linking to Your
+ Products</a> to find out how.
+</p>
+
+<div class="headerLine clearfloat">
+<h1>Related Resources</h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/googleplay"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="4"></div>
+ </div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/about/distribution.jd b/docs/html/distribute/googleplay/about/distribution.jd
deleted file mode 100644
index 8020110..0000000
--- a/docs/html/distribute/googleplay/about/distribution.jd
+++ /dev/null
@@ -1,167 +0,0 @@
-page.title=Distribution Control
-page.metaDescription=Reach the users you want, whenever you want.
-
-@jd:body
-
-<p>Deliver your apps to the users you want, on the devices you want, on <em>your</em> schedule. </p>
-
-<h2 id="instant">Instant publishing, instant updates</h2>
-
-<p>On Google Play, you can publish your products to customers instantly. Just
-upload and configure your product in the <span style="font-weight:500;">Google Play Developer Console</span>
-and press the Publish button—your app appears in the store listings within
-hours, not weeks.</p>
-
-<p>Once your app is published, you can update it as often as you want. You can
-change prices, configuration, and distribution options at any time through the
-Google Play Developer Console, without needing to update your app
-binary.</p>
-
-<p>Later, as you add features or address code issues, you can publish an updated
-binary at any time. Google Play makes the new version available almost immediately and
-notifies existing customers that an update is ready for download. To streamline
-the rollout across your customer base, Google Play also lets users accept
-automatic updates of your app, so that your updates are delivered and installed
-as soon as you publish them.</p>
-
-
-<h2 id="targeting">Reaching the customers you want</h2>
-
-<div class="figure-right" style="width:400px;">
-<img src="{@docRoot}images/gp-dc-countries.png" class="frame">
-</div>
-
-<p>Google Play does more than connect your app with users—it helps you
-reach the broadest possible distribution across the Android ecosystem, while
-making sure that your app is only available to the audience that you want to
-reach.</p>
-
-<h3 id="geotargeting">Geographic targeting</h3>
-
-<p>You can use controls in the Google Play Developer Console to easily
-manage the geographic distribution of your apps, without any changes in your
-application binary. You can specify which countries and territories you want to
-distribute to, and even which carriers (for some countries). </p>
-
-<p>When users visit the store, Google Play makes sure that they are in one of
-your targeted countries before downloading your app. You can change your country
-and carrier targeting at any time just by saving changes in the Google Play
-Developer Console.</p>
-
-<div class="figure-right" style="width:400px;">
-<img src="{@docRoot}images/gp-supported-dev-requirements.png" class="frame">
-</div>
-
-<p>To help you market to users around the world, you
-can <a href="{@docRoot}distribute/googleplay/publish/preparing.html#localize">localize
-your store listing</a>, including app details and description,
-promotional graphics, screenshots, and more.</p>
-
-<h3 id="captargeting">Capabilities targeting</h3>
-
-<p>Google Play also lets you control distribution according to device features
-or capabilities that your app depends on. There are several types of
-dependencies that the app can define in its manifest, such as hardware features,
-OpenGL texture compression formats, libraries, Android platform versions, and
-others.</p>
-
-<p>When you upload your app, Google Play reads the dependencies and sets up any
-necessary distribution rules. For technical information about declaring
-dependencies, read <a href="{@docRoot}google/play/filters.html">Filters on
-Google Play</a>. </p>
-
-<p>For pinpoint control over distribution, Google Play lets you see all of the
-devices your app is available to based on its dependencies (if any). From the
-Google Play Developer Console, you can list the supported devices and
-even exclude specific devices if needed.</p>
-
-<h2 id="stats">Statistics for analyzing installs and ratings</h2>
-
-<p>Once you’ve published your app, Google Play makes it easy to see how it’s
-doing. The Google Play Developer Console gives you access to a variety
-of anonymized statistics and custom charts that show you the app's installation
-performance and ratings.</p>
-
-<p>You can view data and charts for active, daily, and total installs
-per unique devices or users, as well as upgrades and uninstalls.
-You can also view the app's daily average user rating and its cumulative
-user rating. To help you analyze the data, you can view install
-and ratings statistics across a variety of different dimensions such as Android
-version, device, country, app version, and carrier.</p>
-
-<div class="figure-left">
- <img src="{@docRoot}images/gp-dc-stats-mini.png" class="frame">
-</div>
-<p>You can see your app statistics on timeline charts, for
-all metrics and dimensions. At a glance, the charts highlight your app’s
-installation and ratings peaks and longer-term trends, which you can correlate
-to promotions, app improvements, or other factors. You can even focus in on
-data inside a dimension by highlighting specific data points (such as
-individual platform versions or languages) on the timeline.</p>
-
-<p>So that you can “take your data with you”, you can download all of your
-installation data as a CSV file for viewing in the business program of your
-choice.</p>
-
-
-<h2 id="advanced">Advanced delivery options</h2>
-
-<p>Google Play offers convenient options for managing how your apps are
-delivered to users.</p>
-
-<h3 id="abc">Alpha and beta testing, staged rollouts</h3>
-
-<p>It's always valuable to get real-world feedback from users, especially before
-launch. Google Play makes it easy to distribute pre-release versions of your app
-to alpha and beta test groups anywhere in the world. You can start with a small
-group of alpha testers, then move to a larger group of beta testers. Once users
-are added, they access your app's store listing and install the app. User
-feedback from alpha and beta testers goes directly to you and is not posted as
-public reviews. </p>
-
-<p>To help you ensure quality and protect your app ratings, you can choose a
-staged rollout when launching an app or an update. With staged rollout, you
-distribute the production version of your app to a percentage of users. You can
-adjust the percentage as you go, starting small and increasing until your app is
-available to all users.</p>
-
-<h3 id="multiple-apk">Multiple APK support</h3>
-
-<p>In most cases, it’s easy to create an app that supports all of your targeted
-screen sizes and platform versions from a single APK. Distributing a single APK
-to all of your users is a highly recommended approach, because it’s the easiest
-way to manage and maintain the app. If you need to deliver a different APK to
-devices, Google Play provides a way to do that. </p>
-
-<p>An option called Multiple APK support lets you create multiple APK packages
-that use the same package name but differ in their OpenGL texture compression
-formats, screen-size support, or Android platform versions supported. You can
-upload all of the APKs to Google Play under a single product listing and Google
-Play selects the best APK to deliver to users, based on the characteristics of
-their devices. </p>
-
-<p>The APK Expansion Files option lets you upload up to two secondary downloads
-for each published APK, including multiple APKs. Each of the two expansion files
-can be up to 2GB each and can contain any type of code or assets. When you
-upload the expansion files, Google Play hosts them for free and handles the
-download of the files as part of the normal APK installation.</p>
-
-<h2 id="licensing">Protecting your app</h2>
-
-<p>Google Play provides two key features to help you protect your application
-against piracy — Google Play Licensing and app encryption.</p>
-
-<p> Google Play Licensing is a network-based service that you implement in your
-app. The service lets your app query a trusted licensing server at runtime, to
-determine whether the app is licensed to the current device user. You can use
-the licensing service to protect any app, even apps that you distribute for
-free. For an overview of the service, see <a
-href="{@docRoot}google/play/licensing/index.html">Application
-Licensing</a>.</p>
-
-<p>Additionally, Google Play offers app encryption to help protect your priced
-apps. When delivering your priced apps to devices running Android 4.1 or higher,
-Google encrypts the app binary so that it can be run only by the user who
-downloaded it, on the device to which it was originally downloaded. Your priced
-apps benefit from app encryption automatically — there's no extra
-development work or configuration needed.</p>
diff --git a/docs/html/distribute/googleplay/about/monetizing.jd b/docs/html/distribute/googleplay/about/monetizing.jd
deleted file mode 100644
index 9a5c6d7..0000000
--- a/docs/html/distribute/googleplay/about/monetizing.jd
+++ /dev/null
@@ -1,162 +0,0 @@
-page.title=Flexible Monetizing and Business Tools
-page.metaDescription=
-
-@jd:body
-
-<div style="float:right;margin-left:18px;padding:1.5em;">
-<img src="{@docRoot}images/gp-details-ww.png" style="width:180px">
-<img src="{@docRoot}images/gp-details-ww-purchase.png" style="width:180px">
-</div>
-
-<p>Sell your app in more than 130 countries. Flexible monetization options with
-in-app purchase, subscriptions, and more. </p>
-
-<h2>Streamlined purchase flow for users</h2>
-
-<p>When users find your app, they can purchase it instantly with a streamlined,
-consistent purchasing process and convenient payment methods.</p>
-
-<h3>Instant purchase from device or web</h3>
-
-<p>Google Play makes it fast and easy for your customers to buy your products,
-whether from a phone, a tablet, or a desktop computer. When users find an app or
-game that they want to buy, they can purchase it in as few as two steps—one
-to initiate the purchase and another to accept purchase details and permissions
-and complete the transaction.</p>
-
-<p>Google Play's convenient purchase experience is the same familiar process for
-all products everywhere across Google Play—apps, games, in-app products and
-subscriptions, and other digital content.</p>
-
-<h3 id="cloud-connected-purchase">Cloud-connected</h3>
-
-<p>Purchasing is even more convenient on Google Play because it’s
-cloud-connected. Users can find and purchase your products from anywhere—from
-their Android phones or using any web browser on any host computer. </p>
-
-<p>When users find an app or game they want to buy, they purchase it and download
-it instantly to their devices over-the-air. Users who sign in to the Google Play web site can also buy apps and games
-and push them instantly to their phones, tablets, or other devices. Google Play
-manages the application download.</p>
-
-<h3 id="payment-methods">Convenient payment options</h3>
-
-<p>Users can purchase your products on Google Play using several convenient
-payment methods—credit cards, Direct Carrier Billing, gift cards, and Google Play balance.</p>
-
-<p><span style="font-weight:500">Credit card</span> is the most common method of payment. Users can pay using any credit card
-that they’ve registered in Google Play. To make it easy for users to get started,
-registration is offered as a part of initial device setup process.</p>
-
-<div class="sidebox-wrapper" style="float:right;">
-<div class="sidebox">
-<h2>Payment methods on Google Play</h2>
-<ul>
-<li>Credit card</li>
-<li>Direct Carrier Billing</li>
-<li>Gift card</li>
-<li>Google Play balance (stored value)</li>
-</ul>
-</div>
-</div>
-
-<p>Subscribers on many popular carrier networks worldwide can charge purchases
-to their monthly mobile phone bills through <span style="font-weight:500">Direct
-Carrier Billing</span>. This form of payment is convenient and simple and is
-extremely popular in regions where credit cards are less common. More than 75
-million users in key markets around the world can purchase
-your products through Direct Carrier Billing. Many more will get the option in
-the months ahead.</p>
-
-<p><span style="font-weight:500">Google Play balance</span> is a stored account
-balance in Google Play. Users can increase their balance through promotions and
-offers in the store, and they can use their balanace to make purchases of apps,
-games, or other content.
-
-<p>The payment methods available to users worldwide may vary, based on
-location, carrier network, and other factors.</p>
-
-<div style="float:left;margin-right:2em;margin-top:3em;margin-bottom:1em;width:220px;">
-<img src="{@docRoot}images/gp-subs.png" style="width:220px">
-</div>
-
-<h2 id="billing-models" style="margin-top:1.5em;">Choice of billing models</h2>
-
-<p>Google Play gives you a choice of billing models to let you monetize your
-products. </p>
-
-<p>You can offer apps to all users for free, or
-you can set an initial price for the app, paid before download. You can also
-sell one-time purchases and auto-renewing subscriptions from inside the app, and
-you can take advantage of AdMob integration to monetize your app through
-targeted advertising.</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Billing models on Google Play</h2>
-<ul>
-<li>Free (no charge to download)</li>
-<li>Priced (user charged before download)</li>
-<li>In-app products and subscriptions</li>
-</ul>
-</div>
-</div>
-
-<p>You can combine these billing models in different ways, based on your business
-needs or market conditions. </p>
-
-<p>For example, you can use a freemium or ad-supported model by distributing
-your app for free and selling in-app products or advertising. Alternatively you
-could set a nominal price for your app at download and sell value add-ons,
-gameplay levels, and upgrades as in-app products. The only restriction is that
-free apps must remain free (to download) for the life of the app.</p>
-
-<p>For details about in-app products or subscriptions,
-see <a href="{@docRoot}google/play/billing/index.html">Google Play In-app Billing</a>.</p>
-
-<h2 id="buyer-currency" style="margin-top:1.5em;">Flexible pricing in the currencies of your customers</h2>
-
-<div class="figure-right" style="width:250px;">
-<img src="{@docRoot}images/gp-buyer-currency.png" class="frame">
-</div>
-
-<p>Google Play gives you complete control over how you price your products. You
-can set prices in more than 130 countries, for millions of
-users around the world. When users browse your app’s product page or initiate a
-purchase, Google Play shows them the price they will be charged <em>in
-their local currency</em>.</p>
-
-<p>You can set and adjust your prices at any time, in any available currency.
-Your prices in available currencies are independent, so you can adjust one
-price without affecting others. This gives you the ability to run
-short-term promotions and discounts in specific countries and more easily
-manage shifts in exchange rates.</p>
-
-<p>You can set and manage prices for your apps and in-app products from the
-Google Play Developer Console.</p>
-
-<h2 id="payouts">Monthly payouts in your local currency</h2>
-
-<p>To sell products in Google Play, all you have to do is register for a Google
-Wallet merchant account and link it to your Google Play Android Developer
-Console account (see <a
-href="{@docRoot}distribute/googleplay/publish/register.html">Get Started with
-Publishing</a> for details). Once you’ve set up your account and published your
-apps, Google Play makes monthly payouts of sales proceeds to your merchant
-account, in your local currency.</p>
-
-<h2 id="reporting">Detailed financial reporting</h2>
-
-<p>When you sell priced apps or in-app products on Google Play, you get a
-variety of financial reports to help you track and project sales, optimize your
-marketing campaigns, and support your customers.</p>
-
-<p>To help you keep up-to-date with the current activity, you can download daily
-reports summarizing recent purchases of your products. The reports include
-estimated sales amounts and include a variety of other data for each
-transaction.</p>
-
-<p>At the close of the month, you can download a complete sales report that
-gives you the final details of all transactions that closed in the month,
-including the payout amounts and other data. Additional financial reports are
-available in your Google Wallet merchant account.</p>
diff --git a/docs/html/distribute/googleplay/about/visibility.jd b/docs/html/distribute/googleplay/about/visibility.jd
deleted file mode 100644
index 18f60e9..0000000
--- a/docs/html/distribute/googleplay/about/visibility.jd
+++ /dev/null
@@ -1,246 +0,0 @@
-page.title=Visibility for Your Apps
-page.metaDescription=
-
-@jd:body
-
-<div style="float:right;margin:0px 0px 24px 0px;">
- <img src="{@docRoot}images/gp-tab.png" style="width:420px" alt="" />
-</div>
-
-<p>A billion downloads a month and growing. Get your apps in front of millions
-of users at Google's scale. </p>
-
-
-<h2 id="reach">Worldwide reach, rapid growth</h2>
-
-<p>Google Play is the premier store for distributing Android apps. It’s
-preinstalled on more than 400 million devices worldwide, a number growing by
-more than a million every day. Android users have downloaded
-more than <strong style="text-wrap:none;">25 billion apps</strong> from Google
-Play, growing at a rate of more than 1.5 billion per month.</p>
-
-<p>When you publish on Google Play, you put your apps in front of Android's huge
-base of active customers, in more than 130 countries and territories across the
-world. </p>
-
-<p>Google Play is a central part of the Android experience. New users
-personalize their devices with apps, games, and other Google Play content.
-Existing users return regularly to see what's trending and new. Downloading new
-apps is extremely convenient and fast— Google Play pushes apps to the
-user's devices instantly, over the air. No cable or sync is ever needed.</p>
-
-<div style="float:left;margin:0px 20px 0px 0px;width:374px;">
-<div style="width:378px;padding:2px;">
-<img src="{@docRoot}images/gp-growth-downloads.png" style="width:600px;margin-bottom:0em;">
-</div>
-<p class="image-caption" style="padding:.5em"><span
-style="font-weight:500;">Growth in app consumption</span>: Users download more than
-1.5 billion apps from Google Play each month.</p>
-</div>
-
-<div>
-<p>Google Play is also a top destination for visitors from the web. Anyone
-with a browser can explore everything that Google Play has to offer from its <a
-href="http://play.google.com/store">web site</a>. Android users can even buy and
-install the apps they want and Google Play pushes them automatically to their
-devices over the air. </p>
-
-<p>The accessiblility and convenience of the Google Play web
-site give you new ways to drive traffic to your products from online ads, web
-search, cross-linking, and more.</p>
-</div>
-
- <div style="clear:both;">
-<h2>Built for app discovery</h2>
-
-<p>Google Play is designed to connect users with great apps and games. It
-provides key channels to help your app get noticed and gain traction in the
-marketplace.</p>
-
-<h3 id="ratings">User ratings and reviews</h3>
-
-<p>When you develop a great app, Android users show their appreciation through
-ratings and reviews. They rate your app (out of 5 stars) after downloading it
-and can post a short description of their experience. When other users are
-considering your app, they look at the ratings and reviews as key benchmarks of
-the app’s quality. </p>
-
- </div>
-
-<p>Your app’s rating is one of the most important factors influencing its
-ranking in the various lists and search results in Google Play. It's also one of
-the key signals that the editorial staff looks for, when curating apps and games
-for promotion in the store.</p>
-
-<div style="border:1px solid #DDD;padding:1px;margin-left:110px;width:504px;">
-<img src="{@docRoot}images/gp-rating-web.png" style="width:500px;padding:0;margin:0;">
-</div>
-
-<h3 id="category" stdle="padding-top:2em;">Category browsing</h3>
-
-<p>When you publish an app in Google Play, you pick the category in which you
-want users to find your app. More than 30 categories are available. Inside each
-category, apps are ranked based on a combination of ratings, reviews, downloads,
-country, and other factors. Many popular categories also start with a collection
-of featured apps selected by the Google Play editorial staff.</p>
-
-<div style="clear:both;margin-top:2em;margin-left:10%;width:560px;">
-<div style="clear:both;margin-top:2em;">
-<img src="{@docRoot}images/gpp-cat-feature280-puzzle.png" style="width:180px">
-<img src="{@docRoot}images/gpp-cat-feature280-photo.png" style="width:180px">
-<img src="{@docRoot}images/gpp-cat-feature280-sports.png" style="width:180px">
-</div>
-<p class="image-caption"><span style="font-weight:500;">Featuring in
-categories</span>: Most app and game categories include a featured list curated
-by the editorial team.</p>
-</div>
-
-<h3 id="search">Search</h3>
-
-<p>Search on Google Play lets users pinpoint an app or game quickly. Search uses
-powerful heuristics to suggest terms as the user types, and it offers direct
-links to apps as suggestions. In results, users find the most relevant, most
-popular apps at the top. </p>
-
-<div style="float:left;margin:12px 24px 0px 0px;">
-<img src="{@docRoot}images/gp-top-new-paid.png" style="width:250px">
-</div>
-
-<h3 id="top-charts" style="padding-top:1em">Top charts and lists</h3>
-
-<p>Top charts keep users in touch with what’s popular and trending with Android
-users, right from the Apps and Games home pages. The charts are generated
-several times each day based on recent download activity, keeping them fresh and
-allowing new apps to move upward in the charts. To make the charts as relevant
-as possible for users across the world, they are also country-specific in
-Google Play's most popular countries.</p>
-
-<p>As your apps get traction and build momentum in downloads and ratings,
-they’ll climb one or more of the top charts and gain even more exposure.</p>
-
-<div>
-<table style="width:440px">
-<tr>
-<td style="width:100px">Top Free</td><td>Free apps and games</td></tr>
-<td style="width:140px">Top Paid</td><td>Priced apps and games</td></tr>
-<td>Top New Free</td><td>Less than 30 days old</td></tr>
-<td>Top New Paid</td><td>Less than 30 days old</td></tr>
-<td>Top Grossing</td><td>Gross proceeds, free or priced</td></tr>
-<td>Best Selling</td><td>Popular priced games</td></tr>
-<td>Trending</td><td>New arrivals growing quickly in installs</td>
-</tr>
-</table>
-</div>
-
-<div style="clear:both">
-<h4 id="featured" style="padding-top:2.5em;">Featured, Staff Picks, Collections,
-and Badges</h4>
-
-
-<div style="float:right;margin-left:18px;">
-<img src="{@docRoot}images/gp-apps-home.png" style="width:180px">
-<img src="{@docRoot}images/gp-games-home.png" style="width:180px">
-</div>
-
-<p>The Google Play editorial team is dedicated to bringing the best apps to the
-attention of users and setting the tone for app quality throughout the store.
-It constantly reviews apps from across Google Play to find
-not only the best-known apps and games, but also the “diamonds in the rough” that
-they want more people to see. </p>
-
-<p>When the team finds great apps and games, it uses the <em>Featured</em>,
-<em>Staff Picks</em>, and other collections to promote them to users.</p>
-
-<p>You can't nominate your app for featuring, but the team is always
-on the lookout for great apps through a number of signals and indicators.
-If you build an app that users love and that looks great on Android devices,
-the editorial team will notice.</p>
-</div>
-
-<h4>Featured and Staff Picks</h4>
-
-<p>Each week the Google Play editorial staff selects a new set of apps to
-promote in its popular <em>Featured</em> and <em>Staff Picks</em> collections.
-</p>
-
-The <em>Featured</em> collections highlight the latest and greatest app and game
-titles available for Android. Category featuring highlights the best and most
-popular apps in the top categories.
-
-<em>Staff Picks</em> collects all recently featured apps and games on Google
-Play. To better reach tablet users, there’s a special <em>Staff Picks</em>
-collection that highlights the best apps for Android tablets.</p>
-
-<div style="float:left;margin-right:18px;">
-<img src="{@docRoot}images/gp-collectibles.png" stydle="width:180px">
-
-</div>
-
-<h4>App collections</h4>
-
-<p>From time to time the editorial staff puts together a collection of apps and
-games based on a theme or seasonal event. The collections are popular with
-customers because they are timely and relevant, and they provide a new way to
-showcase great Android apps to users.</p>
-
-<p>The editorial staff chooses apps for collection promotions in a similar way
-as for featuring—high-quality apps that show the best of Android on phones
-and tablets. For collections the staff also looks for apps that can make an
-interesting or unique contribution to the collection as a whole. </p>
-
-<h4><img style="margin-right:.25em;margin-bottom:.5em;"
-src="{@docRoot}images/editorschoice_ann.png"> EDITORS' CHOICE</h4>
-
-<p><em>Editors’ Choice</em> is a curated collection of apps that highlights some
-of the very best apps available on Android. These apps are chosen for high
-quality and great UI, long-term popularity, and innovative use of Android
-features.</p>
-
-<p>Apps chosen for <em>Editors’ Choice</em> also receive a badge that is
-displayed wherever the app name is seen in Google Play.</p>
-
-<h4><img style="margin-right:.25em;margin-bottom:.5em;"
-src="{@docRoot}images/topdev_ann.png"> TOP DEVELOPER</h4>
-
-<p>Top Developer is a badge recognizing established, respected developers for
-their commitment to launching high-quality and innovative apps on
-Android. The Google Play editorial staff selects developers awards a Top
-Developer badge from time to time, based on the cumulative work of the
-developer.</p>
-
-<p>The Top Developer badge appears next to the developer name wherever it is
-displayed in Google Play. For a developer, the badge means long-term recognition
-of all of your apps. For users, the badge signifies an additional level of trust
-and confidence in your products.</p>
-
-<h3 id="details">Rich, colorful product pages</h3>
-
-<p>In Google Play, your app’s storefront is its <em>product details page</em>
-— a rich and colorful page that lets you promote your app, highlight its
-ratings and reviews, and show what your app can do.
-
-<p>Your product details page is the one page where your users come to find out
-everything about your app. When they see your app listed in search results, top
-charts, category listings, and collections, one tap takes them directly to your
-product details page.</p>
-
-<div style="float:right;margin-left:10px;">
-<img src="{@docRoot}images/gp-details-pages-magicpiano.png" style="width:500px">
-</div>
-
-<p>You can manage your product details page through the <span
-style="font-weight:500">Google Play Android Develeper Console</span>, from any
-web browser. Just sign in, upload or update your brand assets, and enter your
-product details in the languages of your markets. </p>
-
-<p>When you publish, Google Play adds your app’s ratings, reviews, links to your
-other products, and more, and makes sure your product details page looks great
-on phones, tablets, or in a web browser.</p>
-
-<p>You can link web users directly to your product details page from outside
-Google Play, such as from your web site, an ad campaign, reviews, social media
-posts, and more. See <a href="{@docRoot}distribute/googleplay/promote/linking.html">Linking
-to Your Products</a> to find out how. </p>
-
-<p>To learn more about how to create your product details page, see
-<a href="{@docRoot}distribute/googleplay/publish/index.html">Publishing on Google Play</a>.</p>
diff --git a/docs/html/distribute/googleplay/developer-console.jd b/docs/html/distribute/googleplay/developer-console.jd
new file mode 100644
index 0000000..6263431
--- /dev/null
+++ b/docs/html/distribute/googleplay/developer-console.jd
@@ -0,0 +1,600 @@
+page.title=Developer Console
+page.metaDescription=Learn about the Developer Console, your home for app publishing on Google Play.
+page.image=/distribute/images/developer-console.jpg
+Xnonavpage=true
+
+@jd:body
+
+ <div id="qv-wrapper">
+ <div id="qv">
+ <h2>Publishing Features</h2>
+ <ol>
+ <li><a href="#allapps">All Applications</a></li>
+ <li><a href="#account-details">Your Account Details</a></li>
+ <li><a href="#merchant-account">Linking Your Merchant Account</a></li>
+ <li><a href="#multiple-user-accounts">Multiple User Accounts</a></li>
+ <li><a href="#alpha-beta">Alpha and Beta Testing</a></li>
+ <li><a href="#staged-rollouts">Staged Rollouts</a></li>
+ <li><a href="#multiple-apk">Multiple APK Support</a></li>
+ <li><a href="#selling-pricing-your-products">Selling and Pricing</a></li>
+ <li><a href="#in-app-products">In-App Products</a></li>
+ <li><a href="#distribution-controls">Distribution Controls</a></li>
+ <li><a href="#reviews-reports">User Reviews, Crash Reports</a></li>
+ <li><a href="#app-stats">App Stats</a></li>
+ <li><a href="#related-resources">Related Resources</a></li>
+ </ol>
+ </div>
+</div>
+
+<p>
+ The <a href="https://play.google.com/apps/publish/">Google Play Developer
+ Console</a> is your home for publishing operations and tools.
+</p>
+<!-- <img src="{@docRoot}images/gp-dc-startscreen.jpg" style="width:480px;" /> -->
+<img src="{@docRoot}images/gp-devconsole-home.png" style="width:480px;">
+<p>
+ Upload apps, build your product pages, configure prices and distribution, and
+ publish. You can manage all phases of publishing on Google Play through the
+ Developer Console, from any web browser.
+</p>
+
+<p>
+ Once you've <a href=
+ "{@docRoot}distribute/googleplay/start.html">registered</a> and received
+ verification by email, you can sign in to your Google Play Developer Console.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="allapps">
+ All Applications
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Start in All Applications, which gives you a quick overview of your apps,
+ lets you jump to stats, reviews, and product details, or upload a new app.
+</p>
+
+<div style="padding:1em 0em 0em 0em;">
+ <img src="{@docRoot}images/gp-dc-home.png" class="border-img">
+</div>
+
+<div class="headerLine clearfloat" style="margin-top:-6px">
+ <h1 id="account-details">
+ Your Account Details
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Specify basic developer profile information about yourself or your company on
+ the accounts detail page. This identifies you to Google Play and your
+ customers. You can go back at any time to edit the information and change
+ your settings.
+</p>
+
+<div>
+ <img src="{@docRoot}images/gp-dc-profile.png" class="frame">
+</div>
+
+<p>
+ Your developer profile contains:
+</p>
+
+<ul>
+ <li>
+ <p>
+ Developer name — displayed on your store listing page and elsewhere
+ on Google Play.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Contact information — used by Google only, it isn't seen by your
+ customers.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Web site URL — displayed on your store listing page.
+ </p>
+ </li>
+</ul>
+
+<p>
+ On the account details page you can also add restricted access for marketers
+ and other teams, register for a merchant account, or set up test accounts for
+ Google Play licensing.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="merchant-account">
+ Linking Your Merchant Account
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ If you want to sell apps or in-app products, link your Google Wallet Merchant
+ Account to your developer profile. Google Play uses the linked merchant
+ account for financial and tax identification, as well as for monthly payouts
+ from sales.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="multiple-user-accounts">
+ Multiple User Accounts
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Set up user accounts for other team members to access different parts of your
+ Developer Console.
+</p>
+
+<div style="width:550px;">
+ <img src="{@docRoot}images/gp-dc-invite.png" class="frame">
+</div>
+
+<p>
+ The first account registered is the <em>account owner</em>, with full access
+ to all parts of the console. The owner can add <em>user accounts</em> and
+ manage console access.
+</p>
+
+<p>
+ For example, an owner can grant users access to publishing and app
+ configuration, but not to financial reports. Learn how to <a href=
+ "https://support.google.com/googleplay/android-developer/answer/2528691">set
+ up multiple accounts</a> now.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="store-listing-details">
+ Store Listing Details
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Use the Developer Console to set up a <em>Store Listing page</em>. This is
+ the home for your app in Google Play. It's the page users see on their mobile
+ phones or on the web to learn about your app and download it.
+</p>
+
+<p>
+ Upload custom brand assets, screenshots, and videos to highlight what's great
+ about your app. Provide a localized description, add notes about the latest
+ version, and more. You can update your store listing at any time.
+</p>
+
+<div>
+ <img src="{@docRoot}images/gp-dc-details.png" class="frame">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="upload-instantly-publish">
+ Upload and Instantly Publish
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ From the Developer Console you can quickly upload and publish a release-ready
+ Android application package file. The app is a <em>draft</em> until you
+ publish it, at which time Google Play makes your store listing page and app
+ available to users—your app appears in the store listings within hours,
+ not weeks.
+</p>
+
+<p>
+ Once your app is published, you can update it as often as you want: Change
+ prices, configuration, and distribution options at any time, without needing
+ to update your app binary.
+</p>
+
+<p>
+ As you add features or address code issues, you can publish an updated binary
+ at any time. The new version is available almost immediately and existing
+ customers are notified that an update is ready for download. Users can also
+ accept automatic updates to your app, so that your updates are delivered and
+ installed as soon as you publish them. You can unpublish your apps app at any
+ time.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="alpha-beta">
+ Alpha and Beta Testing
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ It's always valuable to get real-world feedback from users, especially before
+ launch. Google Play makes it easy to distribute pre-release versions of your
+ app to alpha and beta test groups anywhere in the world.
+</p>
+
+<p>
+ In the <strong>APK</strong> section of your Google Play Developer Console
+ you’ll find the <strong>Alpha Testing</strong> and <strong>Beta
+ Testing</strong> tabs. Here you can upload versions of your apps’ APK files
+ and define a list of testers as a <a href=
+ "https://support.google.com/groups/answer/46601">Google Group</a> or <a href=
+ "https://support.google.com/plus/topic/2888488">Google+ Community</a>. Once
+ this is done you’ll receive a URL that you forward to your testers, from
+ which they can opt-in to the testing program.
+</p>
+
+<div>
+ <img src="{@docRoot}images/gp-dc-ab.png" class="frame">
+</div>
+
+<p>
+ After opting-in, your testers then go to your app’s product page and when
+ they download the app Google Play will deliver them the alpha or beta version
+ as appropriate. Incidentally, if a user happens to be opted-in to both your
+ testing groups, Google Play will always deliver them the alpha test version.
+</p>
+
+<p>
+ Note that users cannot provide feedback and reviews on alpha and beta
+ versions of your apps. To gather feedback you could used the <a href=
+ "https://support.google.com/groups/answer/46601">Google Group</a> or <a href=
+ "https://support.google.com/plus/topic/2888488">Google+ Community</a>, or
+ setup an email address or your own website.
+</p>
+
+<p>
+ You can use these testing programs to <a href=
+ "{@docRoot}distribute/essentials/optimizing-your-app.html">optimize your
+ apps</a>, help with <a href=
+ "{@docRoot}distribute/users/expand-to-new-markets.html">rollout to new
+ markets</a>, and start <a href=
+ "{@docRoot}distribute/users/build-community.html">building your
+ community</a>. There is also more information on using beta test in the
+ <a href="{@docRoot}distribute/tools/launch-checklist.html">Launch
+ Checklist</a> and <a href=
+ "{@docRoot}distribute/tools/localization-checklist.html">Localization
+ Checklist</a>.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="staged-rollouts">
+ Staged Rollouts
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ You can also stage the rollout of your apps using the Production tab in the
+ APK section of your Google Play Developer Console. Here you can define the
+ percentage of user who’ll be able to download your app.
+</p>
+
+<p>
+ Staging your rollout will help limit the impact of unexpected bugs or server
+ load and enable you to gauge user feedback with an unbiased sample of users.
+ Users can rate and review your apps during staged roll outs, so if you’re
+ hesitant, start your rollout to a small percentage of users. Be sure to watch
+ for and respond to any negative reviews.
+</p>
+
+<p>
+ Note that rollbacks aren’t supported due to the <a href=
+ "{@docRoot}tools/publishing/versioning.html">app versioning requirements</a>
+ of the Android platform. If you need to rollback, consider launching a
+ previous APK with a new version number. However, this practice should be used
+ only as a last resort, as users will lose access to new features and your old
+ app may not be forward-compatible with your server changes or data formats,
+ so be sure to run <a href="#alpha-beta">alpha and beta tests</a> of your
+ updates.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="multiple-apk">
+ Multiple APK Support
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ In most cases, a single app package (APK) is all you need, and it’s usually
+ the easiest way to manage and maintain the app. However, if you need to
+ deliver a different APK to different devices, Google Play provides a way to
+ do that.
+</p>
+
+<p>
+ <em>Multiple APK support</em> lets you create multiple app packages that use
+ the same package name but differ in their OpenGL texture compression formats,
+ screen-size support, or Android platform versions supported. You can simply
+ upload all the APKs under a single product listing and Google Play selects
+ the best ones to deliver to users, based on the characteristics of their
+ devices.
+</p>
+
+<p>
+ You can also upload up to two secondary downloads for each published APK,
+ including multiple APKs, using the <em>APK Expansion Files</em> option. Each
+ expansion file can be up to 2GB and contain any type of code or assets.
+ Google Play hosts them for free and handles the download of the files as part
+ of the normal app installation.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="selling-pricing-your-products">
+ Selling and Pricing Your Products
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure-right">
+ <img src="{@docRoot}images/gp-buyer-currency.png" class="frame">
+</div>
+
+<p>
+ You have tools to set prices for your apps and in-app products. Your app can
+ be free to download or priced, requiring payment before download.
+</p>
+
+<ul>
+ <li>If you publish your app as free, it must <strong>remain free for the life
+ of the app</strong>. Free apps can be downloaded by all users in Google Play.
+ </li>
+
+ <li>If you publish it as priced, you can later change it to free. Priced apps
+ can be purchased and downloaded only by users who have registered a form of
+ payment in Google Play.
+ </li>
+</ul>
+
+<div class="sidebox-wrapper" style="float:right;">
+ <div class="sidebox">
+ <p>
+ See <a href=
+ "http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294&topic=2365624&ctx=topic">
+ Supported locations for distributing applications</a> for a list of
+ countries where you can distribute or sell your apps.
+ </p>
+ </div>
+</div>
+
+<p>
+ You can also offer in-app products and subscriptions, whether the app is free
+ or priced. Set prices separately for priced apps, in-app products, and
+ subscriptions.
+</p>
+
+<p>
+ When users browse your app product pages or initiate a purchase, Google Play
+ shows them the price they’ll be charged in their local currency.
+</p>
+
+<p>
+ For each product, you initially set a default price in your own currency. If
+ you do no more, Google Play will automatically set local prices once a month
+ based on the US-Dollar price for your app.
+</p>
+
+<p>
+ However, Google Play gives you complete control over how you price your
+ products in each country. To start you can manually set fixed local prices
+ from the default price, using the <strong>auto-convert prices now</strong>
+ feature. You can then review these prices and set new ones for any countries
+ you wish — the price for each country is independent, so you can adjust
+ one price without affecting others. For most countries, the price you set is
+ the final price charged to users, including taxes.
+</p>
+
+<p>
+ For more on pricing your apps, see <a href=
+ "{@docRoot}distribute/users/expand-to-new-markets.html#localize-your-google-play-listing">
+ Expand into New Markets</a>.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="in-app-products">
+ In-app Products
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ You can sell in-app products and subscriptions using <a href=
+ "{@docRoot}google/play/billing/index.html">Google Play In-app Billing</a> as
+ a way to monetize your apps. In-app products are one-time purchases, while
+ subscriptions are recurring charges on a monthly or annual basis.
+</p>
+
+<p>
+ In the <strong>In-app Products</strong> section for a specific published or
+ draft APK you:
+</p>
+
+<ul>
+ <li>Create product lists for in-app products and subscriptions.
+ </li>
+
+ <li>Set prices.
+ </li>
+
+ <li>Publish the products with the app or withdraw obsolete products.
+ </li>
+</ul>
+
+<p>
+ For details on how to implement In-app Billing, see the <a href=
+ "{@docRoot}google/play/billing/index.html">In-app Billing</a> developer
+ documentation. You make use of in-app products in the <a href=
+ "{@docRoot}distribute/monetize/premium.html">Premium</a>, <a href=
+ "{@docRoot}distribute/monetize/freemium.html">Freemium</a>, and <a href=
+ "{@docRoot}distribute/monetize/subscriptions.html">Subscription</a>
+ monetization models
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="distribution-controls">
+ Distribution Controls
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Manage which countries and territories your apps will distribute to. For some
+ countries, you can choose which carriers you want to target. You can also see
+ the list of devices your app is available for, based on any distribution
+ rules declared in its manifest file.
+</p>
+
+<h3 id="geotargeting">
+ Geographic targeting
+</h3>
+
+<p>
+ You can use controls in the Google Play Developer Console to easily manage
+ the geographic distribution of your apps, without any changes in your
+ application binary. You can specify which countries and territories you want
+ to distribute to, and even which carriers (for some countries).
+</p>
+
+<p>
+ When users visit the store, Google Play makes sure that they are in one of
+ your targeted countries before downloading your app. You can change your
+ country and carrier targeting at any time just by saving changes in the
+ Google Play Developer Console.
+</p>
+
+<div class="figure-right" style="width:500px;">
+ <img src="{@docRoot}images/gp-supported-dev-requirements.png" class="frame">
+</div>
+
+<p>
+ To help you market to users around the world, you can <a href=
+ "{@docRoot}distribute/tools/launch-checklist.html#start-localization">localize
+ your store listing</a>, including app details and description, promotional
+ graphics, screenshots, and more.
+</p>
+
+<h3 id="captargeting">
+ Capabilities targeting
+</h3>
+
+<p>
+ Google Play also lets you control distribution according to device features
+ or capabilities that your app depends on. There are several types of
+ dependencies that the app can define in its manifest, such as hardware
+ features, OpenGL texture compression formats, libraries, Android platform
+ versions, and others.
+</p>
+
+<p>
+ When you upload your app, Google Play reads the dependencies and sets up any
+ necessary distribution rules. For technical information about declaring
+ dependencies, read <a href="{@docRoot}google/play/filters.html">Filters on
+ Google Play</a>.
+</p>
+
+<p>
+ For pinpoint control over distribution, Google Play lets you see all of the
+ devices your app is available to based on its dependencies (if any). From the
+ Google Play Developer Console, you can list the supported devices and even
+ exclude specific devices if needed.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="reviews-reports">
+ User Reviews and Crash Reports
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure-right" style="width:500px;">
+ <img src="{@docRoot}images/gp-dc-reviews.png" class="frame">
+ <p class="img-caption">
+ The User reviews section gives you access to user reviews for a specific
+ app. You can filter reviews in a number of ways to locate issues more
+ easily and support your customers more effectively.
+ </p>
+</div>
+
+<p>
+ Google Play makes it easy for users to submit reviews of your app for the
+ benefit of other users. The reviews give you usability feedback, support
+ requests, and details of important functionality issues direct from your
+ customers.
+</p>
+
+<p>
+ Use crash reports for debugging and improving your app. You can see crash
+ reports with stack trace and other data, submitted automatically from Android
+ devices.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="app-stats">
+ App Statistics
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure" style="width:500px">
+ <img src="{@docRoot}images/gp-dc-stats.png">
+ <p class="img-caption">
+ <b>App statistics page</b>: Shows you a variety of statistics about a
+ specific app's installation performance.
+ </p>
+</div>
+
+<p>
+ You get detailed statistics on the install performance of your app.
+</p>
+
+<p>
+ See installation metrics measured by unique users as well as by unique
+ devices. View active installs, total installs, upgrades, daily installs and
+ uninstalls, and metrics about ratings.
+</p>
+
+<p>
+ Zoom into the installation numbers by metric, including Android platform
+ version, device, country, language, app version, and carrier. View the
+ installation data for each dimension on timeline charts.
+</p>
+
+<p>
+ These charts highlight your app’s installation peaks and longer-term trends.
+ They help you learn your user’s adoption behavior, correlate statistics to
+ promotions, see the effect of app improvements, and other factors. Focus in
+ on data inside a dimension by adding specific points to the timeline.
+</p>
+
+<div class="dynamic-grid">
+<div class="headerLine clearfloat">
+<h1 id="related-resources">Related Resources</h1><hr/>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/googleplay/developerconsole"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="6"></div>
+ </div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/edu/about.jd b/docs/html/distribute/googleplay/edu/about.jd
index 20a0d4d..3944909 100644
--- a/docs/html/distribute/googleplay/edu/about.jd
+++ b/docs/html/distribute/googleplay/edu/about.jd
@@ -1,103 +1,131 @@
-page.title=About Google Play for Education
-page.metaDescription=How Google Play for Education helps you reach a new audience of educators.
-excludeFromSuggestions=true
+page.title=Google Play for Education
+page.image=/distribute/images/about-play-education.jpg
+page.metaDescription=Distribute your educational app directly to educators and schools.
+meta.tags="gpfe, googleplay, distribution, edu"
+page.tags="education"
+Xnonavpage=true
+
@jd:body
- <div style="position:absolute;margin-left: 636px;
- margin-top:-76px;color:#777;">If you're interested<br>
- <a href="{@docRoot}distribute/googleplay/edu/contact.html"
- class="go-link"
- style="display: block;text-align: right;">SIGN UP</a></div>
+<p>
+ Google Play for Education is an extension of Google Play designed for
+ schools. Here educators can discover apps approved by teachers for teachers,
+ as well as educational videos and a collection of classic books for their
+ classroom.
+</p>
- <div style="float:right;margin:0px 0px 24px 44px;">
- <img src="{@docRoot}images/gp-edu-apps-n7.jpg" style="width:420px" alt="" />
-</div>
+<p>
+ Teachers can search for approved apps by grade, subject and standard,
+ including Common Core State Standards. They can bulk purchase and pay using a
+ purchase order, then instant distribution let educators bring your apps
+ directly to classrooms and schools.
+</p>
-<p>Introducing Google Play for Education, the online destination where schools
-can find the right tablet content and tools for their students and teachers.</p>
-<p>With easy bulk ordering for groups, schools can purchase and
-instantly distribute your apps, and videos right to their students’
-devices.</p>
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/googleplay/gpfe/highlight"
+ data-sortOrder="-timestamp"
+ data-cardSizes="18x6,"
+ data-maxResults="1"></div>
-<p>Google Play for Education can help your innovative educational apps
-gain visibility with the right audiences, without having to knock on school doors. </p>
-<p><a class="landing-page-link" style="text-align:right;" href="#video">Watch a Video</a></p>
+<!-- <div class="center-img"><img src="{@docRoot}images/gp-edu-hero14.jpg" class="" /></div> -->
-<div class="landing-docs">
- <div class="col-6 normal-links">
- <h3 style="clear:left">For Developers</h3>
+<p>
+ If you have an educational app, include it in Google Play for Education.
+ Google Play for Education can help your innovative educational apps gain
+ visibility with the right audiences, without having to knock on school doors.
+</p>
-<h4>Get discovered</h4>
+<div style="margin:30px 0 20px 0;" class="clearfloat dynamic-grid">
+ <div style="width:48%; margin-right:2%; float:left;">
+ <div class="centered-full-image">
+ <img src="{@docRoot}images/gpfe-developer.png">
+ </div>
-<p>With Google Play for Education, teachers and administrators can
-browse content by curriculum, grade, and standard — discovering the right
-content for their students. If your app offers an exciting new
-way to learn sixth grade algebra, math educators will be able to find,
-purchase, and distribute your app to their classes in a few clicks.</p>
-
-<h4>Reach more schools and students</h4>
-
-<p>Over 30 million students, faculty, and staff are already using
-Google Apps for Education and other Google services. Many of these schools are
-excited to take advantage of tablets with Google Play for Education and they
-look to bringing your apps into their classrooms,
-especially apps using Google sign-on.</p>
-
-<h4>Monetize effectively</h4>
-<p>With Google Play for Education, educators are able to make high-volume purchases
-using standard institutional payment mechanisms and distribute them to the students
-they want — whether it is a class of 20 or a district of 20,000.</p>
-<code></code>
+ <h3>
+ FOR DEVELOPERS
+ </h3>
+ <b>Get discovered</b>
+ <p>
+ With Google Play for Education, teachers and administrators can browse
+ content by curriculum, grade, and standard — discovering the right
+ content for their students. If your app offers an exciting new way to
+ learn sixth grade algebra, math educators will be able to find, purchase,
+ and distribute your app to their classes in a few clicks.
+ </p>
+ <b>Reach more schools and students</b>
+ <p>
+ Millions of students, faculty, and staff are using Google Apps for
+ Education and other Google services. Many of these schools are excited to
+ take advantage of tablets with Google Play for Education and they are
+ looking to bring your apps into their classrooms, especially apps using
+ Google sign-on.
+ </p>
+ <b>Monetize effectively</b>
+ <p>
+ With Google Play for Education, educators are able to make high-volume
+ purchases using standard institutional payment mechanisms and then
+ distribute apps to the students who need them — whether it’s a class of
+ 20 or a district of 20,000.
+ </p>
</div>
- <div class="col-6 normal-links">
- <h3 style="clear:left">For Educators</h3>
- <h4>Android tablets in the classroom</h4>
- <p>Google Play for Education brings the innovation of Android technology
-into classrooms. School districts can set up and deploy large numbers of devices in
-just minutes or hours rather than days.</p>
+ <div style="width:48%; margin-left:2%; float:left;">
+ <div class="centered-full-image">
+ <img src="{@docRoot}images/gpfe-educator.png">
+ </div>
- <h4>Curriculum-based discovery</h4>
- <p>Powerful browsing tools let educators quickly discover apps,
-videos, and other content—with many recommended by teachers and
-categorized according to familiar Core Curriculum standards.
-
- <h4>Bulk purchase with institutional payment</h4>
- <p>Convenient purchasing and delivery tools let educators buy apps in bulk
-using purchase orders and other payment methods that are easy for schools to
-manage.</p>
-
- <h4>Over-the-air delivery to student devices</h4>
-
- <p>After finding apps they want to use, educators can push them instantly
-to student devices over the air. They can send the apps to individuals or groups
-of any size, across classrooms, schools, or even districts. </p>
-
+ <h3>
+ FOR EDUCATORS
+ </h3>
+ <b>Android tablets in the classroom</b>
+ <p>
+ Google Play for Education brings the innovation of Android technology
+ into classrooms. School districts can set up and deploy large numbers of
+ devices in just minutes or hours, rather than days.
+ </p>
+ <b>Curriculum-based discovery</b>
+ <p>
+ Powerful browsing tools let educators quickly discover apps, videos, and
+ other content—with many recommended by teachers and categorized according
+ to familiar Core Curriculum standards.
+ </p>
+ <b>Bulk purchase with institutional payment</b>
+ <p>
+ Convenient purchasing and delivery tools let educators buy apps in bulk,
+ using purchase orders and other payment methods that are easy for schools
+ to manage.
+ </p>
+ <b>Over-the-air delivery to student devices</b>
+ <p>
+ After finding apps they want, educators can push them instantly to
+ student devices over the air. They can send the apps to individuals or
+ groups of any size, across classrooms, schools, or even districts.
+ </p>
</div>
-
-
</div>
-<div id="video" style="background: #F0F0F0;
- border-top: 1px solid #DDD;
- padding: 0px 0 24px 0;
- overflow: auto;
- clear:both;
- margin-bottom:40px;
- margin-top:30px;">
- <div style="padding:0 0 0 29px;">
- <h4>Introducing Google Play for Education</h4>
- <div style="width:700px;">
- <p style="margin-top:26px;
- margin-bottom:12px;">
- Hear how Google Play for Education works and how developers can leverage the unique business opportunities in creating educational apps for the K-12 market. There's a demo at 4m10s.</p>
- </div>
- <iframe style="float:left;
- margin-right:24px;
- margin-top:14px;" width="700" height="394" src=
- "http://www.youtube.com/embed/haEmsMo0f3w?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
- </iframe>
- </div>
+<div class="headerLine clearfloat">
+<h1>Related Resources</h1><hr>
</div>
+
+<div class="dynamic-grid">
+
+<h3>For Developers</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/googleplay/gpfe/dev/about"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="6"></div>
+
+<h3>For Teachers and Educators</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/googleplay/aboutgpfe/educators/about"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="3"></div>
+
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/edu/contact.jd b/docs/html/distribute/googleplay/edu/contact.jd
index ca83438..042a92b 100644
--- a/docs/html/distribute/googleplay/edu/contact.jd
+++ b/docs/html/distribute/googleplay/edu/contact.jd
@@ -7,32 +7,29 @@
bring your first-class educational content into schools across the United
States, and to a broader international audience in the future. </p>
-<div class="vspace size-1">
-
-</div>
-<div class="layout-content-row">
- <div class="layout-content-col span-6">
- <h4>
- For Developers
- </h4>
- <p>
+<div style="margin:0 0 20px 0;" class="clearfloat dynamic-grid">
+ <div style="width:48%; margin-right:2%; float:left;">
+
+ <h3>
+ FOR DEVELOPERS
+ </h3>
+ <p>
Whether you have an existing educational app or are developing a fresh idea that
will unlock learning in the classroom — sign up to receive information about
-the upcoming launch of Google Play for Education. To get your apps ready, read our
-<a href="{@docRoot}distribute/googleplay/edu/guidelines.html">guidelines</a> for building
-educational apps.</p>
- </p><a href="http://developer.android.com/edu/signup">Developer Sign Up »</a>
+Google Play for Education. To get your apps ready, read our
+<a href="{@docRoot}distribute/essentials/gpfe-guidelines.html">guidelines for building
+educational apps</a>.</p>
+ </p><a href="http://developer.android.com/edu/signup">Developer Sign Up »</a> </p>
</div>
- <div class="layout-content-col span-6">
- <h4>
- For Educators
- </h4>
- <p>
+
+ <div style="width:48%; margin-left:2%; float:left;">
+
+ <h3>
+ FOR EDUCATORS
+ </h3>
+ <p>
If you're a school or system interested in tablets and Google Play for Education,
complete the expression of interest form at <a href="http://www.google.com/edu/android">www.google.com/edu/android</a>.
- </p><a href="http://www.google.com/edu/android">School Interest Form »</a>
- </div>
-</div>
-
-
+ </p><a href="http://www.google.com/edu/android">School Interest Form »</a> </div>
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/edu/faq.jd b/docs/html/distribute/googleplay/edu/faq.jd
index 0c3b185..0866da5 100644
--- a/docs/html/distribute/googleplay/edu/faq.jd
+++ b/docs/html/distribute/googleplay/edu/faq.jd
@@ -1,372 +1,433 @@
-page.title=Google Play for Education FAQ
-page.metaDescription=Questions and answers about Google Play for Education.
-excludeFromSuggestions=true
+page.title=Education FAQ
+meta.tags="gpfe, edu"
+page.metaDescription=Answers to frequent questions about Google Play for Education.
+page.image=/distribute/images/gpfe-faq.jpg
+
@jd:body
- <div style="position:absolute;margin-left: 636px;
- margin-top:-76px;color:#777;">If you're interested<br>
- <a href="{@docRoot}distribute/googleplay/edu/contact.html"
- class="go-link"
- style="display: block;text-align: right;">SIGN UP</a></div>
-
-
- <style>
- dt {
- font-weight:bold;
- }
- </style>
-
<div id="qv-wrapper">
-<ol id="qv">
-<h2>In this document</h2>
-<ol>
- <li><a href="#business">Business Model</a></li>
- <li><a href="#free_trials">Free Trials</a></li>
- <li><a href="#discovery">Discovery</a></li>
- <li><a href="#reviews">App Review Process</a></li>
- <li><a href="#features">App Features</a></li>
- <li><a href="#marketing">Marketing and ROI</a></li>
- <li><a href="#devices">Devices</a></li>
- <li><a href="#accounts">Accounts</a></li>
-</ol>
+ <div id="qv">
+ <h2>
+ Topics
+ </h2>
+
+ <ol>
+ <li>
+ <a href="#business-model-and-monetization">Business Model and
+ Monetization</a>
+ </li>
+
+ <li>
+ <a href="#free-trials">Free Trials</a>
+ </li>
+
+ <li>
+ <a href="#discovery">Discovery</a>
+ </li>
+
+ <li>
+ <a href="#app-review-process">App Review Process</a>
+ </li>
+
+ <li>
+ <a href="#app-features">App Features</a>
+ </li>
+
+ <li>
+ <a href="#marketing-and-roi">Marketing and ROI</a>
+ </li>
+
+ <li>
+ <a href="#devices">Devices</a>
+ </li>
+
+ <li>
+ <a href="#accounts">Accounts</a>
+ </li>
+
+ <li>
+ <a href="#related-resources">Related Resources</a>
+ </li>
+ </ol>
+ </div>
</div>
<p>
- The sections below provide more information about Google Play for Education
- and answer common questions that you might have about it.
+ This page provides answers to common questions that you might have about
+ Google Play for Education.
</p>
+<div class="headerLine">
+ <h1 id="business-model-and-monetization">
+ Business Model and Monetization
+ </h1>
-<h2 id="business">Business Model and Monetization</h2>
+ <hr>
+</div>
-<dl>
- <dt>
- What is Google Play for Education?
- </dt>
+<p>
+ <strong>What is Google Play for Education?</strong>
+</p>
- <dd>
- Google Play for Education is a new online destination designed for schools.
- Teachers can discover educational apps, books, and videos to meet the needs
- of a single student, a classroom, or a whole district. Educators can browse
- apps by grade, subject, keyword, or standard including common core.
- Purchasing is done via PO with no credit card required. Apps are
- distributed to tablets instantly via the cloud.
- </dd>
+<p>
+ Google Play for Education is a new online destination designed for schools.
+ Teachers can discover educational apps, books, and videos to meet the needs
+ of a single student, a classroom, or a whole district. Educators can browse
+ apps by grade, subject, keyword, or standard including Common Core State
+ Standards. Purchasing is done using a PO with no credit card required. Apps
+ are distributed to tablets instantly through the cloud.
+</p>
- <dt>
- Is Google Play for Education primarily for students or educators?
- </dt>
+<p>
+ <strong>Is Google Play for Education primarily for students or
+ educators?</strong>
+</p>
- <dd>
- The store on Google Play for Education is for educators, but its content is
- for both educators and students. Teachers and administrators have the
- ability to make purchases and control who within their school has access to
- the purchase flows.
- </dd>
+<p>
+ The store on Google Play for Education is for educators, but its content is
+ for both educators and students. Teachers and administrators have the ability
+ to make purchases and control who within their school has access to the
+ purchase flows.
+</p>
- <dt>
- Will Google Play for Education support subscription purchases?
- </dt>
+<div class="figure">
+ <img src="{@docRoot}distribute/images/gpfe-faq.jpg" style=
+ "width:480px;margin:1em 0em 1.5em 1.5em;">
+</div>
- <dd>
- Currently, Google Play for Education supports one-time purchases. We are
- investigating additional purchase mechanisms to enable more flexible
- pricing models for developers and schools.
- </dd>
+<p>
+ <strong>Will Google Play for Education support subscription
+ purchases?</strong>
+</p>
- <dt>
- Why is it recommended to disable in-app purchases?
- </dt>
+<p>
+ Currently, Google Play for Education supports one-time purchases. We’re
+ investigating additional purchase mechanisms to enable more flexible pricing
+ models for developers and schools.
+</p>
- <dd>
- In-app purchase is currently not supported with Google Play for Education,
- and a student device will block the Play transaction if a student attempts
- to make an in-app purchase. To avoid student confusion in the classroom,
- also recommend not including any in-app purchase buttons and other UI in
- your application. We are investigating additional purchase mechanisms to
- enable more flexible pricing models for developers and schools.
- </dd>
+<p>
+ <strong>Why is it recommended that in-app purchase features are
+ removed?</strong>
+</p>
- <dt>
- Is Google Play for Education restricted so only its users can purchase from
- the Google Play for Education? Or will anyone be able to purchase from it?
- </dt>
+<p>
+ In-app Billing is currently not supported with Google Play for Education, and
+ a student device will block the Google Play transaction if a student attempts
+ to make an in-app purchase. To avoid confusing students, we recommend not
+ including any in-app purchase buttons and other UI in your apps. We’re
+ investigating additional purchase mechanisms to enable more flexible pricing
+ models for developers and schools.
+</p>
- <dd>
- Currently, only schools that are signed up for Google Play for Education
- can make purchases on it.
- </dd>
+<p>
+ <strong>Is Google Play for Education restricted so only its users can
+ purchase from the Google Play for Education? Or will anyone be able to
+ purchase from it?</strong>
+</p>
- <dt>
- Is there a way to differentiate an app's pricing between Google Play for
- Education and Google Play?
- </dt>
+<p>
+ Currently, only schools that are signed up for Google Play for Education can
+ make purchases on it.
+</p>
- <dd>
- For each app that you publish, you can set a single price that applies to
- both Google Play and Google Play for Education &mdash. You can’t set a
- different price for a given app (based on a single package name) in Google
- Play for Education.
- </dd>
-</dl>
+<p>
+ <strong>Can I set different prices for my apps in Google Play for Education
+ and Google Play?</strong>
+</p>
+<p>
+ You set a single price for each app that applies to both Google Play and
+ Google Play for Education. You can’t set a different price for a given app
+ (based on a single package name) in Google Play for Education.
+</p>
-<h2 id="free_trials">Free Trials</h2>
+<div class="headerLine">
+ <h1 id="free-trials">
+ Free Trials
+ </h1>
-<dl>
- <dt>
- Can I offer free trials through Google Play for Education?
- </dt>
+ <hr>
+</div>
- <dd>
- Google Play for Education doesn't currently support free trials. If you
- want, you can offer a free version of your app with limited functionality
- in Google Play for Education, but that app would need to be separate from
- your paid app and be reviewed separately for educational content.
- </dd>
+<p>
+ <strong>Can I offer free trials through Google Play for Education?</strong>
+</p>
- <dt>
- Can I offer a free trial through Google Play's "In-app Subscriptions with
- Free Trials" feature?
- </dt>
+<p>
+ Google Play for Education doesn't currently support free trials. If you want,
+ you can offer a free version of your app with limited functionality in Google
+ Play for Education, but that app would need to be separate from your paid app
+ and be reviewed separately for educational content.
+</p>
- <dd>
- Google Play for Education does not currently support In-app Billing or
- In-app Subscriptions with free trials.
- </dd>
-</dl>
+<p>
+ <strong>Can I offer a free trial through Google Play's "In-app Subscriptions
+ with Free Trials" feature?</strong>
+</p>
+<p>
+ Google Play for Education doesn’t currently support In-app Billing or In-app
+ Subscriptions with free trials.
+</p>
-<h2 id="discovery">Discovery</h2>
+<div class="headerLine">
+ <h1 id="discovery">
+ Discovery
+ </h1>
-<dl>
- <dt>
- What are the categories in Google Play for Education?
- </dt>
+ <hr>
+</div>
- <dd>
- Google Play for Education includes categories for all grade levels from
- Kindergarten to 12 and the following subjects: English Language Arts, World
- Languages, Mathematics, Science, Social Science, Elective, OER (Open
- Education Resources), and Tools.
- </dd>
+<p>
+ <strong>What are the categories in Google Play for Education?</strong>
+</p>
- <dt>
- I created an app specifically for Google Play for Education and do not want
- it to show up in Google Play. Is this possible?
- </dt>
+<p>
+ Google Play for Education includes categories for all grade levels from
+ Kindergarten to 12 and the following subjects: English Language Arts, World
+ Languages, Mathematics, Science, Social Science, Elective, Open Education
+ Resources (OER), and Tools.
+</p>
- <dd>
- Currently, it is not possible to publish an app Google Play for Education
- and make it unavailable on Google Play.
- </dd>
+<p>
+ <strong>I created an app specifically for Google Play for Education and don’t
+ want it to show up in Google Play. Is this possible?</strong>
+</p>
- <dt>
- If my app offers content for every level of education, how will it fit the
- common-core standard filters?
- </dt>
+<p>
+ Currently, it’s not possible to publish an app on Google Play for Education
+ and make it unavailable on Google Play.
+</p>
- <dd>
- If your app applies to multiple levels of education, then the app will show
- up filtered results for in multiple levels.
- </dd>
-</dl>
+<p>
+ <strong>If my app offers content for every level of education, how will it
+ fit the Common Core State Standard filters?</strong>
+</p>
+<p>
+ If your app applies to multiple levels of education, then the app will show
+ up in filtered results for multiple levels.
+</p>
-<h2 id="reviews">App Review Process</h2>
+<div class="headerLine">
+ <h1 id="app-review-process">
+ App Review Process
+ </h1>
-<dl>
- <dt>
- How are apps being reviewed? By whom and with what criteria?
- </dt>
+ <hr>
+</div>
- <dd>
- Apps are being reviewed by a third party network of educators. These
- educators assign the appropriate subject, grade, and common core standards
- metadata, as well as evaluating whether the app meets the Google Play for
- Education <a href=
- "{@docRoot}distribute/googleplay/edu/guidelines.html">criteria for
- classroom use</a>. You can learn more about the submission process and
- criteria at <a href=
- "http://developer.android.com/edu">developer.android.com/edu</a>.
- </dd>
+<p>
+ <strong>How are apps being reviewed? By whom and against what
+ criteria?</strong>
+</p>
- <dt>
- How do I update my apps in Google Play for Education?
- </dt>
+<p>
+ Apps are being reviewed by a third-party network of educators. These
+ educators assign the appropriate subject, grade, and Common Core State
+ Standards metadata, as well as evaluating whether the app meets the Google
+ Play for Education <a href=
+ "{@docRoot}distribute/essentials/gpfe-guidelines.html">criteria for classroom
+ use</a>.
+</p>
- <dd>
- Developers can update their apps on Google Play for Education in the same
- manner that they do for Google Play. App updates will not be reviewed prior
- to being made available through Play for Education. However, we will
- periodically review updated apps for quality.
- </dd>
+<p>
+ <strong>How do I update my apps in Google Play for Education?</strong>
+</p>
- <dt>
- Does the app maturity rating reflect solely what a user can do within my
- Android app, or does the web version of my app influence the rating as
- well?
- </dt>
+<p>
+ You can update your apps on Google Play for Education in the same manner you
+ do on Google Play. App updates will not be reviewed prior to being made
+ available through Google Play for Education. However, we will periodically
+ review updated apps for quality.
+</p>
- <dd>
- The maturity rating that you set for your Android app refers only to the
- content displayed in that application.
- </dd>
-</dl>
+<p>
+ <strong>Does the app maturity rating reflect solely on what a user can do
+ within my Android app, or does the web version of my app influence the rating
+ as well?</strong>
+</p>
+<p>
+ The maturity rating that you set for an Android app refers only to the
+ content displayed in that app.
+</p>
-<h2 id="features">App Features</h2>
+<div class="headerLine">
+ <h1 id="app-features">
+ App Features
+ </h1>
-<dl>
- <dt>
- Do I need separate builds of my phone and tablet apps for Google Play for
- Education, or is it the exact same app that lives on Google Play?
- </dt>
+ <hr>
+</div>
- <dd>
- We recommend you create one app and use it in both Google Play and Google
- Play for Education.
- </dd>
+<p>
+ <strong>Do I need separate builds of my phone and tablet apps for Google Play
+ for Education, or is it the exact same app that lives on Google
+ Play?</strong>
+</p>
- <dt>
- What is the best way to get students’ work within apps sent back to their
- teachers?
- </dt>
+<p>
+ We recommend you create one app and use it in both Google Play and Google
+ Play for Education.
+</p>
- <dd>
- Many teachers have mentioned that the way apps treat this now is via an
- email from a third party, which is not optimal for schools. As many schools
- use Google Apps for Education, consider integrating your app with Google
- Drive using the SDK which can be found here: <a class="external-link" href=
- "https://developers.google.com/drive/about-sdk">developers.google.com/drive/about-sdk</a>.
- </dd>
+<p>
+ <strong>What is the best way to get students’ work within apps sent back to
+ their teachers?</strong>
+</p>
- <dt>
- How can developers test the teacher experience in Google Play for
- Education? Is there a way to get an account to test it?
- </dt>
+<p>
+ Teachers have mentioned that many apps achieve this by email from a third
+ party, which isn’t optimal for schools. As many schools use Google Apps for
+ Education, consider integrating your apps with Google Drive using the
+ <a href="https://developers.google.com/drive/about-sdk">SDK</a>.
+</p>
- <dd>
- Currently, we are unable to provide developers with a test account to test
- the Google Play for Education user experience. We are investigating ways to
- allow developers to simulate the environment.
- </dd>
+<p>
+ <strong>How can developers test the teacher experience in Google Play for
+ Education? Is there a way to get an account to test it?</strong>
+</p>
- <dt>
- If I already have an app in the Chrome Apps Pack will I get some help
- migrating this to Android?
- </dt>
+<p>
+ Currently, we are unable to provide developers with a test account to test
+ the Google Play for Education user experience. We’re investigating ways to
+ allow developers to simulate the environment.
+</p>
- <dd>
- If you’d like to reach tablet users in schools we encourage you
- to build a native app for the optimal user experience. Considerations for
- building your app and instructions for registering it can be found at
- <a href="http://developer.android.com/edu">developer.android.com/edu</a>.
- </dd>
-</dl>
+<p>
+ <strong>If I already have an app in the Chrome Apps Pack will I get some help
+ migrating this to Android?</strong>
+</p>
+<p>
+ If you’d like to reach tablet users in schools we encourage you to build a
+ native app for the optimal user experience. Considerations for building your
+ apps can be found in the <a href=
+ "{@docRoot}distribute/essentials/gpfe-guidelines.html">Google Play for
+ Education Guidelines</a>.
+</p>
-<h2 id="marketing">Marketing and ROI</h2>
+<div class="headerLine">
+ <h1 id="marketing-and-roi">
+ Marketing and ROI
+ </h1>
-<dl>
- <dt>
- What are you doing to promote these apps to educators?
- </dt>
+ <hr>
+</div>
- <dd>
- Google Play for Education is an extension of Google Play targeting schools
- and making discovery easier for educational apps. It helps your apps gain
- visibility with the right audiences, without having to knock on school
- doors. We are constantly referring to the highest quality apps in our
- educator outreach. We have also developed a series of collections to help
- educators quickly browse apps for the most common use cases.
- </dd>
+<p>
+ <strong>What are you doing to promote these apps to educators?</strong>
+</p>
- <dt>
- How many installs have similar apps had on Play? How much can I expect to
- make if I do an ROI analysis?
- </dt>
+<p>
+ Google Play for Education is an extension of Google Play targeting schools
+ and making the discovery of educational apps easier. It helps your apps gain
+ visibility with the right audiences, without having to knock on school doors.
+ We’re constantly referring to the highest quality apps in our educator
+ outreach. We’ve also developed a series of collections to help educators
+ quickly browse apps for the most common use cases.
+</p>
- <dd>
- While we cannot disclose specific numbers, Google Play app listings provide
- app download ranges for all apps.
- </dd>
+<p>
+ <strong>How many installs have similar apps had on Google Play for Education?
+ How much can I expect to make if I do an ROI analysis?</strong>
+</p>
- <dt>
- What is the seasonality like for the education market? What are the key
- timing considerations for app developers?
- </dt>
+<p>
+ While we cannot disclose specific numbers, Google Play app listings provide
+ app download ranges for all apps.
+</p>
- <dd>
- In the United States, school districts’ budget decisions go through a
- planning phase in the Spring with budgets being released on July 1. We have
- observed high purchase-volumes in the second quarter of the calendar year,
- using up end-of-year budgets. New budget purchases begin in the third
- quarter of the calendar year.
- </dd>
+<p>
+ <strong>What is the seasonality like for the education market? What are the
+ key timing considerations for app developers?</strong>
+</p>
- <dt>
- Is there a way to offer a special deal, such as a discount, only on Google
- Play for Education and not on Google Play?
- </dt>
+<p>
+ In the United States, school districts’ budget decisions go through a
+ planning phase in the Spring with budgets being released on July 1. We’ve
+ observed high purchase-volumes in the second quarter of the calendar year, to
+ use up end-of-year budgets. New budget purchases begin in the third quarter
+ of the calendar year.
+</p>
- <dd>
- No, this is not possible. Pricing, including special offers, must be the
- same between Google Play for Education and Google Play.
- </dd>
-</dl>
+<p>
+ <strong>Is there a way to offer a special deal, such as a discount, only on
+ Google Play for Education and not on Google Play?</strong>
+</p>
+<p>
+ No, this isn’t possible. Pricing, including special offers, must be the same
+ between Google Play for Education and Google Play.
+</p>
-<h2 id="devices">Devices</h2>
+<div class="headerLine">
+ <h1 id="devices">
+ Devices
+ </h1>
-<dl>
- <dt>
- Which devices are available in the program? Will more be available?
- </dt>
+ <hr>
+</div>
- <dd>
- Nexus 7 is available for shipment now, and the Asus Transformer and HP
- Slate 8 Pro will be available in early 2014. We look forward to welcoming
- more Android devices into the Google in Education family soon.
- </dd>
+<p>
+ <strong>Which devices are available in the program? Will more be
+ available?</strong>
+</p>
- <dt>
- Can the devices be shared among many students?
- </dt>
+<p>
+ Nexus 7 is available for shipment now, and the Asus Transformer, HP Slate 8
+ Pro, and Galaxy Tab for Education will be available in early 2014. We look
+ forward to welcoming more Android devices into the Google in Education family
+ soon.
+</p>
- <dd>
- No. Currently, this program is for one-to-one usage. Each student can login
- to one specific tablet that is allocated to them.
- </dd>
-</dl>
+<p>
+ <strong>Can the devices be shared among many students?</strong>
+</p>
+<p>
+ No. Currently, this program is for one-to-one use. Each student can login to
+ one specific tablet that is allocated to them.
+</p>
-<h2 id="accounts">
+<div class="headerLine">
+ <h1 id="accounts">
Accounts
-</h2>
+ </h1>
-<dl>
- <dt>
- Will an app know whether a user is a teacher or student?
- </dt>
+ <hr>
+</div>
- <dd>
- No, the app has no mechanism for knowing if it is running on a teacher’s
- device or a student’s device. We recommend developers use their own user
- database to enable this feature, where logins can be based on Google
- Account information.
- </dd>
+<p>
+ <strong>Will an app know whether a user is a teacher or student?</strong>
+</p>
- <dt>
- What log-in method do you recommend for an app on Google Play for
- Education?
- </dt>
+<p>
+ No, the app has no mechanism for knowing if it’s running on a teacher’s
+ device or a student’s device. We recommend developers use their own user
+ database to enable this feature, where logins can be based on Google Account
+ information.
+</p>
- <dd>
- One of the key pieces of feedback we have heard multiple times from various
- schools is that they prefer apps that offer Google Single Sign-on, so that
- teachers and students do not need to remember multiple log-in credentials.
- As schools in the program use Google Accounts and Google Apps for
- Education, offering Google Single Sign-on is ideal.
- </dd>
-</dl>
\ No newline at end of file
+<p>
+ <strong>What log-in method do you recommend for an app on Google Play for
+ Education?</strong>
+</p>
+
+<p>
+ One of the key pieces of feedback we’ve heard multiple times from various
+ schools is that they prefer apps that offer Google Single Sign-on, so that
+ teachers and students don’t need to remember multiple log-in credentials. As
+ schools in the program use Google Accounts and Google Apps for Education,
+ offering Google Single Sign-on is ideal.
+</p>
+<div class="headerLine"><h1 id="related-resources">Related Resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/toolsreference/gpfefaq"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x3,6x3,6x3,9x3,9x3,9x3"
+ data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/googleplay/edu/guidelines.jd b/docs/html/distribute/googleplay/edu/guidelines.jd
deleted file mode 100644
index 8427044..0000000
--- a/docs/html/distribute/googleplay/edu/guidelines.jd
+++ /dev/null
@@ -1,244 +0,0 @@
-page.title=Guidelines for Apps
-page.metaDescription=Get your apps ready for Google Play for Education.
-excludeFromSuggestions=true
-@jd:body
-
- <div style="position:absolute;margin-left: 636px;
- margin-top:-76px;color:#777;">If you're interested<br>
- <a href="{@docRoot}distribute/googleplay/edu/contact.html"
- class="go-link"
- style="display: block;text-align: right;">SIGN UP</a></div>
-
-<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">You
-can now include your educational apps in the recently launched Google Play for Education program,
-getting it into the hands of participating schools and key influencers in the education technology
-community. See <a href="start.html">Get Started</a> to
-learn how to participate. </div>
-
-<p>The sections below list the guidelines and requirements for apps
-participating in Google Play for Education.
-
-<p>Before you include your app in Google Play for Education, set up a <a
-href="#test-environment">test environment</a> and make sure your app meets all
-of the safety, usability, and quality guidelines given here. You can use the
-linked resources to help
-you develop a great app for students that offers compelling content and an
-intuitive user experience on Android tablets.</p>
-
-<p>In addition, ensure that your app complies with the terms of a <a
-href="https://play.google.com/about/developer-distribution-agreement-addendum.html"
-target="_policies">Google Play for Education Addendum</a>, as well as
-the standard <a
-href="http://play.google.com/about/developer-content-policy.html"
-target="_policies">Google Play Developer Program Policies</a> and <a
-href="http://play.google.com/about/developer-distribution-agreement.html"
-target="_policies">Developer Distribution Agreement</a>.</p>
-
-
-<h2 id="requirements">Safety First</h2>
-
-<p>To participate, your apps must be designed to be appropriate for
-the K-12 market. The basic requirements that your apps must meet are:</p>
-
-<ol>
- <li>Apps and the ads they contain must not collect personally identifiable
-information other than user credentials or data required to operate and improve
-the app.</li>
- <li>Apps must not use student data for purposes unrelated to its educational
-function.</li>
- <li>Apps must have a content rating of "Everyone" or "Low Maturity" (apps with
-a "Medium Maturity" rating are allowed, if they have that rating solely because
-they allow communication between students).</li>
- <li>App content, including ads displayed by the app, must be consistent with
-the app's maturity rating. The app must not display any “offensive” content, as
-described in the <a
-href="http://play.google.com/about/developer-content-policy.html">Google Play
-Developer Program Policies</a> and <a
-href="https://support.google.com/googleplay/android-developer/answer/188189">
-content-rating guidelines</a>.</p></li>
-<li>Apps must comply with the Children’s Online Privacy Protection Act
-and all other applicable laws and regulations.</li>
-</ol>
-
-
-<h2 id="inapp">Monetizing and Ads</h2>
-
-<p>Google Play for Education provides a simple and secure environment for students
-and teachers. To support that environment, priced or free apps that do not use in-app
-purchases are preferred, as are apps that do not display ads. Apps that use in-app
-payments or ads are acceptable, but you must declare those behaviors when opting-in
-to Google Play for Education. Your app's use of in-app purchases or ads will be
-disclosed to educators when they are browsing for content.</p>
-
-<p>Follow the guidelines below to help your app receive the
- highest ratings and offer the best possible user-experience.</p>
-
-<p>If your app is priced or sells in-app products, you must:</p>
-
-<ul>
- <li>Sell all content and services through Google Play for Education</li>
- <li>Allow Google Play to offer teachers limited free trials before purchase
-(through business terms only, no development work is needed)</li>
-<li>Disable in-app purchases if possible, or ensure that:
-
-<ul>
-<li>Users can access your app's core functionality for a classroom setting without
-an in-app purchase.</li>
-<li>In-app purchases are clearly identifiable in your UI.</li>
-<li>You declare the use of in-app purchases at <a href="{@docRoot}distribute/googleplay/edu/start.html#opt-in">opt-in</a>.</li>
-</ul>
-</li>
-</ul>
-
-<p class="note"><strong>Note</strong>: In-app
-purchases are blocked on Google Play for Education tablets at this time.</p>
-
-<p>If your app displays ads, you should:
- <ul>
- <li>Disable the display of ads if possible, or ensure that:
- <ul>
- <li>Ads are not distracting for students or teachers</li>
- <li>Ads do not occupy a significant portion of the screen</li>
- <li>Ads content does not exceed the maturity rating of the app.</li>
- <li>You declare the use of ads at <a href="{@docRoot}distribute/googleplay/edu/start.html#opt-in">opt-in</a>.</li>
- </ul>
- </li>
-</ul>
-
-
-<h2 id="approved">Educational Value</h2>
-
-<p>Apps submitted to Google Play for Education will be evaluated by a
-third-party educator network, which will review them based on alignment with <a
-href="http://www.corestandards.org/" class="external-link"
-target="_android">Common Core Standards</a> and other factors. This will help
-make your content more discoverable for teachers and administrators as they
-browse by grade level, subject, core curriculum, and other parameters. </p>
-
-<p>Apps with highest educational value will have these characteristics:</p>
-<ul>
- <li>Designed for use in K-12 classrooms.</li>
- <li>Aligned with a common core standard or support common-core learning.</li>
- <li>Simple, easy to use, and intuitive for the grade levels the app is targeting.
- App is relatively easy to navigate without teacher guidance. Not distracting
- or overwhelming to students.</li>
- <li>Enjoyable and interactive. App is engaging to students and lets them control
- their experience.</li>
- <li>Versatile. App has features make the it useful for more than one classroom
- function or lesson throughout the school year.</li>
- <li>Supports the "4Cs":
- <ul>
- <li><em>Creativity</em> — Allows students to create in order to express
- understanding of the learning objectives, and try new approaches, innovation
- and invention to get things done.</li>
- <li><em>Critical thinking</em> — Allows students to look at problems in
- a new way, linking learning across subjects and disciplines.</li>
- <li><em>Collaboration</em> — Allows students and (if appropriate) educators
- to work together to reach a goal.</li>
- <li><em>Communication</em> — Allows students to comprehend, critique and
- share thoughts, questions, ideas and solutions.</li>
- </ul>
- </li>
-</ul>
-
-<p>As you design and develop your app, make sure it offers high educational value
-by addressing as many of those characteristics as possible.</p>
-
-
-<h2 id="quality">App Quality</h2>
-
-<p>Google Play for Education brings educational content to students and teachers
-on Android tablets. Your apps should be designed to perform well and look great
-on Android tablets, and they should offer the best user experience possible.
-</p>
-
-<p>High quality apps are engaging, intuitive, and offer compelling content.
-Google Play for Education will highlight high-quality apps for easy discovery in
-the store. Here are some recommendations for making your app easy for students
-and teachers to enjoy.</p>
-
-<ul>
- <li>Meet Core app quality guidelines
- <ul>
- <li>Follow <a
- href="{@docRoot}design/index.html">Android Design Guidelines</a>. Pay special
- attention to the sections on <a href="{@docRoot}design/patterns/actionbar.html">Action
- Bar</a>, <a href="{@docRoot}design/patterns/navigation.html">Navigation</a> and <a
- href="{@docRoot}design/patterns/pure-android.html">Pure Android</a>.</li>
- <li>Test your apps against the <a href="{@docRoot}distribute/googleplay/quality/core.html">Core
- App Quality Guidelines</a>.</li>
- </ul>
- </li>
-<li>Meet tablet app quality guidelines
- <ul>
- <li>Follow our best practices for tablet app development</li>
- <li>Review the <a href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App
- Quality Checklist</a> and <a
- href="http://android-developers.blogspot.com/2012/11/designing-for-tablets-were-here-to-help.html"
- target="_android">blog post on designing for tablets</a></li>
- <li>Check your Optimization Tips in the Google Play Developer Console (if you've
- already uploaded your app)</li>
- </ul>
-<li>Strive for simplicity and highest usability for students
- <ul>
- <li>Design your app so that teachers and students can use all capabilities of
- your app without having to sign-in to multiple accounts and remember
- multiple passwords.</li>
- <li>Every student or teacher using a Google Play for Education tablet will already be
- signed in with a Google account on the device. You can take advantage of that to provide a
- simple, seamless sign-in experience in your app. A recommended approach is to use
- <a href="{@docRoot}google/play-services/auth.html">Google OAuth 2 authorization</a>
- through Google Play Services.</li>
- </ul>
-</li>
-</ul>
-
-
-<h2 id="test-environment">Test Environment</h2>
-
-<p>To test your app and assess it against the guidelines in this document, it's
-recommended that you set up a test environment that replicates the actual
-environment in which students and teachers will run your app.</p>
-
-<p>In general, you should use the test environment described in <a
-href="{@docRoot}distribute/googleplay/quality/tablet.html#test-environment">
-Setting Up a Test Environment for Tablets</a>, including a small number of
-actual hardware devices that replicate the tablet form factors used in the
-Google Play for Education.</p>
-
-<h3 id="devices">Android tablets</h3>
-
-<p>Google Play for Education offers a range of 7-inch through 10-inch tablets, so
-your testing should focus on those hardware devices. You can purchase the Nexus 7
-device from <a href="https://play.google.com/store/devices/details?id=nexus_7_16gb"
-target="_android">Google Play</a> and other stores. Although testing on Nexus
-devices is preferred, you can test on other 7-inch or 10-inch tablets or virtual
-devices if you don't have access to Nexus devices.</p>
-
-<h3 id="conditions">Test conditions</h3>
-
-<p>Once you've set up a suitable hardware environment, make sure to test your
-apps under conditions that simulate those of schools. For example, Google Play
-for Education lets administrators control or disable certain capabilities for
-students, so it's good to test your app with those capabilities disabled. Below
-are some conditions to test your app in, to ensure best results in the Google
-Play for Education environment:</p>
-
-<ul>
-<li><em>Android version</em> — Test the app on devices running Android
-4.2. Google Play for Education devices will be running Android 4.2 or higher
-(API level 17+).</li>
-<li><em>Proxy server</em> — Test the app in network environment that uses
-proxies. Many schools use proxies.</li>
-<li><em>No location services</em> — Test the app to make sure it works
-properly with location services disabled. Many schools will disable location
-services for student devices.</li>
-<li><em>No In-app Billing</em> — Test the app to make sure it works
-properly without access to In-app Billing. In-app purchases are blocked on
-Google Play for Education devices at this time.</li>
-<li><em>No Bluetooth</em> — Test the app to make sure it works properly
-when Bluetooth is disabled. Many schools will disable Bluetooth on student
-devices.</li>
-<li><em>No access to network</em> — Test the app to make sure it works
-properly when the device cannot connect to the internet. </li>
-</ul>
diff --git a/docs/html/distribute/googleplay/edu/index.jd b/docs/html/distribute/googleplay/edu/index.jd
deleted file mode 100644
index a27f82f..0000000
--- a/docs/html/distribute/googleplay/edu/index.jd
+++ /dev/null
@@ -1,48 +0,0 @@
-page.title=Google Play for Education
-page.tags=Google Play,education,schools,distribution
-header.hide=1
-
-@jd:body
- <div style="position:absolute;margin-left: 636px;
- margin-top:6px;color:#777;">If you're interested<br>
- <a href="{@docRoot}distribute/googleplay/edu/contact.html"
- class="go-link"
- style="display: block;text-align: right;">SIGN UP</a></div>
-
- <div class="marquee">
- <div class="mainimg" style="position:absolute;margin-left:34px;margin-top:57px;">
- <img src="{@docRoot}images/gp-edu-hero14.jpg" style="width:670px;" />
- </div>
- <div class="copy" style="position:relative;left:334px;margin-top:28px;width:420px;">
- <h1 style="margin-bottom:10px;">Google Play for Education</h1>
- <p>Google Play for Education is a destination where schools can find great,
- teacher-approved, educational apps and videos on Play Store. Teachers can filter
- content by subject matter, grade and other criteria. Bulk purchase and instant
- distribution let educators bring your apps directly to classrooms and schools.</p>
- <p>If you have an educational app, join Google Play for Education.</p>
- <p><a class="button" href="{@docRoot}distribute/googleplay/edu/about.html">Learn More</a></p>
- </div>
-</div>
-
-<div class="distribute-features col-13" style="clear:both;margin-top:248px;">
- <div class="distribute-link">
- <ul>
- <li><a href="{@docRoot}distribute/googleplay/edu/about.html"><h5>About the Initiative</h5>
- Find out how Google Play for Education helps you reach a new audience of educators and students.</a>
- <li><a href="{@docRoot}distribute/googleplay/edu/start.html"><h5>Get your Apps Ready</h5>
- Follow these guidelines to make sure your app meets requirements and offers a great user experience. </a>
- </li>
- <li class="last"><a href="{@docRoot}distribute/googleplay/edu/start.html#opt-in"><h5>Submit your App</h5>
- Use the Google Play Developer Console to mark your app for inclusion in the program and review by third-party
- educators. </a>
- </li>
- </ul>
- </div>
-
-</div>
-
-
-
-
-
-
diff --git a/docs/html/distribute/googleplay/edu/start.jd b/docs/html/distribute/googleplay/edu/start.jd
index dbfbb6a..260ae85 100644
--- a/docs/html/distribute/googleplay/edu/start.jd
+++ b/docs/html/distribute/googleplay/edu/start.jd
@@ -1,233 +1,320 @@
-page.title=Get Started
-page.metaDescription=Get Started with Google Play for Education
-excludeFromSuggestions=true
+page.title=Get Started with Education
+page.image=/distribute/images/play-education.jpg
+meta.tags="education", "guidelines", "quality"
+page.tags="education", "addendum"
+page.metaDescription=Join Google Play for Education in just a few simple steps.
+
@jd:body
- <div class="jd-descr" itemprop="articleBody">
- <div style="position:absolute;margin-left: 636px;
- margin-top:-76px;color:#777;">If you're interested<br>
- <a href="{@docRoot}distribute/googleplay/edu/contact.html"
- class="go-link"
- style="display: block;text-align: right;">SIGN UP</a></div>
-
-<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">You
-can now include your educational apps in the Google Play for Education program,
-getting it into the hands of participating schools and key influencers in the
-education technology community. See the sections below to learn more.</div>
-
-<p>If you've got a great app for education, be
-part of Google Play for Education to reach even more teachers and students. It's
-easy to participate, and you'll be able to offer new or existing Android apps
-using familiar tools and processes in Google Play.</p>
-
-<p>To get started, review the sections in this document and learn how to make
-your apps available through Google Play for Education. Also make sure to read <a
-href="{@docRoot}distribute/googleplay/edu/guidelines.html">Guidelines for
-Apps</a> for information on the safety, usability, and quality standards that
-your apps should meet. When your app is ready, you can opt-in to Google Play for
-Education from the Developer Console.</p>
-
-<p>Note that Google Play for Education is currently available to schools in the
-United States only, with support for schools in other
-countries to follow. At this time, please include your app in Google Play for
-Education only if it is targeting the <strong>US K-12 market</strong>. </p>
-
-
-<h2 id="participate">How to Participate</h2>
-
-<div style="float:right; padding-top:2em;"><img
-src="{@docRoot}images/gp-edu-process.png" /></div>
-
-<p>Google Play for Education is a great way to put your educational apps in front of a
-new audience of teachers and students. You can develop and publish using
-familiar tools and processes, such as your existing <a
-href="https://play.google.com/apps/publish/">Developer Console</a> account
-and your current distribution and pricing settings. It's easy to participate
-— the sections below outline the process.</p>
-
-<h3 id="basic-info">1. Understand guidelines and policies</h3>
-
-<p>To prepare for a successful launch on Google Play for Education, start by
-reviewing the guidelines for educational apps in Google Play and the policies
-that apply to your apps. See <a
-href="{@docRoot}distribute/googleplay/edu/guidelines.html">Guidelines for
-Apps</a> for details.</p>
-
-<p>Also, make sure that your are familiar with the policies that your app must
-comply with, including
-<a href="http://play.google.com/about/developer-content-policy.html" target="_policies">content
-policies</a>, the <a
-href="http://play.google.com/about/developer-distribution-agreement.html"
-target="_policies">developer agreement</a>, and <a
-href="https://play.google.com/about/developer-distribution-agreement-addendum.html"
-target="_policies">Google Play for Education Addendum</a>.</p>
-
-<h3 id="developing">2. Design and develop a great app for education</h3>
-
-<p>A great app for educators and students is designed for classroom use, looks
-great on tablets, and delivers a compelling feature set for teachers and
-students. If you are developing an app for education, make sure that it is
-appropriate for K-12 classrooms, offers educational value, and is refined to
-offer a polished, high-quality tablet experience.</p>
-
-<p>Assess your app against the criteria listed in <a
-href="{@docRoot}distribute/googleplay/edu/guidelines.html">Guidelines for
-Apps</a> and plan on supporting them to the greatest extent possible. In some
-cases you might need to modify your features or UI to support the requirements
-of the classroom use-case. It's a good idea to identify those areas early in
-development so that you are able address them properly. </p>
-
-<p>With Google Play for Education, optimizing your app for tablets is a crucial
-part of getting your app ready for distribution to educators. A variety of
-resources are available to help you understand what you need to optimize for
-tablets — a good starting point is the <a
-href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality
-Guidelines</a>. </p>
-
+<div id="qv-wrapper"><div id="qv">
+<h2>Steps to Join</h2>
+<ol>
+<li><a href="#register">Register for a Publisher Account</li>
+<li><a href="#prepare">Prepare Your Apps</a></li>
+<li><a href="#publish">Publish Your Apps</a></li>
+<li><a href="#related-resources">Related Resources</a></li>
+</ol>
+</div></div>
<p>
- Throughout design and development, it's important to have suitable devices
- on which to prototype and test your user experience. It's highly recommended
- that you acquire 7-inch and 10-inch tablet devices and set up
- your testing environment as early as possible. The recommended 7-inch
- hardware device that replicates the Google Play for Education environment is
- the Nexus 7, which is available from <a href=
- "https://play.google.com/store/devices/details?id=nexus_7_16gb" target=
- "_android">Google Play</a> and other stores.
+ If you've got great apps for education and want to reach even more teachers
+ and students, you can join the <strong>Google Play for Education</strong>
+ program in a few simple steps. You do everything using the familiar tools and
+ processes in Google Play.
</p>
-<p>Proper testing and quality assurance are key aspects of delivering a great
-app for teachers and students. Make sure you set up a <a
-href="{@docRoot}distribute/googleplay/edu/guidelines.html#test-environment">
-proper test environment</a> to ensure that your app meets guidelines under
-realistic conditions.</p>
+<p>
+ Note that Google Play for Education is currently available to <strong>K-12
+ schools in the United States</strong> only.
+</p>
-<h3 id="opt-in">3. Opt-in to Google Play for Education and publish</h3>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Before you opt-in</h2>
-<p>To participate in Google Play for Education, you must agree to a <a
-href="https://play.google.com/about/developer-distribution-agreement-addendum.html"
-target="_policies">Google Play for Education Addendum</a>
-to the standard Developer Distribution Agreement.</p>
-
-<p>Before you opt-in, review the Addendum completely and make any necessary
-modifications to your app.</p>
-</div>
+<div class="center-img">
+ <img src="{@docRoot}images/gpfe-start-0.jpg" style=
+ "border:1px solid #ddd;padding:0px;width:100%;">
</div>
-<p>Once you've built your release-ready APK and tested to ensure that it meets
-the <a href="{@docRoot}distribute/googleplay/edu/guidelines.html">app guidelines</a>,
-upload it to the Developer Console, create your store listing, and set
-distribution options. If you aren't familiar with how to prepare for launch on
-Google Play, see the <a
-href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch Checklist</a>. </p>
+<div class="headerLine clearfloat">
+ <h1 id="register">
+ Register for a Publisher Account
+ </h1>
-<p>When your app is ready to publish, you can <em>opt-in</em> to Google Play for
-Education directly from the <a
-href="https://play.google.com/apps/publish/">Developer Console</a>. Opt-in means that you want your app to be
-made available to educators through Google Play for Education, including review,
-classification, and approval by our third-party educator network. Note that
-opt-in does not affect the availability of your app in Google Play Store.</p>
+ <hr>
+</div>
-<p>Opt-in also confirms that your app complies with <a
-href="http://play.google.com/about/developer-content-policy.html"
-target="_policies">Google Play Developer Program
-Policies</a> and the <a
-href="http://play.google.com/about/developer-distribution-agreement.html"
-target="_policies">Developer Distribution Agreement</a>,
-including a <a
-href="https://play.google.com/about/developer-distribution-agreement-addendum.html"
-target="_policies">Google Play for Education
-Addendum</a>. If you are not familiar with these policy documents or the
-Addendum, make sure to read them before opting-in. </p>
+<p>
+ If you’re new to Google Play, review the information on <a href=
+ "{@docRoot}distribute/googleplay/start.html">getting started</a> with
+ publishing on Google Play. You’ll gain access to the <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html">Developer
+ Console</a>, where you’ll manage your details, apps, and payments.
+</p>
-<p>Here's how to opt-in to Google Play for Education for a specific app:</p>
+<div class="headerLine">
+ <h1 id="prepare">
+ Prepare Your Apps
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure-right">
+ <img src="{@docRoot}images/gp-edu-process.png">
+</div>
+
+<p>
+ By participating in Google Play for Education you’ll be placing your apps
+ before a new audience of teachers and educators. To address this audience,
+ there are specific guidelines and policies your apps should meet and specific
+ design considerations too.
+</p>
+
+<h3>
+ Understand guidelines and policies
+</h3>
+
+<p>
+ To prepare for a launch on Google Play for Education, start by reviewing the
+ guidelines for educational apps in Google Play and the policies that apply to
+ your apps. See the <a href=
+ "{@docRoot}distribute/essentials/gpfe-guidelines.html">Education
+ Guidelines</a> for details.
+</p>
+
+<p>
+ Also, make sure that you're familiar with the policies that your app must
+ comply with, including <a href=
+ "http://play.google.com/about/developer-content-policy.html">content
+ policies</a>, the <a href=
+ "http://play.google.com/about/developer-distribution-agreement.html">Developer
+ Distribution Agreement</a>, and <a href=
+ "https://play.google.com/about/developer-distribution-agreement-addendum.html">
+ Google Play for Education Addendum</a>.
+</p>
+
+<h3>
+ Design and develop a great app for education
+</h3>
+
+<p>
+ Great apps for educators and students <strong>offer educational
+ value</strong>, are <strong>designed for K-12 classroom use</strong>,
+ <strong>deliver a compelling feature set</strong>, and are refined to offer a
+ polished, <strong>high-quality tablet experience</strong>.
+</p>
+
+<p>
+ Assess your app against the criteria listed in the <a href=
+ "{@docRoot}distribute/essentials/gpfe-guidelines.html">Education
+ Guidelines</a> and plan on supporting them to the greatest extent possible.
+ In some cases you might need to modify the app’s features or UI to support
+ classroom requirements. It's a good idea to identify any changes early in
+ development, so that you can address them properly.
+</p>
+
+<p>
+ With Google Play for Education, optimizing your apps for tablets is crucial.
+ A variety of resources are available to help you understand what you need to
+ do — a good starting point is the <a href=
+ "{@docRoot}distribute/essentials/quality/tablets.html">Tablet App Quality</a>
+ guidelines.
+</p>
+
+<p>
+ Throughout design and development, it's important to have suitable devices on
+ which to prototype and test your user experience. It's recommended highly
+ that you acquire 7-inch and 10-inch tablet devices and set up your testing
+ environment as early as possible. The recommended 7-inch hardware device that
+ replicates the Google Play for Education environment is the Nexus 7, which is
+ available from <a href=
+ "https://play.google.com/store/devices/details?id=nexus_7_16gb_2013">Google
+ Play</a> and other stores.
+</p>
+
+<p>
+ Comprehensive testing and quality assurance are key aspects of delivering
+ great apps for teachers and students. Make sure you set up a <a href=
+ "{@docRoot}distribute/essentials/gpfe-guidelines.html#test-environment">proper
+ test environment</a> to, ensure that your apps meet the guidelines under
+ realistic conditions.
+</p>
+
+<div class="headerLine">
+ <h1 id="publish">
+ Publish Your Apps
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Once you have designed, built, and tested your apps, you take two steps to
+ publish them:
+</p>
+
+<ul>
+ <li>Before you opt-in any apps, agree to the <a href=
+ "https://play.google.com/about/developer-distribution-agreement-addendum.html"
+ target="_policies">Google Play for Education Addendum</a>. Ensure you
+ review the Addendum completely and make any necessary modifications to your
+ apps.
+ </li>
+
+ <li>Publish your apps in the Developer Console as normal, but opt-in to
+ Google Play for Education.
+ </li>
+</ul>
+
+<h3 id="opt-in">
+ Opt-in to Google Play for Education and publish
+</h3>
+
+<p>
+ Once you've built your release-ready APK upload it to the Developer Console,
+ create your store listing, and set distribution options. If you aren't
+ familiar with preparing for launch on Google Play, see the <a href=
+ "{@docRoot}distribute/tools/launch-checklist.html">Launch Checklist</a>.
+</p>
+
+<div>
+ <img src="{@docRoot}images/gp-edu-optin-console.jpg" style=
+ "border:2px solid #ddd;width:660px;">
+</div>
+
+<p>
+ When your apps are ready to publish, you <em>opt-in</em> to Google Play for
+ Education directly from the <a href=
+ "https://play.google.com/apps/publish/">Developer Console</a>. Opt-in means
+ that you want your apps to be made available to educators through Google Play
+ for Education, including review, classification, and approval by our
+ third-party educator network. Note that opt-in doesn’t affect the
+ availability of your app in Google Play Store.
+</p>
+
+<p>
+ Opt-in also confirms that your app complies with <a href=
+ "http://play.google.com/about/developer-content-policy.html" target=
+ "_policies">Google Play Developer Program Policies</a> and the <a href=
+ "http://play.google.com/about/developer-distribution-agreement.html" target=
+ "_policies">Developer Distribution Agreement</a>, including a <a href=
+ "https://play.google.com/about/developer-distribution-agreement-addendum.html"
+ target="_policies">Google Play for Education Addendum</a>. If you are not
+ familiar with these policy documents or the Addendum, make sure to read them
+ before opting-in.
+</p>
+
+<p>
+ Here's how to opt-in to Google Play for Education for a specific app:
+</p>
<ol>
- <li>In the Developer Console All Applications page, click the app you want to
-opt-in. </li>
- <li>Under Pricing and Distribution, scroll down to find "Google Play for
-Education" and the opt-in checkbox. </li>
- <li>Click the checkbox next to "Include this application in Google Play for
-Education."</li>
- <li>In the first dialog that appears, review the content policies and guidelines
- and click "Continue" if your app meets the the policies and guidelines.</li>
- <li>In next dialog that appears, shown below, find the "Ads" and "In-app purchases" radio
- buttons. Check each option that applies. Your app's use of ads or in-app purchases will
-be shown to educators when they are browsing your app. </li>
- <li>Click "Save" to save your Pricing and Distribution changes.</li>
+ <li>In the Developer Console <strong>All Applications</strong> page, click
+ the app you want to opt-in.
+ </li>
+
+ <li>Under Pricing and Distribution, scroll down to find <strong>Google Play
+ for Education</strong> and the opt-in checkbox.
+ </li>
+
+ <li>Click the checkbox next to <strong>Include my app in Google Play for
+ Education...</strong>
+ </li>
+
+ <li>In the first dialog that appears, review the content policies and
+ guidelines and click <strong>Continue</strong> if your app meets the the
+ policies and guidelines.
+ </li>
+
+ <li>In the next dialog that appears, shown below, find the
+ <strong>Ads</strong> and <strong>In-app purchases</strong> radio buttons.
+ Check each option that applies. Your app's use of ads or in-app purchases
+ will be shown to educators when they are browsing your app.
+ </li>
+
+ <li>Click <strong>Save</strong>f to save your Pricing and Distribution
+ changes.
+ </li>
</ol>
<div style="clear:both;margin-top:1.5em;margin-bottom:1.5em;width:660px;">
-<img src="{@docRoot}images/gp-edu-ads-iab.png" style="border:2px solid #ddd;width:660px;" />
-<p class="image-caption"><span style="font-weight:500;">Ads and in-app purchase</span>:
-When you opt-in to Google Play for Education, make sure to declare your app's use of ads and
-in-app purchases.</p>
+ <img src="{@docRoot}images/gp-edu-ads-iab.png" style=
+ "border:2px solid #ddd;width:660px;">
+ <p class="img-caption">
+ <strong>Ads and in-app purchase</strong>: When you opt-in to Google Play
+ for Education, make sure to declare your app's use of ads and in-app
+ purchases.
+ </p>
</div>
-<p>Once you save changes and publish your app, the app will be submitted to our
-third-party educator network for review and approval. If the app is already
-published, it will be submitted for review as soon as you opt-in and save your
-changes. </p>
+<p>
+ Once you save changes and publish your app, the app will be submitted to our
+ third-party educator network for review and approval. If the app is already
+ published, it will be submitted for review as soon as you opt-in and save
+ your changes.
+</p>
-<p class="note"><strong>Note</strong>: Google Play for Education is part of
-Google Play. When you publish an app that's opted-in to Google Play for
-Education, the app becomes available to users in Google Play right away. After
-the app is reviewed and approved, it then becomes available to educators in
-Google Play for Education.</p>
+<p class="note">
+ <strong>Note</strong>: Google Play for Education is part of Google Play. When
+ you publish an app that's opted-in to Google Play for Education, the app
+ becomes available to users in Google Play right away. After the app is
+ <a href="{@docRoot}distribute/essentials/gpfe-guidelines.html#e-value">review
+ and approval</a>, it then becomes available to educators in Google Play for
+ Education.
+</p>
-<h3 id="review">4. Track your review and approval</h3>
+<h3>
+ Track your review and approval
+</h3>
-<p>Google Play for Education provides content to educators in a way that's
-properly organized by subject, grade level, and common core standards (where
-applicable). To ensure high educational value and proper classification, we work
-with a third-party educator network to review and approve apps before making
-them discoverable through the Google Play for Education browsing tools. </p>
+<p>
+ As soon as you opt-in to Google Play for Education and publish, your apps are
+ queued for review by our third-party educator network. The review and
+ approval process can take four weeks or more. You'll receive notification by
+ email (to your developer account address) when the review is complete, with a
+ summary of the review results.
+</p>
-<p>Our third-party educator network will evaluate apps according to educational
-value and alignment with K-12 core standards, then assign the metadata for
-subject, grade level, and core curriculum that makes them easily browsable for
-educators. To understand how your apps will be evaluated, please see the <a
-href="{@docRoot}distribute/googleplay/edu/guidelines.html">Guidelines for
-Apps</a> document.</p>
-
-<p>As soon as you opt-in to Google Play for Education and publish, your app is
-queued for review by our third-party educator network. The review and approval
-process can take four weeks or more</strong>. You'll receive notification
-by email (to your developer account address) when the review is complete, with a
-summary of the review results. </p>
-
-<p>At any time, you can check the review and approval status of your app in the
-<a href="https://play.google.com/apps/publish/">Developer Console</a>, under
-"Google Play for Education" in the app's Pricing and
-Distribution page. There are three approval states:</p>
+<p>
+ At any time, you can check the review and approval status of your app in the
+ Developer Console, under "Google Play for Education" in the app's Pricing and
+ Distribution page. There are three approval states:
+</p>
<ul>
-<li><em>Pending</em> — Your app was sent for review and the review
-is not yet complete.</li>
-<li><em>Approved</em> — Your app was reviewed and approved. The app
-will be made available directly to educators through Google Play for Education.
-Once your app is approved, you can update it at your convenience without needing
-another full review. </li>
-<li><em>Not approved</em> — Your app was reviewed and not approved.
-Check the notification email for information about why the app was not approved.
-You can address any issues and opt-in again for another review. </li>
+ <li>
+ <em>Pending</em> — Your app was sent for review and the review isn't
+ yet complete.
+ </li>
+
+ <li>
+ <em>Approved</em> — Your app was reviewed and approved. The app will
+ be made available directly to educators through Google Play for Education.
+ Once your app is approved, you can update it at your convenience without
+ needing another full review.
+ </li>
+
+ <li>
+ <em>Not approved</em> — Your app was reviewed and not approved. Check
+ the notification email send for information about why the app wasn’t
+ approved. You can address any issues and opt-in again for another review.
+ </li>
</ul>
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
-<p>If you have questions about the review status of your app, follow the process
-discussed in the next section. </p>
+<div class="dynamic-grid">
+<h3>FOR DEVELOPERS</h3>
-<h3 id="appeal">5. Get support or appeal your review results</h3>
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/googleplay/gpfe/dev"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3,9x3,6x3,6x3,6x3"
+ data-maxResults="8"></div>
-<p>After your app is reviewed you'll receive an email giving you the
-results, including information on whether the app was approved and
-what issues may need to be addressed. You'll receive the email at the address
-you specified for your developer account. </p>
+<h3>FOR EDUCATORS</h3>
-<p>If your app has issues that need to be addressed, make the necessary
-adjustments, upload your app, and then resubmit the app to Google Play for
-Education through the Developer Console using process described above. Your app
-will be queued for review and you'll receive the review results by email just
-as before.</p>
-
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/googleplay/aboutgpfe/educators"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="3"></div>
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/googleplay_toc.cs b/docs/html/distribute/googleplay/googleplay_toc.cs
new file mode 100644
index 0000000..4196c39
--- /dev/null
+++ b/docs/html/distribute/googleplay/googleplay_toc.cs
@@ -0,0 +1,47 @@
+<ul id="nav">
+
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/about.html">
+ <span class="en">The Google Play Opportunity</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/start.html">
+ <span class="en">Get Started with Publishing</span>
+ </a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/developer-console.html">
+ <span class="en">Developer Console</span>
+ </a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/edu/about.html">
+ <span class="en">Google Play for Education</span>
+ </a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/edu/start.html">
+ <span class="en">Get Started with Education</span>
+ </a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/edu/faq.html">
+ <span class="en">Education FAQ</span>
+ </a>
+ </div>
+ </li>
+</ul>
+
+
+<script type="text/javascript">
+<!--
+ buildToggleLists();
+ changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html/distribute/googleplay/index.jd b/docs/html/distribute/googleplay/index.jd
new file mode 100644
index 0000000..a215930
--- /dev/null
+++ b/docs/html/distribute/googleplay/index.jd
@@ -0,0 +1,45 @@
+page.title=Google Play
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+ <p>
+ The premier store for distributing Android apps and games, with global reach
+ and <span style="white-space:nowrap;">tools to
+ help you gain traction in the marketplace.</span>
+</p>
+
+<div class="dynamic-grid">
+
+ <h3>Overview</h3>
+
+ <div class="resource-widget resource-flow-layout landing col-16"
+ data-query="collection:distribute/gp/gplanding"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x6"
+ data-maxResults="3">
+ </div>
+
+ <h3>Google Play for Education</h3>
+
+ <div class="resource-widget resource-flow-layout landing col-16"
+ data-query="collection:distribute/gp/gpfelanding"
+ data-cardSizes="6x6"
+ data-maxResults="3">
+ </div>
+
+ <h3>Related resources</h3>
+
+ <div class="resource-widget resource-flow-layout col-16"
+ data-query="type:youtube+tag:growth"
+ data-cardSizes="6x3"
+ data-maxResults="3">
+ </div>
+ <div class="resource-widget resource-flow-layout col-16"
+ data-query="type:blog+tag:googleplay"
+ data-cardSizes="6x3"
+ data-maxResults="3">
+ </div>
+
+</div>
diff --git a/docs/html/distribute/googleplay/policies/ads.jd b/docs/html/distribute/googleplay/policies/ads.jd
deleted file mode 100644
index f2fb0f8..0000000
--- a/docs/html/distribute/googleplay/policies/ads.jd
+++ /dev/null
@@ -1,350 +0,0 @@
-page.title=Ads
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
- <h2>In This Document</h2>
- <ol>
- <li><a href="#content-maturity">Content and Maturity</a></li>
- <li><a href="#context">Context and Behavior</a></li>
- <li><a href="#disclosure" style="clear:right">Disclosure</a></li>
- <li><a href="#impersonation">Impersonation of System UI</a></li>
- <li><a href="#adwalls">Adwalls and Interstitial Ads</a></li>
- <li><a href="#interfering" style="clear:right;">Interference with Apps and Third-Party Ads</a></li>
- </ol>
-
- <h2>More Resources</h2>
- <ol>
- <li><a href="http://play.google.com/about/developer-content-policy.html" target="_policies">Developer Program Policies</a></li>
- <li><a href="http://www.android.com/us/developer-distribution-agreement.html#showlanguages" target="_policies">Developer Distribution Agreement</a></li>
- <li><a href="http://support.google.com/googleplay/android-developer/answer/188189" target="_policies">Maturity Ratings</a></p>
- </ol>
-</div>
-</div>
-
-<p>
- Google Play policies guide how you can use ads in your apps, to help ensure
- the best experience for users visiting and downloading apps from the store.
-</p>
-
-<p>
- In general, for the purposes of policy, the content of ads displayed by your
- app is considered part of your app. As an app developer, it is your
- responsibility to ensure that the content, context, and behavior of ads in
- your apps conforms to Google Play policies.
-</p>
-
-<p>
- Before you publish, make sure you understand Google Play ad policies and how
- to display ads in conformance with those policies. The sections below
- highlight best practices and common examples to help you avoid the most
- common types of policy violations.
-</p>
-
-<p>
- For more information about Google Play policies that apply to your apps and
- content, please see the <a href=
- "http://play.google.com/about/developer-content-policy.html" target=
- "_policies">Developer Program Policies</a> and <a href=
- "http://play.google.com/about/developer-distribution-agreement.html" target=
- "_policies">Developer Distribution Agreement</a>.
-</p>
-
-
-<h2 id="content-maturity">Content and Maturity</h2>
-
-<div class="example-block bad">
- <div class="heading">Ad maturity exceeds app</div>
- <img src="{@docRoot}images/gp-policy-ads-maturity-violation.png">
-</div>
-
-<p>
- From a policy perspective, ads shown in your app are part of your content
- and your app is responsible for any violations. If an ad shown in your app
- violates Google Play policies, your app may be suspended or your developer
- account terminated.
-</p>
-
-<p>
- For this reason, it's important for you to be be aware of what ads will be
- displayed in your app and to manage the ads content according to Google Play
- policies. Here are some guidelines:
-</p>
-
-<ul>
- <li>
- <strong>Ads must not violate Content Policy</strong>—Ads in
- your app must not violate the terms of Google Play’s Content Policy,
- including those concerning illegal activities, violence, sexually
- explicit content, or privacy violations.
- </li>
- <li>
- <strong>Ads maturity must be consistent with your app's
- maturity</strong>—Content shown in your ads must be consistent
- with the app’s maturity rating in Google Play. Especially, ads content
- should never exceed your app's maturity rating, even if the ads content
- by itself complies with general policies.
- </li>
-</ul>
-
-<p>
- In the example at right, the app's maturity rating is set to
- "Everyone", which is the lowest maturity level on Google Play. By choosing
- the "Everyone" maturity level, the developer is declaring that all of the
- content in the app, <em>including ads</em>, is suitable for all users
- regardless of age.
-</p>
-
-<p>
- The example app violates Google Play policies by displaying ad content with a
- higher maturity level—ad content showing gambling, profanity, user
- location, suggestive content, or content from another app with higher
- maturity exceeds the "Everyone" maturity rating. Because the ad's
- maturity is higher than the app's maturity level, the app itself is in
- violation of policy. To correct the problem, the developer must either
- restrict ads content to "Everyone" level or raise the app's maturity rating.
-</p>
-
-<p>
- For detailed information about how to choose the appropriate maturity level
- for your app, or to assess the maturity requirement of ads in your app, see
- <a href=
- "http://support.google.com/googleplay/android-developer/answer/188189"
- target="_policies">Rating your application content for Google Play</a>.
-</p>
-
-
-<h2 id="context">Context and Behavior</h2>
-
-<p>
- If your app displays ads, it should do so in ways that do not interrupt users,
- mislead them into clicking on ads, or make changes outside the app without
- the user's knowledge or consent. Here are some guidelines:
-</p>
-
-<ul>
- <li>
- <strong>Display your ads within your UI</strong>—If possible,
- display ads only within your app's UI. This leads to a better user
- experience and helps avoid policy violations
- </li>
-
- <li>
- <strong>Don't make changes outside of the app without consent</strong>
- —Ads must not make changes outside of the app without the user's
- full knowledge and consent.
- </li>
-
- <li>
- <div class="example-block bad" style="width:360px;margin:1em 0 0 2em;">
- <div class="heading">Ads through system-level notifications</div>
- <img src="{@docRoot}images/gp-policy-ads-notif-attr-violation.png">
- </div>
- <div class="example-block good" style="width:360px;margin:.5em 0 0 2em;">
- <div class="heading">Notification that's part of the app's feature set</div>
- <img src="{@docRoot}images/gp-policy-ads-notif-attr.png">
- </div>
- <strong>Changes outside the app must be reversible</strong>—If an
- ad makes changes outside the app as described above, the changes (and
- origin app) must be evident and easily reversible. For example, the user
- must be able to locate and reverse the changes by adjusting settings,
- changing ad preferences in the app, or uninstalling the app altogether.
- </li>
-
- <li>
- <strong>Notification ads are prohibited</strong>—Your app
- should not create system-level <a href=
- "{@docRoot}design/patterns/notifications.html">notifications</a>
- containing ads unless the notifications are part of the explicit
- feature set of the app.
- </li>
-
- <li>
- <strong>Don't add shortcuts, bookmarks, or icons</strong>—Your app
- and its ads must not add homescreen shortcuts, browser bookmarks, or icons
- on the user's device as a service to third parties or for advertising
- purposes.
- </li>
-</ul>
-
-<p>
- Above right is an example notification ad that violates ad policy by
- providing ads through system level notification.
-</p>
-<p>
- Below right, the notification ad complies with policy because the
- nature of the notification is part of the explicit feature set of the app,
- and it also provides attribution of the origin app.
-</p>
-
-<h2 id="disclosure" style="clear:right">Disclosure of Ads to Users</h2>
-
-<p>
- It's important to sufficiently disclose to users how your app will use ads.
- You must make it easy for users to understand what ads will be shown in your
- app, where they will be shown, and what the associated behaviors are, if any.
- Further, you should ask for user consent and provide options for managing ads
- or opt-out. Here are some guidelines:
-</p>
-
-<ul>
- <li>
- <strong>Tell users about your ads</strong>—Create a simple,
- complete disclosure that tells users how your app uses ads, where the ads
- are shown, and how they can manage ad options. Take common-sense steps to
- make the disclosure as clear as possible.
- </li>
-
- <li>
- <div class="example-block good" style="width:213px;margin-left:.5em;">
- <div class="heading">Disclosure in Terms</div>
- <img src="{@docRoot}images/gp-policy-ads-terms.png">
- </div>
- <div class="example-block bad" style="width:213px;">
- <div class="heading">Disclosure is hidden</div>
- <img src="{@docRoot}images/gp-policy-ads-eula-violation.png">
- </div>
- <strong>Make sure users know</strong>—Present your ads disclosure
- is an easy-to-see location, rather than hiding it where users are not
- likely to find it.
- </li>
-
- <li>
- <strong>Ask for consent (opt-in) at launch</strong>—Where possible,
- include your ads disclosure in the app description as well as in an Ads
- Terms, End User License Agreement (EULA), or similar document. Display the
- terms at first launch and ask for the user's consent before continuing to
- the app.
- </li>
-</ul>
-
-<p>
- A recommended approach is to provide an ads disclosure in an End-User License
- Agreement (EULA). The disclosure should be clear and succinct and displayed
- in a modal dialog that asks the user to agree to the terms before using the
- app.
-</p>
-
-<p>
- Above left is an example of ads disclosure that is hidden in a long EULA. The
- disclosure information itself is not clearly indicated in the document text
- and it's not visible unless the user happens to scroll down far enough in the
- EULA.
-</p>
-<p>
- Above right shows an approach that presents the disclosure in an obvious
- and clear manner in a EULA and a dedicated Terms agreement.
-</p>
-
-
-<h2 id="impersonation">Impersonation of System UI</h2>
-
-
-
-
-
-
-
-
-<p>
- Ads must not simulate or impersonate the user interface of any app, or
- notification and warning elements of an operating system. Your app must not
- display any ad that attempts to impersonate or represent a
- system function or UI component. If such an ad is displayed in your app, your
- app will be in violation of policy and subject to suspension. Here are some
- guidelines:
-</p>
-
-<ul>
- <li>
- <strong>No fake app UI notifications</strong>—Ads should not impersonate
- the interface of an application for advertising purposes.
- </li>
- <li>
- <strong>No fake system dialogs or warnings</strong>—Any ad that
- presents itself as a system dialog or warning and asks for user input is in
- violation of Google Play policies.
- </li>
-
- <li>
- <strong>No fake app updates</strong>—Ads should not impersonate
- system UI for app updates.
- </li>
-</ul>
-
-<div class="example-block bad" style="width:213px;">
- <div class="heading">Ad impersonates app UI</div>
- <img src="{@docRoot}images/gp-policy-ads-impersonate-violation-app-ui.png">
-</div>
-<div class="example-block bad" style="width:213px;">
- <div class="heading">Ad impersonates system warning</div>
- <img src="{@docRoot}images/gp-policy-ads-impersonate-violation-sys-warning.png">
-</div>
-<div class="example-block bad" style="width:213px;">
- <div class="heading">Ad impersonates system dialog</div>
- <img src="{@docRoot}images/gp-policy-ads-impersonate-violation.png">
-</div>
-<p style="clear:both">
- Above are examples of impersonations — a pop-up ad that impersonates a
- system dialog, an ad that impersonates a system warning, and an ad that impersonates
- an application UI. All of these are in violation of policy.
-</p>
-
-
-<h2 id="adwalls">Adwalls and Interstitial Ads</h2>
-
-<p>
- If your app uses adwalls to drive affiliate traffic, those adwalls must not
- force the user to click on ads or submit personal information for advertising
- purposes before using the app.
-</p>
-
-<p>
- Forcing a user action in an adwall is not only a poor user experience, it is
- a violation of Google Play policies.
-</p>
-
-<p>
- For this reason, <strong>all adwalls must give the user the option to
- cancel</strong> or otherwise dismiss the ad without penalty. Interstitial ads
- may only be displayed inside of the app they came with. Forcing the user to
- click on ads or submit personal information for advertising purposes in order
- to fully use an app is prohibited.
-</p>
-
-<div class="example-block bad" style="width:213px;">
- <div class="heading">Interstitial, modal ad</div>
- <img src="{@docRoot}images/gp-policy-ads-interstitial-violation.png">
-</div>
-
-<div class="example-block good" style="width:213px;">
- <div class="heading">Adwall lets user cancel</div>
- <img src="{@docRoot}images/gp-policy-ads-paywall.png">
-</div>
-
-<div class="example-block bad" style="width:213px;">
- <div class="heading">Adwall forces user action</div>
- <img src="{@docRoot}images/gp-policy-ads-paywall-violation.png">
-</div>
-
-<p style="clear:both">
- At left is an example of an app that requires the user to click through the
- ad to fully use the app. This is a violation of policy.
-</p>
-
-<p>
- The center example demonstrates an adequate option to let the user dismiss
- the ad wall easily by cancelling. This is not a violation of policy.
-</p>
-
-<p>
- At right is an example of an interstitial, modal ad that is displayed outside
- of the app. This is a violation of policy.
-</p>
-
-<h2 id="interfering" style="clear:right;">Interfering with Apps and Third-Party Ads</h2>
-
-<p>
- Ads associated with your app <strong>must not interfere</strong> with other
- apps or their ads.
-</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/policies/index.jd b/docs/html/distribute/googleplay/policies/index.jd
deleted file mode 100644
index fb46055..0000000
--- a/docs/html/distribute/googleplay/policies/index.jd
+++ /dev/null
@@ -1,59 +0,0 @@
-page.title=Google Play Policies and Guidelines
-page.metaDescription=Guidelines and tips for creating apps that comply with Google Play content and distribution policies.
-@jd:body
-
-<p>
- Before publishing your apps on Google Play, take a few minutes to read and
- understand the content and distribution policies that apply to all apps
- in the store. These policies help to keep Android and Google Play an enjoyable
- and trusted platform for content consumers and developers alike.
-</p>
-
-<p>
- The documents below highlight important policy areas and provide tips to help
- you create policy-compliant apps. You'll also find examples and guidance on common
- policy questions that can help your app stay clear of practices that can result in
- low ratings or even suspensions from the store.
-</p>
-
-<p>
- For complete information about Google Play policies, please see the full
- <a href="http://play.google.com/about/developer-content-policy.html" target=
- "_policies">Developer Program Policies</a> and <a href=
- "http://play.google.com/about/developer-distribution-agreement.html" target=
- "_policies">Developer Distribution Agreement</a> documents.
-</p>
-
-<div class="vspace size-1">
-
-</div>
-<div class="layout-content-row">
- <div class="layout-content-col span-4">
- <h4>
- Spam
- </h4>
- <p>
- Make sure that your app does not present content that is unwanted,
- deceptive, repetitive, or unrelated to the core function of the app.
- </p><a href="{@docRoot}distribute/googleplay/policies/spam.html">Learn more »</a>
- </div>
- <div class="layout-content-col span-4">
- <h4>
- Intellectual Property
- </h4>
- <p>
- Tips and examples of how to use intelletual property (IP) properly,
- including when to ask permission to use someone else's copyright or
- trademark.
- </p><a href="{@docRoot}distribute/googleplay/policies/ip.html">Learn more »</a>
- </div>
- <div class="layout-content-col span-4">
- <h4>
- Ads
- </h4>
- <p>
- Make sure that the ads displayed in your app follow the Google Play Content
- Policy and meet the maturity rating that you have selected for your app.
- </p><a href="{@docRoot}distribute/googleplay/policies/ads.html">Learn more »</a>
- </div>
-</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/policies/ip.jd b/docs/html/distribute/googleplay/policies/ip.jd
deleted file mode 100644
index 0d1f68d..0000000
--- a/docs/html/distribute/googleplay/policies/ip.jd
+++ /dev/null
@@ -1,345 +0,0 @@
-page.title=Intellectual Property
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
- <h2>In This Document</h2>
- <ol>
- <li><a href="#copyright">Copyright Infringement</a></li>
- <li><a href="#impersonation">Impersonation</a></li>
- <li><a href="#trademarks">Trademark Infringement</a></li>
- <li><a href="#other">DDA 4.4 Prohibited Actions</a></li>
- </ol>
-
- <h2>More Resources</h2>
- <ol>
- <li><a href="http://play.google.com/about/developer-content-policy.html"
- target="_policies">Developer Program Policies</a></li>
- <li><a href="http://www.android.com/us/developer-distribution-agreement.html#showlanguages"
- target="_policies">Developer Distribution Agreement</a></li>
- </ol>
-</div>
-</div>
-
-<p>
- Google Play policies protect your intellectual property (IP) as well as that
- of other app developers and content creators in the store. The policies and
- their enforcements help ensure proper use of copyright, trademarks, and
- developer identity in Google Play.
-</p>
-
-<p>
- As an app developer, these IP policies benefit you. At the same time, it's
- your responsibility to ensure that your app does not violate the IP of other
- developers or content creators. Violations of IP-related policy may result in
- suspension of your apps from the store and termination of your developer
- account.
-</p>
-
-<p>
- This document introduces several key areas of IP-related policy that you
- should understand before publishing on Google Play. In each area you'll find
- best practices and examples to help you avoid common types of mistakes and
- violations.
-</p>
-
-<p>
- For more information about Google Play policies that apply to your apps and
- content, please see the <a href=
- "http://play.google.com/about/developer-content-policy.html" target=
- "_policies">Developer Program Policies</a> and <a href=
- "http://play.google.com/about/developer-distribution-agreement.html" target=
- "_policies">Developer Distribution Agreement</a>.
-</p>
-
-
-
-<h2 id="copyright">Copyright Infringement</h2>
-
-<p>
- Copyright is the legal right granted to an author or creator for a literary,
- dramatic or artistic piece of work. As soon as you create an original piece
- of work and fix it in a tangible medium, the work is automatically protected
- by copyright law and you are the owner of the copyright. Likewise, when other
- people create content, they may own the copyrights for those works.
-</p>
-
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>How to report infringements</h2>
-<p>If you feel your copyright is being infringed, you may file a Digital Millenium
- Copyright Act (DMCA) request. Please see <a
- href="http://support.google.com/bin/request.py?&product=androidmarket&contact_type=lr_dmca"
- target="_policies">copyright procedures</a> for more information.</p>
-</div>
-</div>
-
-<p>
- Copyright infringement is an improper or unauthorized use of a copyrighted
- work. If you publish an app in Google Play that uses another party's copyrighted
- works improperly or without permission, your apps can be suspended and your
- developer account terminated.
-</p>
-
-<p>
- As you design your app and prepare for publishing, make sure to review Google
- Play policies and analyze all of your content. If your app uses or links to
- another party's original work, make sure that your app is not infringing on
- copyright. Not all uses of another party’s work are infringements on
- copyright, and the rules vary by country and can be complex.
-</p>
-
-<p>
- If you are unsure whether your use of another party's work infringes on a
- copyright, consider getting legal advice before publishing, or simply request
- permission to use the work from the copyright owner.
-</p>
-
-<p>
- Here are some guidelines to help you avoid copyright infringement policy
- violations:
-</p>
-
-<ul>
- <li>
- <strong>Respect copyright laws</strong>—Do not let your app infringe
- on the copyrights of others. That includes linking to other apps or web
- sites that contain obviously infringing material (please refer to the <a href="
- {@docRoot}distribute/googleplay/policies/spam.html#webview-spam">Spam in WebViews</a> guidelines), and using icons or images that are obvious infringements.
- </li>
-
- <li>
- <strong>Know your app's content</strong>—Before you publish, look
- for content that may be protected by trademark or copyright in your app
- and get legal advice if necessary. Protected work could typically include
- product names, brands, images, music, and similar works.
- </li>
-
- <li>
- <strong>Create original work</strong>—If you’re not sure whether
- something will violate another party's copyright, the safest approach is to
- create something that's completely original, such as images or audio
- that you’ve created yourself. When you create your own original content,
- you rarely have to worry about infringing on existing copyright.
- </li>
-
- <li>
- <strong>Ask permission to use copyrighted work</strong>—If you want
- to use another party's copyrighted work in your app, you should ask for
- permission from the work's creator or copyright owner and include
- appropriate copyright attribution.
- </li>
-</ul>
-
-<p>
- A common misunderstanding is believing that your app may use copyrighted
- content without permission, provided that you clearly indicate that your app
- is not the "official" app that readers may be familiar with. That is not the
- case. Even if you let users know that your app is "unofficial", it still
- violates Google Play policies if it uses or links to copyrighted content
- without permission. Also, this type of "unofficial" app may violate <a
- href="#impersonation">impersonation policies</a>.
-</p>
-
-<p>
- The example app below shows an app that uses screenshots/images of known
- artists without their authorization and lists popular songs. The combination
- of these may induce users to download music ringtones that infringe on
- copyright. This is a violation of Google Play policy.
-</p>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
- <div class="heading">Images and downloads that violate copyright</div>
- <img src="{@docRoot}images/gp-policy-ip-copyright-violation.png">
-</div>
-
-
-<h2 id="impersonation">Impersonation</h2>
-
-<p>
- Impersonation is when an app attempts to imply a relationship to another app
- or developer, where no relationship actually exists.
-</p>
-
-<p>
- For example, if your app displays the brand, icon, or title from another app
- in order to get to users to download your app, you are leading users to
- believe that your app is developed by the same entity as the other app and
- offers similar content or experience. This is an impersonation of the other
- app and developer, and it is a violation of Google Play policy. If you
- publish apps that violate impersonation policies, your apps can be suspended
- and your developer account terminated.
-</p>
-
-<p>
- No matter what type of app you offer or what your motivation, don’t try to
- imply an endorsement or relationship to another company or product where none
- exists. Don’t try to establish your app as the "official" version of another
- party's work by prominently featuring their brand names or trademarks in your
- app title or description.
-</p>
-
-<p>
- Even if your app description states that your app is an "unofficial" version,
- the use of the other app's branding, trademarks, and other content still can
- violate policy by presenting content that isn’t yours.
-</p>
-
-<p>
- Here are some guidelines:
-</p>
-
-<ul>
- <li>
- <strong>Don't pretend to be someone else</strong>— Don't represent
- that your content is produced by another company or organization if that is
- not the case.
- </li>
-
- <li>
- <strong>Don't support infringing sites or apps</strong>— Don't divert
- users or provide links to any other site that mimics Google Play or
- represents itself as another application or service.
- </li>
-
- <li>
- <strong>Don't use another app's branding</strong>— Don’t try to pass
- off your app as the official version of someone else’s property by using a
- person or entity (or brand) name in your app title or description.
- </li>
-</ul>
-
-<p>
- Below is an example of an "unofficial" app that violates Google Play policy
- by impersonating another company and an existing product. Specifically:
-</p>
-
-<ul>
- <li>The example app has a name and icon that appear to be impersonating an
- existing product.
- </li>
-
- <li>The example developer name implies an endorsement or relationship to
- another company and their products where none exists.
- </li>
-</ul>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
- <div class="heading">App name, icon, and developer name that impersonate another</div>
- <img src="{@docRoot}images/gp-policy-ip-impersonation-violation.png">
-</div>
-
-
-<h2 id="trademarks">Trademark Infringement</h2>
-
-<p>
- A trademark is a brand that uniquely identifies a product and distinguishes
- it from other products. It can be a word, name, symbol, or combination of
- those that is intended to identify the source of the product. A trademark is
- specifically acquired by a company or other entity through a legal process
- and once acquired gives the owner exclusive rights to the trademark usage.
-</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>How to report infringements</h2>
-<p>If you feel your trademark is being infringed, you can request a content review.
-See <a href="http://support.google.com/bin/static.py?&ts=1114905&page=ts.cs"
-target="_policies">Removing content from Google</a> for more information.</p>
-</div>
-</div>
-
-<p>
- Trademark infringement is improper or unauthorized use of a trademark. Google
- Play policies prohibit apps that infringe trademarks. If you publish apps in
- Google Play that use another party's trademarks, your apps can be suspended
- and your developer account terminated.
-</p>
-
-<p>
- As you design your app and prepare for publishing, make sure to review Google
- Play policies and analyze all of your content. If your app uses a trademark
- not owned by you, or if you are not sure whether a brand is a trademark, you
- should get legal advice before publishing. As with copyright, the rules vary
- by country and can be complex.
-</p>
-
-<p>
- Here are some guidelines for avoiding trademark infringement policy
- violations:
-</p>
-
-<ul>
- <li>
- <strong>Understand and follow trademark laws</strong>—Don't let your
- app infringe on the trademarks of others.
- </li>
-
- <li>
- <strong>Know your app's content</strong>—Before you publish, look for
- brands and potential trademarks used in your app and store listing and get
- legal advice if necessary.
- </li>
-
- <li>
- <strong>Use a distinct name</strong>—Don't give your app a name that
- is confusingly similar to another company's trademark.
- </li>
-
- <li>
- <strong>Don't use trademarks to imply a relationship</strong>—Don't
- describe your app using another company's trademarks in a way that implies
- an endorsement by or affiliation with the other company.
- </li>
-
- <li>
- <strong>Use a distinct app icon and logo</strong>—Don't use a
- modified version of another company’s trademarked logo.
- </li>
-</ul>
-
-<p>
- A common misunderstanding is believing that your app may use a brand or
- trademark without permission, provided you clearly indicate that the app is
- not the "official" or original app. That is not the case. Even if you let
- users know that your app is "unofficial", it still violates Google Play
- policies if it uses another party's trademarks. Also, this type of
- "unofficial" app may violate <a href="#impersonation">impersonation
- policies</a>.
-</p>
-
-<p>
- Below is an example app that violates Google Play policies by infringing on
- another party's trademarks. Specifically:
-</p>
-
-<ul>
- <li>The example app name is confusingly similar to another party's trademark.</li>
- <li>The example app icon is a modified version of a another party's logo.</li>
-</ul>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
- <div class="heading">App name and icon that infringe trademarks</div>
- <img src="{@docRoot}images/gp-policy-ip-trademark-violation.png">
-</div>
-
-
-<h2 id="other">DDA 4.4 Prohibited Actions</h2>
-
-<p>
- When you publish an app on Google Play, you agree to the terms of the
- Developer Distribution Agreement (DDA). Section 4.4 of the DDA prohibits certain
- types of actions on your part. For reference, you agree that you will not
- engage in any activity with the Market, including the development or
- distribution of Products, that interferes with, disrupts, damages, or
- accesses in an unauthorized manner the devices, servers, networks, or other
- properties or services of any third party including, but not limited to,
- Android users, Google or any mobile network operator.
-</p>
-
-<p>
- For details, please refer to the complete <a href=
- "http://play.google.com/about/developer-distribution-agreement.html" target=
- "_policies">Developer Distribution Agreement</a>.
-</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/policies/spam.jd b/docs/html/distribute/googleplay/policies/spam.jd
deleted file mode 100644
index f4d303c..0000000
--- a/docs/html/distribute/googleplay/policies/spam.jd
+++ /dev/null
@@ -1,421 +0,0 @@
-page.title=Spam
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
- <h2>In This Document</h2>
- <ol>
- <li><a href="#keyword-spam">Spam in App Title and Description</a></li>
- <li><a href="#ratings">Spam in Ratings and Reviews</a></li>
- <li><a href="#webview-spam">Spam in WebViews</a></li>
- <li><a href="#wizard-spam">Spam from Wizards</a></li>
- <li><a href="#message-spam">Spam in Messaging</a></li>
- </ol>
-
- <h2>More Resources</h2>
- <ol>
- <li><a href="http://play.google.com/about/developer-content-policy.html" target="_policies">Developer Program Policies</a></li>
- <li><a href="http://play.google.com/about/developer-distribution-agreement.html" target="_policies">Developer Distribution Agreement</a></li>
- </ol>
-</div>
-</div>
-
-<p>
- Google Play policies prohibit spam, to help ensure the best experience for
- Android users. Please do not publish deceptive, repetitive, or irrelevant
- content on Google Play. Not only will it lower your app's rating and cause
- negative reviews, it can result in your app being suspended or your developer
- account terminated.
-</p>
-
-<p>
- As an app developer, it is your responsibility to ensure that your apps are
- free from spam and conform to the Google Play policies highlighted in this
- document. Before you publish, make sure that you understand what is
- considered spam on Google Play and check your apps for violations, even those
- that might be inadvertent. The sections below highlight best practices and
- common spam examples to help you avoid the most common types of policy
- violations.
-</p>
-
-<p>
- For more information about Google Play policies that apply to your apps and
- content, please see the <a href=
- "http://play.google.com/about/developer-content-policy.html" target=
- "_policies">Developer Program Policies</a> and <a href=
- "http://play.google.com/about/developer-distribution-agreement.html" target=
- "_policies">Developer Distribution Agreement</a>.
-</p>
-
-
-<h2 id="keyword-spam">Spam in App Title and Description</h2>
-
-<p>
- When you publish an app on Google Play, you should pay special attention to
- the app's title and description in its store listing. Those fields are
- important because they make your app recognizable to users, and they help to
- drive downloads by highlighting what's great about your app. A memorable
- title and compelling description are essential to effective marketing, but
- you should realize that these must follow Google Play policies, just as your
- app content must do.
-</p>
-
-<p>
- Many developers unknowingly violate spam policy in their app titles and
- descriptions in ways that are easy to avoid. In general, you can
- avoid spam violations in your app title and description by following these
- best practices:
-</p>
-
-<ul>
- <li>
- <strong>Highlight what's great about your app</strong>—Share
- interesting and exciting facts about your app with users. Help users
- understand what makes your app special.
- </li>
-
- <li>
- <strong>Describe your app accurately</strong>—Make sure the title
- and description describe the app function and user experience accurately.
- </li>
-
- <li>
- <strong>Don't use repetitive keywords</strong>—Avoid keywords that
- are repetitive or excessive.
- </li>
-
- <li>
- <strong>Don't include unrelated keywords or references</strong> —
- Your description should not be loaded with irrelevant keywords in an
- attempt to manipulate ranking or relevancy.
- </li>
-
- <li>
- <strong>Keep it brief</strong>—Keep the description succinct and
- straightforward. Shorter descriptions tend to give a better user experience
- on devices with smaller displays. Excessive length, detail, or repetition
- can violate spam policy.
- </li>
-</ul>
-
-<p>
- Here's an example app title and description that follows best practices and
- does not violate Google Play spam policies.
-</p>
-
-<div class="example-block good" style="width:100%;float:none;margin:.5em auto 2em 0;">
- <div class="heading">Best practice: App description</div>
- <table>
- <tr>
- <td>App Title:</td>
- <td>Kids puzzle: Identify Turtles</td>
- </tr>
- <tr>
- <td style="white-space:nowrap;">App Description:</td>
- <td>
- <p>This is the perfect app to have a good time with your children. It
- is designed to help kids learn different species of turtles through
- cute pictures and amusing puzzle games.</p>
- <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have
- your child drag images around the screen to fit them into the shaded
- region. Phonics is also utilized, as a child can also tap the word
- below the image and hear the name pronounced.</p>
- </td>
- </tr>
- </table>
-</div>
-
-<p>
- The sections below highlight common types of policy violations in an app
- title and description, illustrated with variations on the best practice
- example.
-</p>
-
-<h3 id="repetitive-keywords">Repetitive keywords</h3>
-
-<p>
- Your app description should not include keywords that are repetitive or excessive.
-</p>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
- <div class="heading">Description includes repetitive keywords</div>
- <table>
- <tr>
- <td>App Title:</td>
- <td>Kids puzzle: Identify Turtles</td>
- </tr>
- <tr>
- <td style="white-space:nowrap;">App Description:</td>
- <td>
- <p>This is the perfect app to have a good time with your children. It is
- designed to help kids learn different species of turtles through cute
- pictures and amusing puzzle games.</p>
- <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have your
- child drag images around the screen to fit them into the shaded region.
- Phonics is also utilized, as a child can also tap the word below the image
- and hear the name pronounced.</p>
- <p style="border:2px solid red;">KEYWORDS: game, games, fun, funny, child,
- children, kid, kids, puzzle, puzzle games, sound, turtle, turtles, sea turtles,
- turtles, turtle, turtles, tortoise, tortoises, tortoise, tortoise, turtles,
- turtles, turtles, turtles, tortoises, tortoise</p>
- </td>
- </tr>
- </table>
-</div>
-
-<h3 id="unrelated-keywords">Unrelated keywords or references</h3>
-
-<p>
- The description should not be loaded with irrelevant keywords in an attempt
- to manipulate ranking or relevancy in Google Play search results.
-</p>
-
-<p>
- For example, if your app has nothing to do with Lady Gaga, then she shouldn’t
- be included in your description. Also, do not add highly searched, irrelevant
- keywords that are unrelated to the function of the app. This is in breach of
- policy.
-</p>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
- <div class="heading">Description includes unrelated keywords or references</div>
- <table>
- <tr>
- <td>App Title:</td>
- <td>Kids puzzle: Identify Turtles</td>
- </tr>
- <tr>
- <td style="white-space:nowrap;">App Description:</td>
- <td>
- <p>This is the perfect app to have a good time with your children. It is designed to
- help kids learn different species of turtles through cute pictures and amusing puzzle
- games.</p>
- <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have your child drag
- images around the screen to fit them into the shaded region. Phonics is also utilized,
- as a child can also tap the word below the image and hear the name pronounced.</p>
- <p style="border:2px solid red;">This game is as addictive as Angry Birds, more social
- than Facebook and Twitter, and has a soundtrack reminiscent of Katy Perry and Lady
- Gaga.</p>
- <p style="border:2px solid red;">KEYWORDS: Angry Birds, Facebook, Twitter, Katy Perry,
- Lady Gaga</p>
- </td>
- </tr>
- </table>
-</div>
-
-<h3 id="excessive-detail">Excessive detail, references to your other apps</h3>
-
-<p>
- Your app description should avoid excessive detail and references to your
- other apps or products. For example, you should not list all of the details
- of content included in the app or its various components, as shown in the
- example below. Also, the description should not include any references to
- other apps you’ve published.
-</p>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
- <div class="heading">Description includes excessive detail, references to your other apps</div>
- <table>
- <tr>
- <td>App Title:</td>
- <td>Kids puzzle: Identify Turtles</td>
- </tr>
- <tr>
- <td style="white-space:nowrap;">App Description:</td>
- <td>
- <p>This is the perfect app to have a good time with your children. It is designed
- to help kids learn different species of turtles through cute pictures and amusing
- puzzle games.</p>
- <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have your child
- drag images around the screen to fit them into the shaded region. Phonics is also
- utilized, as a child can also tap the word below the image and hear the name
- pronounced.</p>
- <p style="border:2px solid red;">Turtles included in the app: Alligator
- Snapping Turtle, Asian Box Turtle, Bog Turtle, Common Musk Turtle, Common Snapping
- Turtle, Diamondback Terrapin, Eastern Box Turtle, Eastern Mud Turtle, Eastern Painted
- Turtle, False Map Turtle, Florida Pond Cooter, Florida Softshell Turtle, Green Sea
- Turtle, Map Turtle, Matamata Ornate Box Turtle, Red-bellied Side-necked Turtle,
- Red-eared Slider, Smooth Softshell Turtle, Spiny Softshell Turtle, Spotted Turtle,
- Western Painted Turtle, Wood Turtle, Yellow-bellied Slider</p>
- <p style="border:2px solid red;">If you like this app try our other free apps:<br />
- ★ Fun Zoo<br />
- ★ CD Guns<br />
- ★ Dessert House<br />
- ★ Playground<br />
- ★ 578 Weapons</p>
- </td>
- </tr>
- </table>
-</div>
-
-
-<h2 id="ratings">Spam in Ratings and Reviews</h2>
-
-<div class="example-block bad" style="width:440px;">
- <div class="heading">Inappropriate content in a review</div>
- <img src="{@docRoot}images/gp-policy-spam-negreview.png">
-</div>
-
-<p>
- Ratings and reviews are benchmarks of app quality and users depend on them to
- be authentic and relevant. As an app developer, you should not attempt to
- artificially influence your app's ratings and reviews or those of your
- competitor, such as by posting fake ratings or reviews or including spam
- content in app reviews. The sections below provide guidelines for rating and
- reviewing apps.
-</p>
-
-<p>
- So that you can stay in touch with any issues that users are having with your
- app, you should read through your ratings and reviews on a regular basis. If
- you choose to reply to reviews, make sure to keep your reply focused on the
- actual issues raised in the user's comments and do not ask for a higher
- rating.
-</p>
-
-<p>
- If you see an app or developer reply that doesn’t follow these guidelines,
- you can report it. See <a href=
- "http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113417&topic=2364761&ctx=topic"
- target="_policies">Inappropriate content in comments and applications</a> for
- more information.
-</p>
-
-<div class="example-block bad" style="margin-top:3em;width:213px;">
- <div class="heading">Soliciting ratings</div>
- <img src="{@docRoot}images/gp-policy-spam-reqrating.png">
-</div>
-
-<h3 id="fake-ratings">Fake or inappropriate ratings and reviews</h3>
-
-<p>
- To help ensure the quality of ratings and reviews, Google Play policies limit
- the ways that individuals can use ratings and reviews. In particular, note
- that it is a violation of policy to use ratings and reviews to influence the
- placement of any app in Google Play.
-</p>
-
-<p>
- As an app developer, make sure that you follow these guidelines:
-</p>
-
-<ul>
- <li>
- <strong>Don't try to manipulate ratings</strong>—Do not engage in
- attempts to manipulate the ratings, reviews, or ranking of your apps,
- either directly or indirectly, or by manipulating the ratings of your
- competitors. Do not attempt to artificially boost reviews, ratings, or
- installs through any means.
- </li>
-
- <li>
- <strong>Don't solicit ratings through incentives</strong>—Do not
- offer users any incentives to rate your app, such as offering rewards of
- any kind or tying app functionality to rating.
- </li>
-
- <li>
- <strong>Don't rate apps multiple times</strong>—Do not review or
- rate any app multiple times in an attempt to influence its placement in
- Google Play.
- </li>
-
- <li>
- <strong>Don't add improper content to reviews</strong>—Do not
- include affiliate, coupon, game codes, email addresses, or links to
- websites or other apps in your reviews. If you are responding to a user
- review, feel free to include references to helpful resources such as a
- support address or FAQ page.
- </li>
-</ul>
-
-<h3 id="solicited-ratings">Soliciting ratings from users</h3>
-
-<p>
- In general, <strong>do not offer incentives for ratings</strong>. You should
- not offer users incentives of any kind for rating your app (or any other app)
- on Google Play, and you should not tie your app's functionality or content to
- rating in any way.
-</p>
-
-<p>
- It's acceptable to ask users to rate your app without incentives, for
- example: "If you like this game, rate us in Google Play!" On the other hand,
- it's a policy violation to ask users to rate your app based on incentives,
- for example: "Rate this app and get 500 coins" or "Rate this app 5 stars and
- get you 500 coins!"
-</p>
-
-
-<h2 id="webview-spam" style="clear:right">Spam in WebViews</h2>
-
-<p>
- Apps published on Google Play should provide their own content. Do not
- publish an app whose primary function is to reproduce or frame someone else’s
- website (unless you have permission).
-</p>
-
-<p>
- Similarly, do not publish an app whose primary function is to drive affiliate
- traffic to a website. Although affiliate deals can exist where an app's
- primary purpose is delivering its own content or functionality, it's a
- violation of Google Play policies to publish an app whose primary (or
- only) purpose is to direct affiliate traffic to another website.
-</p>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
- <div class="heading">WebView spam</div>
- <table>
- <tr>
- <td>App Title:</td>
- <td>Kids puzzle: Desktop Browser for Turtoogle Game</td>
- </tr>
- <tr>
- <td>Developer:</td>
- <td>AAZZZ <span style="border:2px solid red;">(not affiliated with Turtoogle
- Inc.)</span></td>
- </tr>
- <tr>
- <td style="white-space:nowrap;">App Description:</td>
- <td>
- <p>Have you ever wanted to use the full, desktop web version of Turtoogle
- Game from your phone or tablet instead of the Turtoogle Game mobile app
- or Turtoogle Game mobile web site?</p>
- <p style="border:2px solid red;">This app lets you access Turtoogle Game
- on your Android device in the same way as you access the game on your
- desktop computer, and with all the same Turtoogle Game features.</p>
- </td>
- </tr>
- </table>
-</div>
-
-
-<h2 id="wizard-spam">Spam from Wizards</h2>
-
-<p>
- Apps that are created by an automated tool or wizard service must not be
- submitted to Google Play by the operator of that service on behalf of other
- persons. Such tools often produce too many duplicative or low-quality
- apps which crowd the higher-quality apps in the Play Store.
-</p>
-
-<p>
- Please be advised that apps created by an automated tool are only permissible
- if the app end-product complies with Google Play policies and is published in
- the Play Store through a developer account that is registered and owned by
- you.
-</p>
-
-
-<h2 id="message-spam">Spam in Messaging</h2>
-
-<p>
- Your app may not send SMS, email, or other messages on behalf of the user
- without providing the user with the ability to confirm the content and intended
- recipient.
-</p>
-
-<p>
- Google Play will aggressively remove applications that are found to send or
- modify SMS messages without user knowledge or consent.
-</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/promote/badge-files.jd b/docs/html/distribute/googleplay/promote/badge-files.jd
deleted file mode 100644
index 03ebd01..0000000
--- a/docs/html/distribute/googleplay/promote/badge-files.jd
+++ /dev/null
@@ -1,290 +0,0 @@
-page.title=Google Play Badge Files
-@jd:body
-
-
-
-
-<style>
-table tr td {border:0}
-</style>
-
-<p>The following links provide the Adobe® Illustrator® (.ai) file for the
-two Google Play badges.</p>
-
-<hr>
-<img src="{@docRoot}images/brand/en_generic_rgb_wo_60.png" alt="Get It On Google Play">
-
-<div style="clear:left"> </div>
-
-<div class="col-4" style="margin-left:0">
-
- <a href="{@docRoot}downloads/brand/v2/english_get.ai">English (English)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/amharic_get.ai">ኣማርኛ (Amharic)</a><br/>
-
- <a href="{@docRoot}downloads/brand/af_generic_rgb_wo.ai">Afrikaans (Afrikaans)</a><br/>
-<!--
- <a href="{@docRoot}downloads/brand/ar_generic_rgb_wo.ai">العربية (Arabic)</a><br/>
--->
- <a href="{@docRoot}downloads/brand/v2/belarusian_get.ai">Беларуская (Belarusian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/bulgarian_get.ai">български (Bulgarian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/catalan_get.ai">Català (Catalan)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/traditional_chinese_get.ai">中文 (中国) (Chinese)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/hongkong_chinese_get.ai">中文(香港) (Chinese Hong Kong)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/taiwan_chinese_get.ai">中文 (台灣) (Chinese Taiwan)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/croatian_get.ai">Hrvatski (Croatian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/czech_get.ai">Česky (Czech)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/danish_get.ai">Dansk (Danish)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/dutch_get.ai">Nederlands (Dutch)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/estonian_get.ai">Eesti keel (Estonian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/farsi_get.ai">فارسی (Farsi Persian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/filipino_get.ai">Tagalog (Filipino)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/finnish_get.ai">Suomi (Finnish)</a><br/>
-
-</div>
-
-<div class="col-4">
-
- <a href="{@docRoot}downloads/brand/v2/french_get.ai">Français (French)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/german_get.ai">Deutsch (German)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/greek_get.ai">Ελληνικά (Greek)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/hebrew_get.ai">עברית (Hebrew)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/hindi_get.ai">हिन्दी (Hindi)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/hungarian_get.ai">Magyar (Hungarian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/indonesian_get.ai">Bahasa Indonesia (Indonesian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/italian_get.ai">Italiano (Italian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/japanese_get.ai">日本語 (Japanese)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/kazakh_get.ai">Қазақ тілі (Kazakh)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/korean_get.ai">한국어 (Korean)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/latvian_get.ai">Latviski (Latvian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/lithuanian_get.ai">Lietuviškai (Lithuanian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/malay_get.ai">Bahasa Melayu (Malay)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/norwegian_get.ai">Norsk (Norwegian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/polish_get.ai">Polski (Polish)</a><br/>
-
-</div>
-
-<div class="col-4" style="margin-right:0">
-
- <a href="{@docRoot}downloads/brand/v2/portugal_portuguese_get.ai">Português (Portuguese)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/brazilian_portuguese_get.ai">Português Brasil (Portuguese Brazil)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/romanian_get.ai">Românã (Romanian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/russian_get.ai">Pусский (Russian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/serbian_get.ai">Српски / srpski (Serbian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/slovak_get.ai">Slovenčina (Slovak)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/slovenian_get.ai">Slovenščina (Slovenian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/spanish_get.ai">Español (Spanish)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/spanish_latam_get.ai">Español Latinoamérica (Spanish Latin America)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/swahili_get.ai">Kiswahili (Swahili)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/swedish_get.ai">Svenska (Swedish)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/thai_get.ai">ภาษาไทย (Thai)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/turkish_get.ai">Türkçe (Turkish)</a><br/>
-
- <a href="{@docRoot}downloads/brand/uk_generic_rgb_wo.ai">Українська (Ukrainian)</a><br/>
- <a href="{@docRoot}downloads/brand/vi_generic_rgb_wo.ai">Tiếng Việt (Vietnamese)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/zulu_get.ai">isiZulu (Zulu)</a><br/>
-
-</div>
-<div style="clear:left"> </div>
-
-
-
-
-
-
-
-
-
-<hr>
-<img src="{@docRoot}images/brand/en_app_rgb_wo_60.png" alt="Android App On Google Play">
-
-<div style="clear:left"> </div>
-
-<div class="col-4" style="margin-left:0">
-
- <a href="{@docRoot}downloads/brand/v2/english_app.ai">English (English)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/afrikaans_app.ai">Afrikaans (Afrikaans)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/amharic_app.ai">ኣማርኛ (Amharic)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/arabic_app.ai">العربية (Arabic)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/belarusian_app.ai">Беларуская (Belarusian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/bulgarian_app.ai">български (Bulgarian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/catalan_app.ai">Català (Catalan)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/traditional_chinese_app.ai">中文 (中国) (Chinese)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/hongkong_chinese_app.ai">中文(香港) (Chinese Hong Kong)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/taiwan_chinese_app.ai">中文 (台灣) (Chinese Taiwan)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/croatian_app.ai">Hrvatski (Croatian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/czech_app.ai">Česky (Czech)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/danish_app.ai">Dansk (Danish)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/dutch_app.ai">Nederlands (Dutch)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/estonian_app.ai">Eesti keel (Estonian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/farsi_app.ai">فارسی (Farsi Persian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/filipino_app.ai">Tagalog (Filipino)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/finnish_app.ai">Suomi (Finnish)</a><br/>
-
-</div>
-
-<div class="col-4">
-
- <a href="{@docRoot}downloads/brand/v2/french_app.ai">Français (French)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/german_app.ai">Deutsch (German)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/greek_app.ai">Ελληνικά (Greek)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/hebrew_app.ai">עברית (Hebrew)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/hindi_app.ai">हिन्दी (Hindi)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/hungarian_app.ai">Magyar (Hungarian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/indonesian_app.ai">Bahasa Indonesia (Indonesian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/italian_app.ai">Italiano (Italian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/japanese_app.ai">日本語 (Japanese)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/korean_app.ai">한국어 (Korean)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/latvian_app.ai">Latviski (Latvian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/lithuanian_app.ai">Lietuviškai (Lithuanian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/malay_app.ai">Bahasa Melayu (Malay)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/norwegian_app.ai">Norsk (Norwegian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/polish_app.ai">Polski (Polish)</a><br/>
-
-
-</div>
-
-<div class="col-4" style="margin-right:0">
-
- <a href="{@docRoot}downloads/brand/v2/portugal_portuguese_app.ai">Português (Portuguese)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/brazilian_portuguese_app.ai">Português Brasil (Portuguese Brazil)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/romanian_app.ai">Românã (Romanian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/russian_app.ai">Pусский (Russian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/serbian_app.ai">Српски / srpski (Serbian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/slovak_app.ai">Slovenčina (Slovak)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/slovenian_app.ai">Slovenščina (Slovenian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/spanish_app.ai">Español (Spanish)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/spanish_latam_app.ai">Español Latinoamérica (Spanish Latin America)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/swahili_app.ai">Kiswahili (Swahili)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/swedish_app.ai">Svenska (Swedish)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/thai_app.ai">ภาษาไทย (Thai)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/turkish_app.ai">Türkçe (Turkish)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/ukranian_app.ai">Українська (Ukrainian)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/vietnamese_app.ai">Tiếng Việt (Vietnamese)</a><br/>
-
- <a href="{@docRoot}downloads/brand/v2/zulu_app.ai">isiZulu (Zulu)</a><br/>
-
-</div>
-<div style="clear:left"> </div>
-
-
-
-
-
-
-<h2>Guidelines</h2>
-
- <ul>
- <li>Do not modify the color, proportions, spacing or any other aspect of the badge image.
- </li>
- <li>When used alongside logos for other application marketplaces, the Google Play logo
- should be of equal or greater size.</li>
- <li>When used online, the badge should link to either:
- <ul>
- <li>A list of products published by you, for example:<br />
- <span style="margin-left:1em;">http://play.google.com/store/search?q=<em>publisherName</em></span>
- </li>
- <li>A specific app product details page within Google Play, for example:<br />
- <span style="margin-left:1em;">http://play.google.com/store/apps/details?id=<em>packageName</em></span>
- </li>
- </ul>
- </li>
- </ul>
-
-<p>For more information, see the
-<a href="{@docRoot}distribute/googleplay/promote/brand.html#brand-google_play">Brand
-Guidelines</a>.
-
-
-<p>To quickly create a badge that links to your apps on Google Play,
-use the <a
-href="{@docRoot}distribute/googleplay/promote/badges.html">Googe Play badge generator</a>.</p>
-
-
-
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/promote/badges.jd b/docs/html/distribute/googleplay/promote/badges.jd
deleted file mode 100644
index 9a32921..0000000
--- a/docs/html/distribute/googleplay/promote/badges.jd
+++ /dev/null
@@ -1,355 +0,0 @@
-page.title=Google Play Badges
-@jd:body
-
-<p itemprop="description">Google Play badges allow you to promote your app with official branding
-in your online ads, promotional materials, or anywhere else you want a link to your app.</p>
-
-<p>In the form below,
-input your app's package name or publisher name, choose the badge style,
-click <em>Build my badge</em>, then paste the HTML into your web content.</p>
-
-<p>If you're creating a promotional web page for your app, you should also use the
-<a href="{@docRoot}distribute/promote/device-art.html">Device Art Generator</a>, which quickly
-wraps your screenshots in real device artwork.</p>
-
-<p>For guidelines when using the Google Play badge and other brand assets,
-see the <a href="{@docRoot}distribute/googleplay/promote/brand.html#brand-google_play">Brand
-Guidelines</a>.</p>
-
-<style type="text/css">
-
-form.button-form {
- margin-top:2em;
-}
-
-/* the label and input elements are blocks that float left in order to
- keep the left edgets of the input aligned, and IE 6/7 do not fully support "inline-block" */
-label.block {
- display: block;
- float: left;
- width: 100px;
- padding-right: 10px;
-}
-
-input.text {
- display: block;
- float: left;
- width: 250px;
-}
-
-div.button-row {
- white-space:nowrap;
- min-height:80px;
-}
-
-div.button-row input {
- vertical-align:middle;
- margin:0 5px 0 0;
-}
-
-#jd-content div.button-row img {
- margin: 0;
- vertical-align:middle;
-}
-
-</style>
-
-<script type="text/javascript">
-
-// locales for which we have the 'app' badge
-var APP_LANGS = ['it','pt-br','pt-pt','nl','ko','ja','fr','es','es-419','en','de'];
-
-// variables for creating 'try it out' demo button
-var imagePath = "https://developer.android.com/images/brand/"
-var linkStart = "<a href=\"https://play.google.com/store/";
-var imageStart = "\">\n"
- + " <img alt=\"";
- // leaves opening for the alt text value
-var imageSrc = "\"\n src=\"" + imagePath;
- // leaves opening for the image file name
-var imageEnd = ".png\" />\n</a>";
-
-// variables for creating code snippet
-var linkStartCode = "<a href=\"https://play.google.com/store/";
-var imageStartCode = "\">\n"
- + " <img alt=\"";
- // leaves opening for the alt text value
-var imageSrcCode = "\"\n src=\"" + imagePath;
- // leaves opening for the image file name
-var imageEndCode = ".png\" />\n</a>";
-
-/** Generate the HTML snippet and demo based on form values */
-function buildButton(form) {
- var lang = $('#locale option:selected').val();
- var selectedValue = lang + $('form input[type=radio]:checked').val();
- var altText = selectedValue.indexOf("generic") != -1 ? "Get it on Google Play" : "Android app on Google Play";
-
- if (form["package"].value != "com.example.android") {
- $("#preview").show();
- var packageName = escapeHTML(form["package"].value);
- $("#snippet").show().html(linkStartCode + "apps/details?id=" + packageName
- + imageStartCode + altText + imageSrcCode
- + selectedValue + imageEndCode);
- $("#button-preview").html(linkStart + "apps/details?id=" + packageName
- + imageStart + altText + imageSrc
- + selectedValue + imageEnd);
-
- // Send the event to Analytics
- _gaq.push(['_trackEvent', 'Distribute', 'Create Google Play Badge', 'Package ' + selectedValue]);
- } else if (form["publisher"].value != "Example, Inc.") {
- $("#preview").show();
- var publisherName = escapeHTML(form["publisher"].value);
- $("#snippet").show().html(linkStartCode + "search?q=pub:" + publisherName
- + imageStartCode + altText + imageSrcCode
- + selectedValue + imageEndCode);
- $("#button-preview").html(linkStart + "search?q=pub:" + publisherName
- + imageStart + altText + imageSrc
- + selectedValue + imageEnd);
-
- // Send the event to Analytics
- _gaq.push(['_trackEvent', 'Distribute', 'Create Google Play Badge', 'Publisher ' + selectedValue]);
- } else {
- alert("Please enter your package name or publisher name");
- }
- return false;
-}
-
-/** Listen for Enter key */
-function onTextEntered(event, form, me) {
- // 13 = enter
- if (event.keyCode == 13) {
- buildButton(form);
- }
-}
-
-/** When input is focused, remove example text and disable other input */
-function onInputFocus(object, example) {
- if (object.value == example) {
- $(object).val('').css({'color' : '#000'});
- }
- $('input[type="text"]:not(input[name='+object.name+'])',
- object.parentNode).attr('disabled','true');
- $('#'+object.name+'-clear').show();
-}
-
-/** When input is blured, restore example text if appropriate and enable other input */
-function onInputBlur(object, example) {
- if (object.value.length < 1) {
- $(object).attr('value',example).css({'color':'#ccc'});
- $('input[type="text"]', object.parentNode).removeAttr('disabled');
- $('#'+object.name+'-clear').hide();
- }
-}
-
-/** Clear the form to start over */
-function clearLabel(id, example) {
- $("#preview").hide();
- $('#'+id+'').html('').attr('value',example).css({'color':'#ccc'});
- $('input[type="text"]', $('#'+id+'').parent()).removeAttr('disabled');
- $('#'+id+'-clear').hide();
- return false;
-}
-
-/** Switch the badge urls for selected language */
-function changeBadgeLang() {
- var lang = $('#locale option:selected').val();
-
- // check if we have the 'app' badge for this lang and show notice if not
- $("div.button-row.error").remove(); // remove any existing instance of error message
- if ($.inArray(lang,APP_LANGS) == -1) {
- $("div.button-row.app").hide();
- $("div.button-row.app").after('<div class="button-row error"><p class="note" style="margin:1em 0 -1em">'
- + 'Sorry, we currently don\'t have the '
- + '<em>Android app on Google Play</em> badge translated for '
- + $("select#locale option[value="+lang+"]").attr("title")
- + '.<br>Please check back later or instead use the <em>Get it on Google Play</em> badge below.'
- + '</p></div>');
- } else {
- $("div.button-row.app").show(); // show the 'app' badge row
- }
-
- $('.button-row img').each(function() {
- var id = $(this).parent().attr('for');
- var imgName = lang + $('input#'+id).attr('value') + '.png';
- var lastSlash = $(this).attr('src').lastIndexOf('/');
- var imgPath = $(this).attr('src').substring(0, lastSlash+1);
- $(this).attr('src', imgPath + imgName);
- });
-}
-
-/** When the doc is ready, find the inputs and color the input grey if the value is the example
- text. This is necessary to handle back-navigation, which can auto-fill the form with previous
- values (and text should not be grey) */
-$(document).ready(function() {
- $(".button-form input.text").each(function(index) {
- if ($(this).val() == $(this).attr("default")) {
- $(this).css("color","#ccc");
- } else {
- /* This is necessary to handle back-navigation to the page after form was filled */
- $('input[type="text"]:not(input[name='+this.name+'])',
- this.parentNode).attr('disabled','true');
- $('#'+this.name+'-clear').show();
- }
- });
-});
-
-</script>
-
-<form class="button-form">
- <label class="block" for="locale">Language:</label>
- <select id="locale" style="display:block;float:left;margin:0"
- onchange="changeBadgeLang()">
- <option title="Afrikaans"
- value="af">Afrikaans</option>
- <option title="Arabic"
- value="ar">العربية</option>
- <option title="Belarusian"
- value="be">Беларуская</option>
- <option title="Bulgarian"
- value="bg">Български</option>
- <option title="Catalan"
- value="ca">Català</option>
- <option title="Chinese (China)"
- value="zh-cn">中文 (中国)</option>
- <option title="Chinese (Hong Kong)"
- value="zh-hk">中文(香港)</option>
- <option title="Chinese (Taiwan)"
- value="zh-tw">中文 (台灣)</option>
- <option title="Croatian"
- value="hr">Hrvatski</option>
- <option title="Czech"
- value="cs">Česky</option>
- <option title="Danish"
- value="da">Dansk</option>
- <option title="Dutch"
- value="nl">Nederlands</option>
- <option title="Estonian"
- value="et">Eesti</option>
- <option title="Farsi - Persian"
- value="fa">فارسی</option>
- <option title="Filipino"
- value="fil">Tagalog</option>
- <option title="Finnish"
- value="fi">Suomi</option>
- <option title="French"
- value="fr">Français</option>
- <option title="German"
- value="de">Deutsch</option>
- <option title="Greek"
- value="el">Ελληνικά</option>
- <option title="English"
- value="en" selected="true">English</option>
-<!--
- <option title="Hebrew"
- value="iw-he">עברית</option>
--->
- <option title="Hungarian"
- value="hu">Magyar</option>
- <option title="Indonesian"
- value="id-in">Bahasa Indonesia</option>
- <option title="Italian"
- value="it">Italiano</option>
- <option title="Japanese"
- value="ja">日本語</option>
- <option title="Korean"
- value="ko">한국어</option>
- <option title="Latvian"
- value="lv">Latviešu</option>
- <option title="Lithuanian"
- value="lt">Lietuviškai</option>
- <option title="Malay"
- value="ms">Bahasa Melayu</option>
- <option title="Norwegian"
- value="no">Norsk (bokmål)</option>
- <option title="Polish"
- value="pl">Polski</option>
- <option title="Portuguese (Brazil)"
- value="pt-br">Português (Brasil)</option>
- <option title="Portuguese (Portugal)"
- value="pt-pt">Português (Portugal)</option>
- <option title="Romanian"
- value="ro">Română</option>
- <option title="Russian"
- value="ru">Русский</option>
- <option title="Serbian"
- value="sr">Српски / srpski</option>
- <option title="Slovak"
- value="sk">Slovenčina</option>
- <option title="Slovenian"
- value="sl">Slovenščina</option>
- <option title="Spanish (Spain)"
- value="es">Español (España)</option>
- <option title="Spanish (Latin America)"
- value="es-419">Español (Latinoamérica)</option>
- <option title="Swedish"
- value="sv">Svenska</option>
- <option title="Swahili"
- value="sw">Kiswahili</option>
- <option title="Thai"
- value="th">ไทย</option>
- <option title="Turkish"
- value="tr">Türkçe</option>
- <option title="Ukrainian"
- value="uk">Українська</option>
- <option title="Vietnamese"
- value="vi">Tiếng Việt</option>
- <option title="Zulu"
- value="zu">isiZulu</option>
- </select>
- <p style="clear:both;margin:0"> </p>
- <label class="block" for="package" style="clear:left">Package name:</label>
- <input class="text" type="text" id="package" name="package"
- value="com.example.android"
- default="com.example.android"
- onfocus="onInputFocus(this, 'com.example.android')"
- onblur="onInputBlur(this, 'com.example.android')"
- onkeyup="return onTextEntered(event, this.parentNode, this)"/>
- <a id="package-clear" style="display:none" href="#"
- onclick="return clearLabel('package','com.example.android');">clear</a>
- <p style="clear:both;margin:0"> <em>or</em></p>
- <label class="block" style="margin-top:5px" for="publisher">Publisher name:</label>
- <input class="text" type="text" id="publisher" name="publisher"
- value="Example, Inc."
- default="Example, Inc."
- onfocus="onInputFocus(this, 'Example, Inc.')"
- onblur="onInputBlur(this, 'Example, Inc.')"
- onkeyup="return onTextEntered(event, this.parentNode, this)"/>
- <a id="publisher-clear" style="display:none" href="#"
- onclick="return clearLabel('publisher','Example, Inc.');">clear</a>
- <br/><br/>
-
-
-<div class="button-row app">
- <input type="radio" name="buttonStyle" value="_app_rgb_wo_45" id="ws" />
- <label for="ws"><img src="{@docRoot}images/brand/en_app_rgb_wo_45.png"
-alt="Android app on Google Play (small)" /></label>
-
- <input type="radio" name="buttonStyle" value="_app_rgb_wo_60" id="wm" />
- <label for="wm"><img src="{@docRoot}images/brand/en_app_rgb_wo_60.png"
-alt="Android app on Google Play (large)" /></label>
-</div>
-
-<div class="button-row">
- <input type="radio" name="buttonStyle" value="_generic_rgb_wo_45" id="ns" checked="checked" />
- <label for="ns"><img src="{@docRoot}images/brand/en_generic_rgb_wo_45.png"
-alt="Get it on Google Play (small)" /></label>
-
- <input type="radio" name="buttonStyle" value="_generic_rgb_wo_60" id="nm" />
- <label for="nm"><img src="{@docRoot}images/brand/en_generic_rgb_wo_60.png"
-alt="Get it on Google Play (large)" /></label>
-</div>
-
- <input class="button" onclick="return buildButton(this.parentNode);"
- type="button" value="Build my badge" style="padding:10px" />
- <br/>
-</form>
-
-<div id="preview" style="display:none">
- <p>Copy and paste this HTML into your web site:</p>
- <textarea id="snippet" cols="100" rows="5" onclick="this.select()"
-style="font-family:monospace;background-color:#efefef;padding:5px;display:none;margin-bottom:1em">
- </textarea >
-
-<p>Try it out:</p>
-<div id="button-preview" style="margin-top:1em"></div>
-</div>
diff --git a/docs/html/distribute/googleplay/promote/brand.jd b/docs/html/distribute/googleplay/promote/brand.jd
deleted file mode 100644
index 0bda561..0000000
--- a/docs/html/distribute/googleplay/promote/brand.jd
+++ /dev/null
@@ -1,193 +0,0 @@
-page.title=Brand Guidelines
-@jd:body
-
-
-
-<p>We encourage you to use the Android and Google Play brands with your Android app
-promotional materials. You can use the icons and other assets on this page
-provided that you follow the guidelines described below.</p>
-
-<h2 id="brand-android">Android</h2>
-
- <p>The following are guidelines for the Android brand
- and related assets.</p>
-
-
- <h4 style="clear:right">Android in text</h4>
-
- <div style="float:right;clear:right;width:200px;margin:0 0 20px 30px">
- <img alt="" src="{@docRoot}images/brand/mediaplayer.png">
- </div>
- <ul>
- <li>Android™ should have a trademark symbol the first time it appears in a creative.</li>
- <li>Android should always be capitalized and is never plural or possessive.</li>
- <li>"Android" cannot be used in names of applications or accessory products,
- including phones, tablets, TVs, speakers, headphones, watches, and other devices. Instead use "for Android".
- <ul>
- <li><span style="color:red">Incorrect</span>: "Android MediaPlayer"</li>
- <li><span style="color:green">Correct</span>: "MediaPlayer for Android"</li>
- </ul>
- <p>If used with your logo, "for Android" needs to be smaller in size than your logo.
- First instance of this use should be followed by a TM symbol, "for Android™".</p>
- </li>
- <li>Android may be used as a descriptor, as long as it is followed by a proper generic term.
- <ul>
- <li><span style="color:red">Incorrect</span>: "Android MediaPlayer" or "Android XYZ app"</li>
- <li><span style="color:green">Correct</span>: "Android features" or "Android applications"</li>
- </ul>
- </li>
- </ul>
-
- <p>Any use of the Android name needs to include this
- attribution in your communication:</p>
- <blockquote><em>Android is a trademark of Google Inc.</em></blockquote></p>
-
-
- <h4>Android robot</h4>
-
- <div style="float:right;width:200px;margin-left:30px">
- <img alt="" src="{@docRoot}images/brand/Android_Robot_100.png"
- style="margin-left:50px">
- <p style="text-align:center">
- <a href="{@docRoot}images/brand/Android_Robot_100.png">100x118</a> |
- <a href="{@docRoot}images/brand/Android_Robot_200.png">200x237</a><br>
- <a href="{@docRoot}downloads/brand/Android_Robot_outlined.ai">Illustrator (.ai)</a></p>
- </div>
-
- <p>The Android robot can be used, reproduced, and modified freely in marketing
- communications. The color value for print is PMS 376C and the online hex
- color is <span style="color:#A4C639">#A4C639</span>.</p>
-
- <p>When using the Android Robot or any modification of it, proper attribution is
- required under the terms of the <a href="http://creativecommons.org/licenses/by/3.0/">Creative
-Commons Attribution</a> license:</p>
-
- <blockquote><em>The Android robot is reproduced or modified from work created and shared by Google and
-used according to terms described in the Creative Commons 3.0 Attribution License.</em></blockquote>
-
- <p>You may not file trademark applications incorporating the Android robot logo or
-derivatives thereof. We want to ensure that the Android robot remains available
-for all to use.</p>
-
-
-<h4 style="clear:right">Android logo</h4>
-
-<div style="float:right;width:210px;margin-left:30px;margin-top:-10px">
- <img alt="" src="{@docRoot}images/brand/android_logo_no.png">
-</div>
-
-<p>The Android logo may not be used. Nor can this be used with the Android robot.</p>
-<p>The custom typeface may not be used.</p>
-
-
-
-
-<h2 id="brand-google_play">Google Play</h2>
-
-
- <p>The following are guidelines for the Google Play brand
- and related assets.</p>
-
-<h4>Google Play in text</h4>
-
-<p>Always include a TM symbol on the first or most prominent instance of Google Play™
-in text.</p>
-
-<p>When referring to the mobile experience, use "Google Play" unless the text is clearly
-instructional for the user. For example, a marketing headline might read "Download our
-games on Google Play™," but instructional text would read "Download our games using the Google
-Play™ Store app."
-
- <p>Any use of the Google Play name or icon needs to include this
- attribution in your communication:</p>
-
-<blockquote><em>Google Play is a trademark of Google Inc.</em></blockquote>
-
-
- <div style="float:right;width:96px;margin-left:30px;margin-top:-20px">
- <img src="{@docRoot}images/brand/Google_Play_Store_96.png" alt="">
- <p style="text-align:center">
- <a href="{@docRoot}images/brand/Google_Play_Store_48.png">48x48</a> |
- <a href="{@docRoot}images/brand/Google_Play_Store_96.png">96x96</a><br>
- <a href="{@docRoot}downloads/brand/Google_Play_Store.ai">Illustrator (.ai)</a>
- </p>
- </div>
-
-<h4>Google Play Store icon</h4>
-
-<p>You may use the Google Play Store icon, but you may not modify it.</p>
-
-<p>As mentioned above, when referring to the Google Play Store app in copy, use the full name:
-"Google Play Store." However, when labeling the Google Play Store icon directly, it's OK to use
-"Play Store" alone to accurately reflect the icon label as it appears on a device.</p>
-
-
-<h4>Google Play badge</h4>
-
- <div style="float:right;clear:right;width:172px;margin-left:30px">
- <img src="{@docRoot}images/brand/en_app_rgb_wo_60.png" alt="">
- <p style="text-align:center">
- <a href="{@docRoot}images/brand/en_app_rgb_wo_45.png">129x45</a> |
- <a href="{@docRoot}images/brand/en_app_rgb_wo_60.png">172x60</a></p>
- </div>
-
- <div style="float:right;clear:right;width:172px;margin-left:30px">
- <img src="{@docRoot}images/brand/en_generic_rgb_wo_60.png" alt="">
- <p style="text-align:center">
- <a href="{@docRoot}images/brand/en_generic_rgb_wo_45.png">129x45</a> |
- <a href="{@docRoot}images/brand/en_generic_rgb_wo_60.png">172x60</a></p>
- </div>
-
- <p>The "Get it on Google Play" and "Android App on Google Play" logos are badges that you
- can use on your web site and promotional materials, to point to your products on Google
- Play.</p>
-
- <ul>
- <li>Do not modify the color, proportions, spacing or any other aspect of the badge image.
- </li>
- <li>When used alongside logos for other application marketplaces, the Google Play logo
- should be of equal or greater size.</li>
- <li>When used online, the badge should link to either:
- <ul>
- <li>A list of products published by you, for example:<br />
- <span style="margin-left:1em;">http://play.google.com/store/search?q=<em>publisherName</em></span>
- </li>
- <li>A specific app product details page within Google Play, for example:<br />
- <span style="margin-left:1em;">http://play.google.com/store/apps/details?id=<em>packageName</em></span>
- </li>
- </ul>
- </li>
- </ul>
-
- <p>To quickly create a badge that links to your apps on Google Play,
- use the <a
- href="{@docRoot}distribute/googleplay/promote/badges.html">Googe Play badge generator</a>
- (provides the badge in over 40 languages).</p>
-
- <p>To create your own size, download an Adobe® Illustrator® (.ai) file for the
- <a href="{@docRoot}distribute/googleplay/promote/badge-files.html">Google Play
- badge in over 40 languages</a>.</p>
-
- <p>For details on all the ways that you can link to your product details page in Google Play,
- see <a href="{@docRoot}distribute/googleplay/promote/linking.html">Linking to your products</a></p>
-
-
-
-<h2 id="Questions">Questions</h2>
-
-<p>To view our full guidelines or for any further brand usage questions, please contact our
-Android Partner Marketing team:</p>
-<ul>
- <li>For North and South America, please contact <a
- href="mailto:android-brand-approvals@google.com?Subject=Brand%20Approval%20Questions"
- >android-brand-approvals@google.com</a></li>
-
- <li>For Europe and Emerging Markets, please contact <a
- href="mailto:emea-android-brand@google.com?Subject=Brand%20Approval%20Questions"
- >emea-android-brand@google.com</a></li>
-
- <li>For Asia and Pacific-America, please contact <a
- href="mailto:apac-android-brand-approvals@google.com?Subject=Brand%20Approval%20Questions"
- >apac-android-brand-approvals@google.com</a></li>
-</ul>
-
diff --git a/docs/html/distribute/googleplay/promote/index.jd b/docs/html/distribute/googleplay/promote/index.jd
deleted file mode 100644
index 6882990..0000000
--- a/docs/html/distribute/googleplay/promote/index.jd
+++ /dev/null
@@ -1,43 +0,0 @@
-page.title=Promoting Your Apps
-page.metaDescription=Raise the visibility of your apps in Google Play through deep links and Google Play badges.
-header.hide=0
-footer.hide=0
-@jd:body
-
-<!--
-<style>
-#landing-graphic-container {
- position: relative;
-}
-
-#text-overlay {
- position: absolute;
- left: 0;
- top: 472px;
- width: 280px;
-}
-</style>
-
-<div id="landing-graphic-container">
- <div id="text-overlay">
- Raise the visibility of your apps with badges and link users to your products on Google Play.
- <br><br>
- <a href="{@docRoot}distribute/googleplay/promote/product-pages.html" class="landing-page-link">Your Product Pages</a>
- </div>
-
- <a href="{@docRoot}distribute/googleplay/promote/index.html">
- <img src="{@docRoot}design/media/index_landing_page.png">
- </a>
-</div> -->
-
-<p>After you publish your app, you can bring Android users to your app's product details page by
-providing links in your social network posts, ad campaigns, app reviews and articles, your
-web site, and more. </p>
-
-<p>You can use the resources in this section to create deep links for your online placements.
-Google Play badges are an especially great way let Android users know that your app is available
-and link them directly to your download page. With the badge generator, they're also easy to make.</p>
-
-
-<p style="margin-top:1.5em;margin-bottom:1.5em;"><a href="{@docRoot}distribute/googleplay/promote/linking.html" class="landing-page-link">Linking to Your Products</a></p>
-
diff --git a/docs/html/distribute/googleplay/promote/linking.jd b/docs/html/distribute/googleplay/promote/linking.jd
deleted file mode 100644
index 4fdc5db..0000000
--- a/docs/html/distribute/googleplay/promote/linking.jd
+++ /dev/null
@@ -1,213 +0,0 @@
-page.title=Linking to Your Products
-@jd:body
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<a href="badges.html">
- <img alt="Get it on Google Play"
- src="{@docRoot}images/brand/en_app_rgb_wo_45.png" />
-</a>
-<p>For a link that includes the Google Play brand icon, check out the <a href="badges.html">Badges</a> page. </p>
-</div>
-</div>
-
-<p>Google Play provides several link formats that let you bring users to your
-products in the way you want, from Android apps, web pages, ads, reviews,
-articles, social media posts, and more.</p>
-
-<p>The link formats let you:</p>
-<ul>
-<li>Link to a specific app's <a href="#OpeningDetails">product details page</a></li>
-<li>Link to a <a href="#OpeningPublisher">list of all of your apps</a>, or</li>
-<li>Link to a <a href="#PerformingSearch">search result</a> of your choice</li>
-<li>Link to a <a href="#OpeningCollection">collection</a> on Google Play</li>
-</ul>
-
-<p>If you are linking from an Android app, you can also control whether the link
-launches the Play Store application or the browser, which takes the user
-to the Google Play web site.</p>
-
-<h2 id="OpeningDetails">Linking to a Product Details Page</h2>
-
-<p>Use the format below to deep-link users directly to a specific app's product
-details page. At the product details page, users can see the app description,
-screenshots, reviews and more, and then install it.</p>
-
-<p>To create the link, you need to know the app's fully qualified <em>package
-name</em>, which is declared in the app's <a
-href="{@docRoot}guide/topics/manifest/manifest-element.html#package">manifest
-file</a>. The package name is also visible in the Developer Console. </p>
-
-<dl>
-<dt><strong>From a web site:</strong></dt>
-<dd>
-<pre>http://play.google.com/store/apps/details?id=<package_name></pre>
-</dd>
-<dt><strong>From an Android app:</strong></dt>
-<dd>
-<pre>market://details?id=<package_name></pre>
-</dd>
-</dl>
-
-<p>Here's an example:</p>
-
-<p style="margin-left:1em;"><code><a href="http://play.google.com/store/apps/details?id=com.google.android.apps.maps">http://play.google.com/store/apps/details?id=com.google.android.apps.maps</a></code></p>
-
-<p>For details on how to send the link in an Android app, see <a href="#android-app">Linking from an Android App</a>.</p>
-
-
-
-<h2 id="OpeningPublisher">Linking to a Product List</h2>
-
-<p>Use the format below to link users to a list of apps published by you. The
-product list lets users see all of the apps from a specific publisher, with
-ratings, editorial badges, and an Install button for each. </p>
-
-<p>To create the link, you need to know your <em>publisher name</em>, which is
-available from the Developer Console. </p>
-
-<dl>
-<dt><strong>From a web site:</strong></dt>
-<dd>
-<pre>http://play.google.com/store/search?q=pub:<publisher_name></pre>
-</dd>
-<dt><strong>From an Android app:</strong></dt>
-<dd>
-<pre>market://search?q=pub:<publisher_name></pre>
-</dd>
-</dl>
-
-<p>Here's an example:</p>
-
-<p style="margin-left:1em;"><code><a href="http://play.google.com/store/search?q=pub:Google Inc.">http://play.google.com/store/search?q=pub:Google Inc.</a></code></p>
-
-<p>For details on how to send the link in an Android app, see <a href="#android-app">Linking from an Android App</a>.</p>
-
-
-<h2 id="PerformingSearch">Linking to a Search Result</h2>
-
-<p>Use the format below to link users to a search query result on Google Play.
-The search result page shows a list of apps (and optionally other content) that
-match the query, with ratings, badges, and an Install button for each. </p>
-
-<p>To create the link, you just need a search query string. If you want the
-query to search outside of the Google Play Apps listings, you can remove the
-<code>&c=apps</code> part of the link URL.</p>
-
-<dl>
-<dt><strong>From a web site:</strong></dt>
-<dd>
-<pre>http://play.google.com/store/search?q=<search_query>&c=apps</pre>
-</dd>
-<dt><strong>From an Android app:</strong></dt>
-<dd>
-<pre>market://search?q=<seach_query>&c=apps</pre>
-</dd>
-</dl>
-
-<p>Here's an example:</p>
-
-<p style="margin-left:1em;"><code><a href="http://play.google.com/store/search?q=maps&c=apps">http://play.google.com/store/search?q=maps&c=apps</a></code></p>
-
-<p>For details on how to send the link in an Android app, see <a href="#android-app">Linking from an Android App</a>.</p>
-
-
-
-<h2 id="OpeningCollection">Linking to a Collection</h2>
-
-<p>If your app is featured or appears in one of the Google Play Top charts or
-collections, you can use the format below to link users directly to the
-collection. The collection shows a ranked list of apps in the collection, with
-ratings, short descriptions, and an Install button.</p>
-
-<dl>
-<dt><strong>From a web site:</strong></dt>
-<dd>
-<pre>http://play.google.com/store/apps/collection/<collection_name></pre>
-</dd>
-<dt><strong>From an Android app:</strong></dt>
-<dd>
-<pre>market://apps/collection/<collection_name></pre>
-</dd>
-</dl>
-
-<p>Here's an example:</p>
-
-<p style="margin-left:1em;"><code><a href="http://play.google.com/store/apps/collection/editors_choice">http://play.google.com/store/apps/collection/editors_choice</a></code></p>
-
-<p>For details on how to send the link in an Android app, see <a href="#android-app">Linking from an Android App</a>.</p>
-
-<p class="table-caption"><strong>Table 1.</strong> Collections on Google Play</a>.</p>
-
-<table>
-<tr>
-<th>Collection</th><th>collection_name</th>
-</tr>
-<tr><td>Staff Picks (Featured)</td><td>featured</td></tr>
-<tr><td>Editor's Choice</td><td>editors_choice</td></tr>
-<tr><td>Top Paid</td><td>topselling_paid</td></tr>
-<tr><td>Top Free</td><td>topselling_free</td></tr>
-<tr><td>Top New Free</td><td>topselling_new_free</td></tr>
-<tr><td>Top New Paid</td><td>topselling_new_paid</td></tr>
-<tr><td>Top Grossing</td><td>topgrossing</td></tr>
-<tr><td>Trending</td><td>movers_shakers</td></tr>
-<tr><td>Best Selling in Games</td><td>topselling_paid_game</td></tr>
-</table>
-
-
-<h2 id="android-app">Linking from an Android App</h2>
-
-<p>There are two general formats for links that are accessible to users on
-Android devices, The two formats trigger slightly different behaviors on the
-device:</p>
-
-<ul>
-<li><code>market://</code> Launches the Play Store app to load the
-target page.</li>
-<li><code>http://</code> Lets the user choose whether to launch the
-Play Store app or the browser to handle the request. If the browser handles the
-request, it loads the target page on the Google Play web site.</li>
-</ul>
-
-<p>In general, you should use <code>http://</code> format for links on web pages
-and <code>market://</code> for links in Android apps.</p>
-
-<p>If you want to link to your products from an Android app, create an {@link
-android.content.Intent} that opens an Google Play URL, as shown in the example
-below.</p>
-
-<pre>
-Intent intent = new Intent(Intent.ACTION_VIEW);
-intent.setData(Uri.parse("market://details?id=com.example.android"));
-startActivity(intent);
-</pre>
-
-
-<h2 id="UriSummary">Summary of URL formats</h2>
-
-<p>The table below provides a summary of the URIs currently supported by the Google Play (both on
-the web and in an Android application), as discussed in the previous sections.</p>
-
-<table>
-<tr>
-<th>For this result</th>
-<th>Web page link</th>
-<th>Android app link</th>
-</tr>
-<tr>
-<td style="width:72px;">Show the product details page for a specific app</td>
-<td><code>http://play.google.com/store/apps/details?id=<package_name></code>
-<td><code>market://details?id=<package_name></code></td>
-</tr>
-<tr>
-<td>Show apps by a specific publisher</td>
-<td><nobr><code>http://play.google.com/store/search?q=pub:<publisher_name></code></nobr></td>
-<td><nobr><code>market://search?q=pub:<publisher_name></code></nobr></td>
-</tr>
-<tr>
-<td>Search for apps using a general string query.</td>
-<td><code>http://play.google.com/store/search?q=<query></code></td>
-<td><code>market://search?q=<query></code></td>
-</tr>
-</table>
-
diff --git a/docs/html/distribute/googleplay/promote/product-pages.jd b/docs/html/distribute/googleplay/promote/product-pages.jd
deleted file mode 100644
index af5b2d5..0000000
--- a/docs/html/distribute/googleplay/promote/product-pages.jd
+++ /dev/null
@@ -1,4 +0,0 @@
-page.title=Your Product Pages
-@jd:body
-
-<p>Placeholder...</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/publish/console.jd b/docs/html/distribute/googleplay/publish/console.jd
deleted file mode 100644
index 3831e51..0000000
--- a/docs/html/distribute/googleplay/publish/console.jd
+++ /dev/null
@@ -1,198 +0,0 @@
-page.title=Developer Console
-@jd:body
-
-
-<p>Once you've <a
-href="{@docRoot}distribute/googleplay/publish/register.html">registered</a> and
-received verification by email, you can sign in to your Google Play
-Developer Console, which will be the home for your app publishing operations and
-tools on Google Play. This sections below introduce a few of the key areas
-you'll find in the Developer Console.</p>
-
-<div class="figure" style="width:756px;">
-<img src="{@docRoot}images/gp-dc-home.png" class="frame">
-<p class="img-caption"><strong>All applications page</strong>: Gives you a quick
-overview of your apps, lets you jump to stats, reviews, and product details, or
-upload a new app. </p>
-</div>
-
-<div class="figure-right" style="width:450px;">
-<img src="{@docRoot}images/gp-dc-profile.png" class="frame">
-<p class="img-caption"><strong>Account details page</strong>: Specifies your developer
-identity and contact information, accounts for app testing, and more.</p>
-</div>
-
-<h3 id="profile">Your account details</h3>
-
-<p>The account details page is where you specify basic information about yourself
-or your company in a developer profile. The information in your developer profile
-is important because it identifies you to Google Play and also to your customers.</p>
-
-<p>During registration you must provide the information for your profile, but you can
-go back at any time to edit the information and change your settings. </p>
-
-<p>Your developer profile contains:</p>
-<ul>
-<li>Your developer name — the name you want to show users on your store
-listing page and elsewhere on Google Play. </li>
-<li>Your developer contact information — how Google can contact you if
-needed (this information isn't exposed to users).</li>
-<li>Your developer website URL — shown to users on your store listing page
-so they can learn more about your company or products.</li>
-</ul>
-
-<p>On the account details page you can also register for a merchant account, set
-up test accounts for Google Play licensing, and more. </p>
-
-<h3 id="user-accounts">Multiple user accounts</h3>
-
-<p>If you are working with a team, you can set up multiple user accounts to
-access different parts of your Developer Console. The first account registered
-is the <em>account owner</em>, with full access to all parts of the Console. The
-owner can add <em>user accounts</em> and manage what parts of the Console they
-have access to. For example, an owner can grant users access to publishing and
-app configuration, but not access to financial reports. </p>
-
-
-<div class="figure-right" style="width:450px;">
-<img src="{@docRoot}images/gp-dc-details.png" class="frame">
-<p class="img-caption"><strong>Store listing page</strong>: Lets you upload your
-graphic assets, description, support information, and other information to
-create the store listing page for a specific app.</p>
-</div>
-
-<h3 id="merchant">Linking your Merchant Account</h3>
-
-<p>If you want to sell apps or in-app products, you can link your Google
-Wallet merchant account to your developer profile. Google Play uses the linked
-merchant account for financial and tax identification and monthly payouts of
-sales. </p>
-
-<h3 id="details">Your store listing details</h3>
-
-<p>The Developer Console lets you set up a colorful storefront page for your app
-called the <em>Store Listing page</em>. Your Store Listing page is the home
-for your app in Google Play — it's the page users see on their mobile
-phones or on the web when they want to learn about your app and download it.
-</p>
-
-<p>You can upload custom brand assets, screen shots, and videos to highlight
-what's great about your app, and you can provide a localized description, add
-notes about the latest version, and more. You can update your store listing at
-any time, even if you don’t have a new version of your application.</p>
-
-<h3 id="uploading">Uploading and publishing</h3>
-
-<p>From the Developer Console you can quickly upload a release-ready APK and
-publish it when you're ready. The app is a <em>draft</em> until you publish it,
-at which time Google Play makes your store listing page and app available to
-users. You can unpublish the app at any time.</p>
-
-<h3 id="controls">Distribution controls</h3>
-
-<p>In the Developer Console you can manage what countries and territories the
-app is distributed to and, for some countries, you can choose what carriers you
-want to target.</p>
-
-<p>You can also see the list of devices that your app is currently available to,
-based on any distribution rules declared in its manifest file.</p>
-
-<h3 id="selling">Selling and pricing your products</h3>
-
-<p>The Developer Console gives you tools to set prices for your apps and in-app
-products. Your app can either be free to download or priced (charged before
-download). </p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<p>See <a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294&topic=2365624&ctx=topic">Supported locations for distributing applications</a> for a list of countries where you can distribute or sell your app,</p>
-</div>
-</div>
-
-<ul>
-<li>If you publish your app as free, <span style="font-weight:500;">it must
-remain free</span>. Free apps can be downloaded by any users in Google
-Play.</li>
-<li>If you publish it as priced, you can later change it to free. Priced apps can be
-purchased and downloaded only by users who have registered a form of payment
-in Google Play.</li>
-</ul>
-
-<p>In addition, you can sell in-app products and subscriptions in your app,
-whether the app is free or priced. You can set prices separately for priced apps,
-in-app products, and subscriptions.</p>
-
-<p>If you are selling a priced app or in-app products or subscriptions, the
-Developer Console lets you set prices in a large number of different currencies.
-When users around the world visit your store listing, they see the price
-of your app in their own currency. For most countries, the price you set is the
-final price charged to users, inclusive of taxes. </p>
-
-<p>To help you manage your prices, the Developer Console provides an autofill
-capability that uses recent exchange rates to populate the prices in all
-supported currencies. You can change prices for apps and in-app products at any
-time, just by saving changes in the Developer Console.</p>
-
-<h3>In-app Billing</h3>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>In-app Billing</h2>
-<p>For details on how to implement In-app Billing, see the
-<a href="{@docRoot}google/play/billing/index.html">In-app Billing</span></a>
-developer documentation.</p></div></div>
-
-<p><a href="{@docRoot}google/play/billing/index.html">In-app Billing</a> is
-a Google Play service that lets you monetize your apps in more ways by selling
-in-app products and subscriptions. In-app products are one-time purchases, while
-subscriptions are recurring charges on an monthly or annual basis.</p>
-
-<p>From the Developer Console you can create product lists for in-app
-products and subscriptions, set prices, and publish.</p>
-
-<div class="figure-right" style="width:410px;">
-<img src="{@docRoot}images/gp-dc-reviews.png" class="frame">
-<p class="img-caption"><strong>User
-reviews page</strong>: Gives you access to user reviews for a specific app.
-You can filter reviews in a number of ways to locate issues more easily
-and support your customers more effectively.</p>
-</div>
-
-<h3>User reviews and crash reports</h3>
-
-<p>Google Play makes it easy for users to submit reviews of your app for the
-benefit of other users. The reviews are also extremely important to you, since
-they give you usability feedback, support requests, and important functionality
-issues direct from your customers. </p>
-
-<p>The Developer Console also lets you see crash reports, with stack trace and
-other data, submitted automatically from Android devices, for debugging and
-improving your app.</p>
-
-<h3>App statistics</h3>
-
-<p>The Developer Console gives you detailed statistics on the install
-performance of your app. </p>
-
-<p>You can view installations of your app measured by unique users, as well as
-by unique devices. For user installations, you can view active installs, total
-installs, daily installs and uninstalls, and metrics about user ratings.
-For devices, you can see active
-installs as well as daily installs, uninstalls, and upgrades.</p>
-
-<p>You can zoom into the installation numbers along several dimensions,
-including Android platform version, device, country, language, app version, and
-carrier (mobile operator). You can see the installation data for each dimension
-on a timeline charts.</p>
-
-<p>At a glance, these charts highlight your app’s installation peaks and
-longer-term trends, which you can correlate to promotions, app improvements, or
-other factors. You can even focus in on data inside a dimension by adding
-specific points (such as individual platform versions or languages) to the
-timeline.</p>
-
-<div style="width:530px;">
-<img src="{@docRoot}images/gp-dc-stats.png" class="frame">
-<p class="img-caption"><strong>App statistics page</strong>: Shows you a variety
-of statistics about a specific app's installation performance over time.</p>
-</div>
diff --git a/docs/html/distribute/googleplay/publish/index.jd b/docs/html/distribute/googleplay/publish/index.jd
deleted file mode 100644
index 5a5eaf2..0000000
--- a/docs/html/distribute/googleplay/publish/index.jd
+++ /dev/null
@@ -1,23 +0,0 @@
-page.title=Publishing on Google Play
-header.hide=1
-footer.hide=1
-page.metaDescription=Get started publishing apps on Google Play.
-
-@jd:body
-
-<div style="height:413px;padding-top:50px;">
- <img src="{@docRoot}images/gp-devconsole-home.png" style="margin-top:0px;">
-</div>
-
-<div style="width:460px;padding-bottom:40px;margin-left:1.5em;">
- <p>Upload apps, build your product pages, configure prices and
- distribution, and publish. You can manage all phases of publishing
- on Google Play through the Developer Console, from any web browser.</p>
-
-<p style="margin-top:1.5em;margin-bottom:1.5em;"><a href="{@docRoot}distribute/googleplay/publish/register.html" class="landing-page-link">Get started</a></p>
-</div>
-
-
-
-
-
diff --git a/docs/html/distribute/googleplay/publish/localizing.jd b/docs/html/distribute/googleplay/publish/localizing.jd
deleted file mode 100644
index 30f10b7..0000000
--- a/docs/html/distribute/googleplay/publish/localizing.jd
+++ /dev/null
@@ -1,600 +0,0 @@
-page.title=Localization Checklist
-page.tags=localize,localization,resources,formats,l10n
-@jd:body
-
-<div id="qv-wrapper"><div id="qv">
-<h2>Checklist</h2>
-<ol>
-<li><a href="#target-languages">1. Identify target languages</a></li>
-<li><a href="#design">2. Design for localization</a></li>
-<li><a href="#strings">3. Manage strings for localization</a></li>
-<li><a href="#translate">4. Translate UI strings</a></li>
-<li><a href="#test">5. Test your localized app</a></li>
-<li><a href="#prelaunch">6. Prepare for international launch</a></li>
-<li><a href="#support">7. Support international users</a></li>
-</ol>
-<h2>See Also</h2>
-<ol>
-<li><a href="{@docRoot}distribute/googleplay/promote/badges.html">Google Play Badge Builder</a></li>
-<li><a href="{@docRoot}distribute/promote/device-art.html">Device Art Generator</a></li>
-<li><a href="#gp-trans">Translations in Google Play</a></li>
-<li><a href="{@docRoot}sdk/installing/installing-adt.html#tmgr">ADT Translation Manager Plugin</a></li>
-</ol>
-</div></div>
-
-<p>Android and Google Play give you a worldwide audience for your app, with an
-addressable user base that's growing very rapidly in countries such as Japan,
-Korea, India, Brazil, Russia, and elsewhere. </p>
-
-<p>To maximize your app's distribution potential and earn high ratings from
-users around the world, we strongly encourage you to localize your app. </p>
-
-<p>Localization involves a variety of tasks throughout your app's development
-cycle, and advance planning is essential. Some of the tasks include
-translating your UI strings and localizing dates and times, layouts, text
-direction, and finally your Google Play store listing. </p>
-
-<p>This document helps you identify key aspects of localization to prepare for
-and the tasks you'll need to perform, to get your app ready for a
-successful worldwide launch on Google Play.</p>
-
-
-<h2 id="target-languages">1. Identify target languages and locales</h2>
-
-<p>A basic but important step in preparing for localization is identifying the
-countries where you will distribute your app and the languages spoken there.
-Google Play lets you distribute your app broadly to hundreds of countries, reaching
-users who speak a variety of languages. </p>
-
-<p>For international users, you can manage your app on three main dimensions:
-country, locale, and language. Of those, language is the key consideration for
-localization, although locale is also significant because of differences in
-formats for dates, times, currencies, and similar information. Users control
-both the language and locale used on their Android devices and in turn those
-affect the display of your app, once installed.</p>
-
-<p>Typically, you would decide which countries to target first, based on overall
-market size and opportunity, app category, competitive landscape, local pricing
-and financial factors, and so on. Then, based on your country targeting, you
-would determine the languages you need to support in your app. </p>
-
-<p>You will need to decide when to localize into some or all of the languages in your targeted countries. In some countries it might make most sense to deliver an app
-in a major regional or international language only, rather than in all locally
-spoken languages. Similarly, based on overall market size, you might decide to
-deliver your app in only a small number of key languages and offer English or
-another language for other countries. You can add more languages in the future
-as your app's userbase grows.</p>
-
-<p>Localizing your app is particularly important in countries where there is a
-large market opportunity and English or another international language is not
-widely used. Once you have identified your target languages, you can focus your
-development, translation, testing, and marketing efforts to these markets.</p>
-
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294&topic=2365624&ctx=topic">Supported locations for distributing applications</a></strong> on Google Play.
-.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="design">2. Design for localization</h2>
-
-<p>After you've determined your target languages for localization, assess what
-you'll need to do to support them in your app and plan the work early. Consider
-the vocabulary expansion, script requirements, character spacing and wrapping
-constraints, left-to-right and right-to-left support, and other potential
-factors in each language.
-
-<h4>Design a single set of flexible layouts</h4>
-
-<p>As you create your layouts, make sure that any UI elements that hold text are
-designed generously. It’s good to allow more space than necessary for your
-language (up to 30% more is normal) to accommodate other languages.</p>
-
-<p>Also, elements should be able to expand horizontally or vertically to
-accommodate variations in the width and height of UI strings or input text. Your
-text strings should not overlap borders or the screen edge in any of your target
-languages.</p>
-
-<p>If you design your UI carefully, you can typically use a single set of
-layouts for all of the languages you support. See <a
-href="{@docRoot}training/basics/fragments/fragment-ui.html">Building a Flexible
-UI</a> for more information.</p>
-
-<h4 id="rtl">Use alternative layouts where needed</h4>
-
-<p>In cases where your UI can't accommodate text in one of your target
-languages, you can create an <a
-href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">alternative
-layout</a> for that language only.
-Android makes it easy to declare sets of layouts and other resources to load for
-specific languages, locales, screen sizes, and so on, simply by tagging them
-with the appropriate resource qualifiers. </p>
-
-<p>Although you can use alternative layouts to work around isolated issues, they
-can also make your app harder to maintain over time. In general, using a single,
-more flexible layout is preferred. </p>
-
-<h4 id="rtl">Support RTL layouts and text</h4>
-
-<p>If you are distributing to countries where right-to-left (RTL) scripts are used,
-should consider implementing support for RTL layouts and text display and
-editing, to the extent possible. </p>
-
-<p>Android 4.1 introduced limited support for bidirectional text, allowing apps
-to display and edit text in both left-to-right (LTR) and right-to-left (RTL)
-scripts. Android 4.2 added <a
-href="http://android-developers.blogspot.fr/2013/03/native-rtl-support-in-
-android-42.html">full native support for RTL layouts</a>, including layout
-mirroring, so that you can deliver the same great app experience to all of your
-users. </p>
-
-<p>At a minimum, for Android 4.2 users, it's simple to add basic RTL layout
-mirroring, which goes a long way toward meeting the needs of RTL users. </p>
-
-<h4 id="formats">Use system-provided formats for dates, times, numbers, and
-currencies</h4>
-
-<p>Where your app specifies dates, times, numbers, currencies, and other
-entities that can vary by locale, make sure to use the system-provided formats,
-rather than app-specific formats. Keep in mind that not every locale uses the
-same thousands separator, decimal separator, or percent sign. </p>
-
-<p>Android provides a variety of utilities for formatting and converting
-patterns across locales, such as {@link android.text.format.DateUtils DateUtils} and
-{@link java.text.DateFormat DateFormat} for
-dates; {@link java.lang.String#format String.format()} or {@link java.text.DecimalFormat DecimalFormat} for
-numbers and currency; {@link android.telephony.PhoneNumberUtils
-PhoneNumberUtils} for phone numbers; and others.</p>
-
-<p>If you hard-code your formats based on assumptions about the user's locale,
-your app could encounter problems when the user changes to another locale. The
-easiest and most reliable approach is to always use system-provided formats and
-utilities.</p>
-
-<h4 id="default-resources">Include a full set of default resources</h4>
-
-<p>Make sure that your app can run properly regardless of language or locale by
-providing a complete set of default resources. The app's default resources are
-those that are <em>not marked</em> with any language or locale qualifiers, for
-example those stored in <code>res/drawable/</code> and <code>res/values/</code>.
-If your app attempts to load a resource that isn't available in the current
-language or in the default set, the app will crash. </p>
-
-<p>Whatever the default language you are using in your app, make sure that you
-store the associated layouts, drawables, and strings in default resource
-directories, without language or locale qualifiers. </p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://android-developers.blogspot.fr/2013/03/native-rtl-support-in-android-42.html">Native RTL Support in Android 4.2</a></strong> — Blog post that explains how to support RTL in your UI.</li>
-<li><strong><a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">Quantity Strings (Plurals)</a></strong> — Developer guide describing how to work with string plurals according to rules of grammar in a given locale. </li>
-<li><strong>{@link java.util.Locale Locale}</strong> — Reference information about how to use locale data determine exactly what CLDR data or version of the Unicode spec a particular Android platform version uses.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="managing-strings">3. Manage strings for localization</h2>
-
-<p>It's important to manage your app's UI strings properly, so that you deliver
-a great experience for users and make localization straightforward.</p>
-
-<h4 id="strings">Move all strings into strings.xml</h4>
-
-<p>As you build your app, remember that it's a best practice to keep all of your
-UI strings in a single file that's easy to update and localize. Declare
-<em>all</em> of your strings as resources in a default <code>strings.xml</code>
-file. Do not hard-code any strings into your compiled code—hard-coded
-strings are much more difficult to extract, translate, and load properly.
-
-<p>If you keep all of your default strings in a <code>strings.xml</code> file,
-you can quickly extract them for translation, and once the translated strings
-are integrated back into your app with appropriate qualifiers, your app can load
-them without any changes to your compiled code.</p>
-
-<p>If you generate images with text, put those strings in <code>strings.xml</code> as well,
-and regenerate the images after translation.</p>
-
-<h4 id="style">Follow Android guidelines for UI strings</h4>
-
-<p>As you design and develop your UI, make sure that you pay close attention to
-<em>how</em> you talk to your user. In general, use a <a
-href="{@docRoot}design/style/writing.html">succinct and compressed style</a>
-that is friendly but brief, and use a consistent style throughout your UI.
-</p>
-
-<p>Make sure that you read and follow the Android Design recommendations for <a
-href="{@docRoot}design/style/writing.html">writing style and word choice</a>.
-Doing so will make your app appear more polished to the user and will help users
-understand your UI more quickly. </p>
-
-<p>Also, always use Android standard terminology wherever possible—such as
-for UI elements such as "Action Bar," "Options Menu," "System Bar,"
-"Notifications," and so on. Using Android terms correctly and consistently
-makes translation easier and results in a better end-product for users.</p>
-
-<h4 id="context">Provide sufficient context for declared strings</h4>
-
-<p>As you declare strings in your <code>strings.xml</code> file, make sure to describe the
-context in which the string is used. Add comments before each string that may
-need clarification. This information will be invaluable to translators and will
-help you manage your strings more effectively over time.</p>
-
-<p>For example, background information to provide might include:</p>
-
-<ul>
- <li>What is this string for? When/where is it presented to the user?</li>
-<li>Where is this in the layout? For example, if it’s a button, translations are
-less flexible than if it were a text box. </li>
-</ul>
-
-<p>Here's an example: </p>
-
-<pre><!-- The action for submitting a form. This text is on a button that can fit 30 chars -->
-<string name="login_submit_button">Sign in</string></pre>
-
-<h4 id="xliff">Mark message parts that should not be translated</h4>
-
-<p>Often strings contain contain text that should not be translated to other
-languages. Common examples might be a piece of code, a placeholder for a value,
-a special symbol, or a name. As you prepare you strings for translation, look
-for and mark text that should remain as-is, without translation, so that
-translators do not change it. </p>
-
-<p>To mark text that should not be translated, use an
-<code><xliff:g></code> placeholder tag. Here's an example tag that ensures
-the text “%1$s” will not be changed during translation (otherwise it could break
-the message):</p>
-
-<pre><string name="countdown">
- <xliff:g id="time" example="5 days>%1$s</xliff:g>until holiday
-</string></pre>
-
-<p>When you declare a placeholder tag, always add an <code>id</code> attribute
-that explains what the placeholder is for. If your app will later replace the
-placeholder value, be sure to provide an example attribute to clarify the expected
-usage.</p>
-
-<p>Here are some more examples of placeholder tag usage:</p>
-<pre><resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Example placeholder for a special unicode symbol -->
- <string name="star_rating">Check out our 5
- <xliff:g id="star">\u2605</xliff:g>
- </string>
- <!-- Example placeholder for a for a URL -->
- <string name="app_homeurl">
- Visit us at <xliff:g id="application_homepage">http://my/app/home.html</xliff:g>
- </string>
- <!-- Example placeholder for a name -->
- <string name="prod_name">
- Learn more at <xliff:g id="prod_gamegroup">Game Group</xliff:g>
- </string>
- <!-- Example placeholder for a literal -->
- <string name="promo_message">
- Please use the ”<xliff:g id="promotion_code">ABCDEFG</xliff:g>” to get a discount.
- </string>
- ...
-</resources></pre>
-<!--<pre><string name="contact_info">
- You can see our posts at <xliff:g id="social_account_id">@superApp</xliff:g>
-</string></pre>-->
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}guide/topics/resources/string-resource.html">String Resources</a></strong> — Developer guide explaining how to use string resources in your UI.</li>
-<li><strong><a href="{@docRoot}design/style/writing.html">Writing Style</a></strong> — Android Design guidelines for voice and style in your UI.</li>
-<li><strong><a class="external-link" href="http://en.wikipedia.org/wiki/XLIFF">XML Localisation Interchange File Format (XLIFF)</a></strong> — Background information on XLIFF.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="translate">4. Translate UI strings and other resources</h2>
-
-<p>Translating your app's UI strings and resources to your target languages is
-the key phase of localization, and it's the one that requires the most care and
-planning.</p>
-
-<p>In general, it's recommended to work with a professional translator to ensure
-that the work goes smoothly, stays on schedule, and results in a high-quality
-product that will enhance the value of your app. If you are considering machine
-translations as an alternative, keep in mind that automated translations are less
-reliable than high-quality professional translations and may not produce as good an
-experience for your users.</p>
-
-<h4>Prepare for translation</h4>
-
-<p>Getting high-quality translation output depends in part on your input. To get
-ready for translation, make sure that your <code>strings.xml</code> file is well organized,
-well commented, and accurate.</p>
-
-<p>Here are some ways to prepare your strings for translation:</p>
-<ul>
- <li>Make sure your strings are formatted correctly and consistently.</li>
- <li>Follow the strings recommendations listed in <a href="#strings">Manage
-strings for localization</a>, above.</li>
- <li>Clean up the <code>strings.xml</code> file and remove unused strings.</li>
- <li>Place comments in the file to identify the owner, origin, and the version
-of the file, as well as any special instructions for translators.</li>
-<li>Identify existing translations, if any, and include those in an outgoing
-zip file or other package that you will send to translators.</li>
-<li>Identify drawables or other resources that require translation and include
-them in the outgoing package for translators.</li>
-<p>Additionally, consider translating your app's store listing details —
-app title and description, release notes, and so on — as
-well as other international marketing materials.</p>
-<li>Create a terminology list that explains the meaning and usage of key terms
-used in your product, your market, or the underlying technology. Add the list to
-the outgoing package.</li>
-</ul>
-
-<h4 id="send">Send your strings for translation</h4>
-
-<p>Early in the development cycle, contact professional translation vendors for
-your target languages to get an idea of cost, lead time required, turnaround
-time, and so on. Then select a vendor and secure their services, making sure to
-include multiple iterations in the cost as a safeguard. Google Play can help you
-do this — see <a href="#gp-trans">Purchase professional
-translations</a>, below.</p>
-
-<p>As soon as your app's UI strings and design are stable, work with your
-development team to extract all of the strings and other resources from the app
-and package them together for the translator. If appropriate, you can version
-the outgoing package for later identification. </p>
-
-<p>When the outgoing package is ready, send it to the translator or share it
-with them over a cloud platform such as Google Drive. Keep a record of what you
-sent and when you sent it, to cross-reference against returning translations and
-billing invoices from the translator.</p>
-
-<p>When your translations are complete, take a preliminary look at the
-translations. Check that all files were translated, check for potential encoding
-issues, and make sure that declaration formats are intact. </p>
-
-<p>If everything looks good, carefully move the localized directories and files
-back into your app's resources. Make sure to tag the directories with the
-appropriate language and locale qualifiers so that they'll later be loaded
-properly.</p>
-
-<p>After the translations are merged back into your app, start <a
-href="#testing">testing the localized app</a>.</p>
-
-<h4 id="gp-trans">Purchase professional translations through Google Play
-<br />App Translation Service</h4>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>App Translations in Google Play</h2>
-
-<p>Hear from developers who have used the Google Play App Translation Service in <a
-href="{@docRoot}distribute/googleplay/spotlight/localization.html">Developer
-Stories: Localization in Google Play</a>.</p>
-
-<p>To make it easy to export your app's strings and import
-the finished translations into your project, try the <a
-href="{@docRoot}sdk/installing/installing-adt.html#tmgr">
-ADT Translation Manager Plugin</a>.</div>
-</div>
-
-<p>Google Play App Translation Service can help you quickly find and purchase translations of your app.
-In the Developer Console, you can browse a list of third-party vendors who are
-pre-qualified by Google to offer high-quality translation at competitive prices.
-You can upload the strings you want translated, select the languages you want to
-translate into, and select your translation vendor based on time and price.</p>
-
-<p>Once you've purchased translations, you'll receive an email from your vendor.
-Your translations are a direct business agreement between you and your vendor;
-you'll need to work directly with the vendor to manage the translation process and
-deliverables and resolve any support issues. </p>
-
-
-<h2 id="testing">5. Test your localized app</h2>
-
-<p>Once you've received your translated strings and resources and moved them
-back into your app, you need to test the app to make sure that it's ready for
-distribution to your international users. </p>
-
-<p>Manual testing can help you discover localization issues in your layouts and
-strings that can affect user satisfaction and, ultimately, your app's user
-rating. </p>
-
-<h4 id="native">Set up a test environment</h4>
-
-<p>To test your localized app, you'll need to set up an environment consisting
-of multiple devices (or virtual devices) and screen sizes, based on the markets
-and form factors you are targeting. Note that the range of devices in specific
-regions might be different. If possible, match your test devices to the actual
-devices likely to be available to users.</p>
-
-<h4 id="native">Look for common localization issues</h4>
-
-<p>On each test device, set the language or locale in Settings. Install and
-launch the app and then navigate through all of the UI flows, dialogs, and user
-interactions. Enter text in inputs. Some things to look for include:</p>
-
-<ul>
- <li>Clipped text, or text that overlaps the edge of UI elements or the
-screen</li>
- <li>Poor line wrapping</li>
- <li>Incorrect word breaks or punctuation</li>
- <li>Incorrect alphabetical sorting</li>
- <li>Incorrect layout direction or text direction</li>
- <li>Untranslated text — if your default strings are displayed instead of
-translated strings, then you may have overlooked those strings for translation
-or marked the resources directory with an incorrect language qualifier. </li>
-</ul>
-
-<p>For cases where your strings have expanded in translation and no longer fit
-your layouts, it's recommended to simplify your default text, simplify your
-translated text, or adjust your default layouts. If none of those resolves the
-issue, you can create a custom layout for the language. </p>
-
-<h4 id="default-test">Test for default resources</h4>
-
-<p>After you've tested your app in all of your supported languages and locales,
-make sure to test it again in an <em>unsupported language</em> and locale. This
-will help you make sure that your app includes a full set of default strings and
-resources, so that your app is usable to all users, regardless of their
-preferred language. </p>
-
-<h4 id="native">Review with native-language speakers</h4>
-
-<p>During or after testing, it's recommended that you let native speakers review
-your localized app. One way to do that is through beta testing with regional
-users — Google Play can help you do this. See <a href="#beta">Plan a beta
-release</a> for more information.</p>
-
-
-<h2 id="prelaunch">Prepare for international launch</h2>
-
-<p>Getting your app translated is a key part of localization, but to help your
-product attract users and gain visibility, you should prepare for launch in your
-target countries and create a broader launch and marketing plan for
-international users. </p>
-
-
-<h4 id="listing">Localize your Google Play listing</h4>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Localize your Google Play listing</h2>
-<p>Highlight what's great about your app to all of your users! Localize your
-listing in the Developer Console: </p>
-<ul>
- <li>App title and description</li>
- <li>App screenshots on phones and tablets</li>
- <li>Promotional graphics and videos.</li>
-</ul>
-</div>
-</div>
-<p>If you want your app to be successful in international markets, it's
-essential to localize your Google Play store listing. You can manage your
-localized listing in the Developer Console.</p>
-
-<p>Well before launch, decide on your app title, description, promotional text,
-marketing names and programs, and other text and images. Send your
-listing text and images for translation early, so that you have them ready when
-beta testing begins. When your translated text is available, you can add it
-through the Developer Console.</p>
-
-<p>Also, since you've made the effort to create a great localized app, let users
-know about it! Take screenshots of your UI in each language, for phones and 7-
-and 10- inch tablets. You can upload screenshots to the Developer Console for
-each language you support. These will be of great value to users browsing your
-app listing in other languages. </p>
-
-<p>It's also essential to create localized versions of your promotional graphics
-and videos. For example, your app's feature graphic might include text that
-should be translated, for maximum effectiveness, or you might want to take a
-different visual approach in one country than you do in another. You can create
-different versions of your promotional graphics for each language and upload
-them to the Developer Console. If you offer a promotional video, you can create
-localized versions of it and then add a link to the correct localized video for
-each language you support.</p>
-<h4 id="beta">Plan a beta release in key countries</h4>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Easy beta testing</h2>
-<p>Google Play now lets you set up groups of alpha and beta testers, anywhere
-around the world. Check out this powerful feature next time you sign in to the
-Developer Console.</p>
-</div>
-</div>
-
-<p>Before launching your app, it's always valuable to get real-world feedback
-from users — even more so when you are launching an app in a new language,
-country, or region. In those cases, it's highly recommended that you distribute
-a pre-release version of your app to users across your key markets and provide
-an easy means for them to provide feedback and report bugs. </p>
-
-<p>Google Play can help you set up a beta program for your app. After you sign
-in to the Developer Console and upload your APK, you can set up groups of users
-for alpha testing and beta testing the app. You can start with a small group of
-alpha testers, then move to a larger group of beta testers. Once users are
-added, they access your app's store listing and install the app. User feedback
-from alpha and beta testers goes directly to you and is not posted as public
-reviews. </p>
-
-<p>The feedback you receive will help you adjust your UI, translations, and
-store listing to ensure a great experience for users. </p>
-
-<h4 id="beta">Plan for international marketing</h4>
-
-<p>For highest visibility across countries, consider an international marketing
-or advertising campaign. The scope of the campaign might vary based on the
-budget you can support, but in general it's cost-effective and productive to do
-regional or country-specific marketing at launch and after. </p>
-
-<h4 id="badges">Create localized Google Play badges</h4>
-
-<p>If you are preparing international marketing, make sure to include a <a
-href="{@docRoot}distribute/googleplay/promote/badges.html">localized Google Play
-badge</a> to tell users you're on Google Play. You can use the badge generator
-to quickly build localized badges that you can use on web sites or marketing
-materials. High-resolution assets are also available.</p>
-
-<h4 id="deviceart">Create Localized Device Art</h4>
-
-<p>If you feature product shots of your app running on Android devices, make
-sure that those shots look great and reflect the latest in Android devices. To
-help you create high-quality marketing materials, use the drag-and-drop <a
-href="{@docRoot}distribute/promote/device-art.html">Device Art Generator</a> to
-quickly frame your screen shot on a Nexus device. </p>
-
-<h4 id="deviceart">Check your Optimization Tips</h4>
-
-<p>As you prepare for launch, make sure to sign into the Developer Console and check
-your app's Optimization Tips. The Optimization Tips let you know when you are missing parts of your localized store listing and provide other helpful reminders for a successful localized launch.</p>
-
-<h2 id="support">Support International Users after Launch</h2>
-
-<p>After you launch your app internationally, you should be prepared to support
-users in a variety of languages and time zones. The extent of your international
-user support depends on your budget, but at a minimum you should watch your
-ratings, reviews, and download stats carefully after launch.
-
-<p>Here are some suggestions: </p>
-
-<ul>
- <li>Use the app stats in the Developer Console to compare your downloads,
-installs, and uninstalls, and ratings across languages and countries—If
-your downloads or ratings are not keeping up in specific languages or countries,
-consider options for improving your product or changing your marketing approach.
-</li>
- <li>Check reviews regularly—Google Play translates all user reviews for
-you, so you can stay in touch with how international users feel about your app,
-what features they like and what issues are affecting them. By watching reviews,
-you can spot technical issues that may affect many users in a particular
-country, then fix and update your app.</li>
- <li>Respond to reviews if possible—It's good to engage with
-international users in their language or a common language if possible. If not,
-you can try using translation tools, although results may not be predictable. If
-your app gets very popular in a language, consider getting support help from
-native-language speakers. </li>
- <li>Make sure there's a link to any support resources on your web site.
-Consider setting up language-specific user groups, Google+ communities, or other
-support forums.
-</ul>
-
-<p>By following these practices for localizing your app, promoting and marketing
-to international users, and providing ongoing support, you can attract many new
-users to your app and maintain their loyalty.</p>
-
-<p>Make sure to read the <a
-href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch
-Checklist</a> to learn more about how to plan, build, and launch your app on
-Google Play. </p>
diff --git a/docs/html/distribute/googleplay/publish/preparing.jd b/docs/html/distribute/googleplay/publish/preparing.jd
deleted file mode 100644
index 6af3eea..0000000
--- a/docs/html/distribute/googleplay/publish/preparing.jd
+++ /dev/null
@@ -1,681 +0,0 @@
-page.title=Launch Checklist
-page.tags=publishing,launch,Google Play,Developer Console
-@jd:body
-
-<div id="qv-wrapper"><div id="qv">
-<h2>Checklist</h2>
-<ol>
-<li><a href="#process">1. Understand the publishing process</a></li>
-<li><a href="#policies">2. Understand Google Play policies</a></li>
-<li><a href="#core-app-quality">3. Test for core app quality</a></li>
-<li><a href="#rating">4. Determine your content rating</a></li>
-<li><a href="#countries">5. Determine country distribution</a></li>
-<li><a href="#size">6. Confirm the app's overall size</a></li>
-<li><a href="#compatibility">7. Confirm app compatibility ranges</a></li>
-<li><a href="#free-priced">8. Decide on free or priced</a></li>
-<li><a href="#inapp-billing">9. Consider In-app Billing</a></li>
-<li><a href="#pricing">10. Set prices for your apps</a></li>
-<li><a href="#localize">11. Start localization early</a></li>
-<li><a href="#graphics">12. Prepare promotional graphics</a></li>
-<li><a href="#apk">13. Build the release-ready APK</a></li>
-<li><a href="#beta">14. Plan a beta release</a></li>
-<li><a href="#product-page">15. Complete the product details</a></li>
-<li><a href="#badges">16. Use Google Play badges</a></li>
-<li><a href="#final-checks">17. Final checks and publishing</a></li>
-<li><a href="#support">18. Support users after launch</a></li>
-</ol>
-</div></div>
-
-
-<p>Before you publish your app on Google Play and distribute it to users, you
-need to get the app ready, test it, and prepare your promotional materials. </p>
-
-<p>This document helps you understand the publishing process and get ready for a
-successful product launch on Google Play. It summarizes some of the
-tasks you'll need to complete before publishing your app on Google Play, such as
-creating a signed, release-ready APK, understanding the requirements of the app,
-and creating the product page and graphic assets for your app.</p>
-
-<p>The preparation and publishing tasks are numbered to give you a rough idea of
-sequence. However, you can handle the tasks in any sequence that works for you
-or you can skip steps as appropriate.</p>
-
-<p>As you move toward publishing, a variety of support resources are available to
-you. Relevant links are provided in each step.</p>
-
-
-<h2 id="process">1. Understand the publishing process</h2>
-
-<p>Before you begin the steps in this checklist, you should take a moment to
-read and understand the overall publishing workflow and become familiar with how
-the process works. In particular, you or your development team will need to
-prepare your app for release using a process common to all Android apps.
-The <a
-href="{@docRoot}tools/publishing/publishing_overview.html">Publishing
-Workflow</a> documents provide the details on how publishing works and how to
-get an APK ready for release. </p>
-
-<p>Once you are familiar with publishing in general, read this document to
-understand the issues that you should consider when publishing an app on Google
-Play. </p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}tools/publishing/publishing_overview.html">General Publishing Overview</a></strong> — Start here for an overview of publishing options for Android apps.</li>
-<li><strong><a href="{@docRoot}tools/publishing/preparing.html">Preparing for Release</a></strong> — Developer documentation on how to build the signed, release-ready APK. This process is the same for all Android apps. </li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="policies">2. Understand Google Play policies and agreements</h2>
-
-<p>Make sure that you understand and follow the Google Play program policies
-that you accepted when registering. Google Play actively enforces the policies
-and any violations can lead to suspension of your app or, for repeated
-violations, termination of your developer account. </p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-
-<li><strong><a href="{@docRoot}distribute/googleplay/policies/index.html">Google Play Policies and Guidelines</a></strong> — An overview of Google Play policies for spam, intellectual property, and ads, with examples of common problems. </li>
-</a></strong> — Help Center document describing various content policies and processes.</li>
-
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/topic.py?hl=en&topic=2364761&parent=2365624&ctx=topic">Policy and Best Practices
-</a></strong> — Help Center document describing various content policies and processes.</li>
-
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="core-app-quality">3. Test for Core App Quality</h2>
-
-<p>Before you publish an app on Google Play, it's important to make sure that
-it meets the basic quality expectations for all Android apps, on all of the devices that you
-are targeting. You can check your app's quality by setting up a test
-environment and testing the app against a short set of <strong>core app quality criteria</strong>.
-For complete information, see the <a
-href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Guidelines</a>.
-</p>
-
-<p>If your app is targeting tablet devices, make sure that it delivers a rich, compelling
-experience to your tablet customers. See the <a
-href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality Checklist</a>
-for recommendations on ways to optimize your app for tablets.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a
-href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality
-Guidelines</a></strong> — A set of core quality criteria that all Android
-apps should meet on all targeted devices.</li>
-<li><strong><a
-href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality
-Checklist</a></strong> — A set recommendations for delivering the best
-possible experience to tablet users.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="rating">4. Determine your app's content rating</h2>
-
-<p>Google Play requires you to set a content rating for your app, which informs
-Google Play users of its maturity level. Before you publish, you should confirm
-what rating level you want to use. The available content rating levels are:</p>
-
-<ul>
-<li>Everyone</li>
-<li>Low maturity</li>
-<li>Medium maturity</li>
-<li>High maturity</li>
-</ul>
-
-<p>On their Android devices, Android users can set the desired maturity level
-for browsing. Google Play then filters apps based on the setting, so the content
-rating you select can affect the app's distribution to users. You can assign (or
-change) the content rating for your app in the Developer Console, so no changes
-are required in your app binary.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=188189">Rating your application content for Google Play</a></strong> — Help Center document describing content ratings levels and how to choose the appropriate one for your app.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="countries">5. Determine country distribution</h2>
-
-<p>Google Play lets you control what countries and territories your app is
-distributed to. For widest reach and the largest potential customer base, you
-would normally want to distribute to all available countries and territories.
-However, because of business needs, app requirements, or launch dependencies,
-you might want to exclude one or more countries from your distribution. </p>
-
-<p>It's important to determine the exact country distribution early, because it
-can affect:</p>
-<ul>
-<li>The need for localized resources in the app</li>
-<li>The need for a localized app description in the Developer Console</li>
-<li>Legal requirements for the app that may be specific to certain
-countries</li>
-<li>Time zone support, local pricing, and so on.</li>
-</ul>
-
-<p>With your country targeting in mind, you should assess what
-your localization needs are, both in your app and in its Google Play listing
-details, and start the work of localization well in advance of your
-launch target date.</p>
-
-<p>See <a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization
-Checklist</a> for key steps and considerations in the localizing process. </p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a></strong> — Overview of key steps and considerations for localizing your Android app.</li>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294&topic=2365624&ctx=topic">Supported locations for distributing applications</a></strong> on Google Play.
-.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="size">6. Confirm the app's overall size</h2>
-
-<p>The overall size of your app can affect its design and how you publish it on
-Google Play. Currently, the maximum size for an APK published on Google Play is
-<strong>50 MB</strong>. If your app exceeds that size, or if you want to offer a
-secondary download, you can use <a
-href="{@docRoot}google/play/expansion-files.html">APK Expansion Files</a>,
-which Google Play will host for free on its server infrastructure and
-automatically handle the download to devices.</p>
-
-<ul>
-<li>The maximum size for an APK published on Google Play is 50 MB.</li>
-<li>You can use up to two (2) APK Expansion Files, each up to 2 GB in size, for
-each APK.</li>
-</ul>
-
-<p>Using APK Expansion files is a convenient, cost-effective method of
-distributing large apps. However, the use of APK Expansion Files requires some
-changes in your app binary, so you will need to make those changes before
-creating your release-ready APK.</p>
-
-<p>To minimize the size of your app binary, make sure that you run the
-<a href="{@docRoot}tools/help/proguard.html">Proguard</a> tool on your code when
-building your release-ready APK.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}google/play/expansion-files.html">APK Expansion Files</a></strong>
-— Developer documentation describing APK Expansion Files and how to support them in your app.</li>
-<li><strong><a href="{@docRoot}tools/help/proguard.html">ProGuard</a></strong> — Developer
-documentation describing how to use ProGuard to shrink, optimize, and obfuscate your code prior
-to release.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="compatibility">7. Confirm the app's platform and screen compatibility ranges</h2>
-
-<p>Before publishing, it's important to make sure that your app is designed to
-run properly on the Android platform versions and device screen sizes that you
-want to target.
-
-<p>From an app-compatibility perspective, Android platform versions are defined
-by <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API level</a>. You should
-confirm the minimum version that your app is compatible with (<a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code><minSdkVersion></code></a>),
-as that will affect its distribution to Android
-devices once it is published. </p>
-
-<p>For screen sizes, you should confirm that the app runs properly and looks
-good on the range of screen sizes and densities that you want to support. You
-should confirm the minimum screen-size and density support that your app
-declares (<a
-href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code><supports-screens></code></a>),
-since that can affect its distribution to
-Android devices once it is published. </p>
-
-<p>To get a better understanding of the current device penetration of Android
-platform versions and screen sizes across all Android devices, see the <a
-href="{@docRoot}about/dashboards/index.html">Device Dashboard</a>
-charts.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}about/dashboards/index.html">Device Dashboard</a></strong> — A chart showing global percentages of devices by Android version, screen size, and level of OpenGL ES support.</li>
-<li><strong><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">Android API Levels</a></strong> — A definition of API Levels and a list of which Android platform versions they are associated with. </li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="free-priced">8. Decide whether your app will be free or priced</h2>
-
-<p>On Google Play, you can publish apps as free to download or priced. Free apps
-can be downloaded by any Android user in Google Play.
-Paid apps can be downloaded only by users who have registered a form of payment
-in Google Play, such as a credit card or Direct Carrier Billing.</p>
-
-<p>Deciding whether you app will be free or paid is important because, on Google
-Play, <strong>free apps must remain free</strong>.</p>
-
-<ul>
-<li>Once you publish your app as a free app, you cannot ever change it to being
-a priced app. However, you can still sell in-app products and
-subscriptions through Google Play's In-app Billing service.</li>
-<li>If you publish your app as a priced app, you <em>can</em> change
-it at any time to being a free app (but cannot then change it back to
-priced). You can also sell in-app products and subscriptions. </li>
-</ul>
-
-<p> If your app is be priced, or if you'll be selling in-app products,
-you need set up a Google Wallet merchant account before you can publish.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}google/play/billing/index.html">In-app Billing</a></strong> — Developer introduction to Google Play In-app Billing.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="inapp-billing">9. Consider using In-app Billing</h2>
-
-<p>Google Play <a href="{@docRoot}google/play/billing/index.html">In-app
-Billing</a> lets you sell digital content in your applications. You can use the
-service to sell a wide range of content, including downloadable content such as
-media files or photos, and virtual content such as game levels or potions.
-In-app Billing service lets you sell one-time purchases and subscriptions from
-inside your app. This can help you to monetize the app over its installed
-lifetime. </p>
-
-<p>If your are looking for more ways to monetize your app and build engagement,
-you should consider In-app Billing. The service has become very popular with
-both users and developers. To use In-app Billing, you need to make changes to
-your app binary, so you will need to complete and test your implementation
-before creating your release-ready APK.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}google/play/billing/index.html">In-app Billing</a></strong> — Developer documentation describing In-app Billing and how to support it in your app.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="pricing">10. Set prices for your products</h2>
-
-<p>If your app is priced or you will sell in-app products, Google Play lets you
-set prices for your products in a variety of currencies, for users in markets
-around the world. You can set prices individually in different currencies, so
-you have the flexibility to adjust your price according to market conditions and
-exchange rates. </p>
-
-<p>Before you publish, consider how you will price your products
-and what your prices will be in various currencies. Later, you can set prices
-in all available currencies through the Developer Console.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1169947&topic=15867&ctx=topic">Selling Apps in Multiple Currencies
-</a></strong> — Help Center document describing how pricing works in Google Play.</li>
-
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138412&topic=15867&ctx=topic">Prices and supported currencies
-</a></strong> — Help Center document listing supported currencies for pricing your apps.</li>
-
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=112622&topic=15867&ctx=topic">Transaction Fees
-</a></strong> — Help Center document describing transaction fees for priced apps and in-app products.</li>
-
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138000&topic=15867&ctx=topic">Specifying tax rates
-</a></strong> — Help Center document describing how to set tax rates for different countries. </li>
-
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="localize">11. Start localization</h2>
-
-<p>With your country targeting in mind, it's a good idea to assess your localization
-needs and start the work of localizing well in advance of your target
-launch date.</p>
-
-<p>There are at least three aspects of localization to consider:</p>
-
-<ul>
-<li>Localizing the strings, images, and other resources in your app</li>
-<li>Localizing your app's store listing details on Google Play</li>
-<li>Localizing the app's graphic assets, screenshots, and videos that accompany your store listing.</li>
-</ul>
-
-<p>See <a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a> for key steps and considerations in the localizing process. </p>
-
-<p>To localize your store listing, first create and finalize your app title, description,
-and promotional text. Collect and send all of these for localization. You can optionally
-translate the "Recent Changes" text for app updates as well. Later you can add your localized
-listing details in the Developer Console, or you can choose to let Google Play auto-translate
-your listing details into the languages you support.</p>
-
-<p>A key part of making your app listing attractive to a global customer base is
-creating localized versions of your promotional graphics, screenshots and
-videos. For example, your app's feature graphic might include text that should
-be translated, for maximum effectiveness. You can create different versions of
-your promotional graphics for each language and upload them to the Developer
-Console. If you offer a promotional video, you can create localized versions of
-it and then add a link to the correct localized video for each language you
-support.</p>
-
-<p>When your translations are complete, move them into your app resources as needed and test
-that they are loaded properly. Save your app's translated listing details for later,
-when you upload assets and configure your product details.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a></strong> — Overview of key steps and considerations for localizing your Android app.</li>
-<li><strong><a href="{@docRoot}guide/topics/resources/localization.html">Localizing with Resources</a></strong> — Developer guide to localizing resources in your app.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="graphics">12. Prepare promotional graphics, screenshots, and videos</h2>
-
-<p>When you publish on Google Play, you can supply a variety of high-quality
-graphic assets to showcase your app or brand. After you publish, these appear on
-your product details page, in store listings and search results, and elsewhere.
-These graphic assets are key parts of a successful product details page that
-attracts and engages users, so you should consider having a professional produce
-them for you. Screen shots and videos are also very important, because they show
-what your app looks like, how it's used or played, and what makes it different.</p>
-
-<p>All of your graphic assets should be designed so that they are easy to see
-and highlight your app or brand in a colorful, interesting way. The assets
-should reference the same logo and icon as users will actually find in the All
-Apps launcher once they have downloaded the app. Your graphic assets should also
-fit in well with the graphic assets of other apps published by you, which will
-be also be displayed to users on your product details page. </p>
-
-<p>To help you market your app more effectively to a global audience, Google
-Play lets you create localized versions of your promotional graphics,
-screenshots, and videos and upload them to the Developer Console. When a user
-visits your app's store listing, Google Play displays the promotional graphic,
-screenshots and video that you've provided for the user's language.</p>
-
-<p>To localize your promotional graphics, you can translate any embedded text, use
-different imagery or presentation, or change your marketing approach to best address the needs
-of users in specific languages. For example, if your feature or promotional graphic
-includes and embedded product name or tag line, you can translate that text
-and add it to a localized version of the promotional graphic.</p>
-
-<p>Because your localized graphic assets and videos are so important, you should get
-started on creating them and localizing them well in advance of your target
-publishing date. </p>
-
-<p class="note"><strong>Note:</strong> Localized promotional graphics and videos
-are supported only in the new Developer Console design.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1078870">Graphic Assets for your Application
-</a></strong> — Details about the graphic assets you need to upload before publishing.</li>
-<li><strong><a href="http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">Google Play Featured Image Guidelines
-</a></strong> — Blog post that highlights key design considerations for your app's featured image.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="apk">13. Build and upload the release-ready APK</h2>
-
-<p>When you are satisfied that your app meets your UI, compatibility, and
-quality requirements, you can build the release-ready version of the app. The
-release-ready APK is what you you will upload to the Developer Console and
-distribute to users.
-
-<p>The process for preparing a release-ready APK is the same for all apps,
-regardless of how they are distributed. Generally the process includes basic code cleanup
-and optimization, building and signing with your release key, and final testing.
-When you are finished preparing your application for release, you'll have a signed
-APK file that you can upload to the Developer Console for distribution to
-users. </p>
-
-<p>For complete details on how to create a release-ready version of your app,
-read <a href="{@docRoot}tools/publishing/preparing.html">Preparing for
-Release</a>.</p>
-
-<p>Once you have the release-ready APK in hand, you can upload it to
-the Developer Console. If necessary, you can replace the APK with a more
-recent version before publishing. </p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}tools/publishing/preparing.html">Preparing for Release</a></strong> — Essential information for preparing and packaging your app properly for distribution.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="beta">14. Plan a beta release</h2>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Easy beta testing</h2>
-<p>Google Play now lets you set up groups of alpha and beta testers, anywhere around the world. Check out this powerful feature next time you sign in to the Developer Console.</p>
-</div>
-</div>
-
-<p>Before launching your app, it's always valuable to get real-world feedback
-from users — even more so when you are launching a new app. It's highly
-recommended that you distribute a pre-release version of your app to users
-across your key markets and provide an easy means for them to provide feedback
-and report bugs. </p>
-
-<p>Google Play can help you set up a beta program for your app. After you sign
-in to the Developer Console and upload your APK, you can set up groups of users
-for alpha testing and beta testing the app. You can start with a small group of
-alpha testers, then move to a larger group of beta testers. Once users are
-added, they access your app's store listing and install the app. User feedback
-from alpha and beta testers goes directly to you and is not posted as public
-reviews. </p>
-
-<p>The feedback you receive will help you adjust your UI, translations, and
-store listing to ensure a great experience for users. </p>
-
-<h2 id="product-page">15. Complete the app's product details</h2>
-
-<p>On Google Play, your app's product information is shown to users on its
-product details page, the page that users visit to learn more about your app and
-the page from which they will decide to purchase or download your app, on their
-Android devices or on the web.</p>
-
-<p>Google Play gives you a variety of ways to promote your app and engage with
-users on your product details page, from colorful graphics, screenshots, and
-videos to localized descriptions, release details, and links to your other apps.
-As you prepare to publish your app, make sure that you take advantage of all
-that your product details page can offer, making your app as compelling as
-possible to users.</p>
-
-<p>You should begin planning your product page in advance of your target launch
-date, arranging for localized description, high-quality graphic assets,
-screenshots and video, and so on. </p>
-
-<p>As you get near your target publishing date, you should become familiar with
-all the fields, options, and assets associated with the product details configuration
-page in the Developer Console. As you collect the information and assets for the
-page, make sure that you can enter or upload it to the Developer Console, until
-the page is complete and ready for publishing. </p>
-
-<p>After you've set your app's geographic targeting in the Developer Console,
-remember to add your localized product details, promotional graphics, and so on, for all of the
-languages that you support.</p>
-
-<p>If your app is targeting tablet devices, make sure to include at least one screen
-shot of the app running on a tablet, and highlight your app's support for tablets
-in the app description, release notes, promotional campaigns, and elsewhere.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113475&topic=2365760&ctx=topic">Category types
-</a></strong> — Help Center document listing available categories for apps.</li>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1078870&topic=2365760&ctx=topic">Graphic Assets for your Application
-</a></strong> — Help Center document describing the various graphics you can add to your product listing.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="badges">16. Use Google Play badges and links in your promotional
-campaigns</h2>
-
-<p>Google Play badges give you an officially branded way of promoting your app
-to Android users. Use the <a
-href="{@docRoot}distribute/googleplay/promote/badges.html">Google Play Badge
-generator</a> to quickly create badges to link users to your products from web
-pages, ads, reviews, and more. You can also use special <a
-href="{@docRoot}distribute/googleplay/promote/linking.html">link formats</a>
-to link directly to your product details page, to a list of your products, or to
-search results.</p>
-
-<p>To help your app get traction after launch, it's strongly recommended that you support
-launch with a promotional campaign that announces your product through many channels as
-possible, in as many countries as possible. For example, you can promote the launch
-using ad placements, social network or blog posts, video and other media, interviews
-and reviews, or any other channel available.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}distribute/googleplay/promote/badges.html">Google Play Badges</a></strong> — Generate a badge to bring users to your app in Google Play.</li>
-<li><strong><a href="{@docRoot}distribute/googleplay/promote/linking.html">Linking to Your Products</a></strong> — Link formats that you can use to bring users to your app in Google Play.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="final-checks">17. Final checks and publishing</h2>
-
-<p>When you think you are ready to publish, sign in to the Developer Console and take a few moments for a few
-final checks.</p>
-
-<p>Make sure that: </p>
-
-<ul>
-<li>Your developer profile has the correct information and is linked to the proper Google Wallet merchant account (if you are selling products).</li>
-<li>You have the right version of the app uploaded.</li>
-<li>All parts of your Product Details are ready, including all graphic assets, screenshots, video, localized descriptions, and so on. </li>
-<li>You have set your app's pricing to free or priced.</li>
-<li>You have set country (and carrier) targeting and priced your products (if appropriate) in buyer currencies</li>
-<li>"Compatible devices" shows that your app is actually reaching the devices that you are targeting. If not, you should check with your development team on the apps requirements and filtering rules. </li>
-<li>You have provided the correct link to your web site and the correct support email address.</li>
-<li>Your app does not violate content policy guidelines.</li>
-<li>You have acknowledged that your app meets the guidelines for Android content on Google Play and also US export laws. </li>
-</ul>
-
-<p>Your app is now ready to publish!</p>
-
-<p>If you are releasing an update, make sure to read the <a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113476&topic=2365760&ctx=topic">requirements for publishing updates</a>. </p>
-
-<p>When you are ready, click the <strong>Publish</strong> button in the Developer Console. Within a few hours, your app will become available to users and your product page will be appear in Google Play for browsing, searching, or linking from your promotional campaigns.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://www.android.com/us/developer-content-policy.html">Google Play Developer Program Policies</a></strong> — Guidelines for what is acceptable conent in Google Play. Please read and understand the policies before publishing. </li>
-<li><strong><a href="{@docRoot}distribute/googleplay/promote/linking.html">Updates</a></strong> — Requirements for app updates in Google Play.</li>
-<li><strong><a href="{@docRoot}support.html">Developer Support</a></strong> — Support resources that you can use to find answers and report issues.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="support">18. Support users after launch</h2>
-
-<p>After you publish an app or an app update, it's crucial for you to support
-your customers. Prompt and courteous support can provide a better experience for
-users that results in better ratings and more positive reviews for your
-products. Users are likely to be more engaged with your app and recommend it if
-you are responsive to their needs and feedback. This is especially true after
-publishing if you are using a coordinated promotional campaign.</p>
-
-<p>There are a number of ways that you can keep in touch with users and offer
-them support. The most fundamental is to provide your <em>support email
-address</em> on your product details page. Beyond that, you can provide support
-in any way you choose, such as a forum, mailing list or a Google+ page. The
-Google Play team does provide user support for downloading, installing and
-payments issues, but issues that fall outside of these topics will fall under
-your domain. Examples of issues you can support include: feature requests,
-questions about using the app and questions about compatibility settings. </p>
-
-<p>After publishing, plan to: </p>
-<ul>
-<li>Check your ratings and reviews frequently on your app's product details
-page. Watch for recurring issues that could signal bugs or other issues. </li>
-<li>Be mindful of new Android platform version launches, as compatibility
-settings for your apps might need to be updated.</li>
-<li>Put a link to your support resources on your web site and set up any other
-support such as forums.</li>
-<li>Provide an appropriate support email address on your product details page
-and respond to users when they take the time to email you.</li>
-<li>Beyond the automatic refund window offered by Google Play, be generous with
-your own refund policy, as satisfied users will be more likely to purchase in
-the future. </li>
-<li>Acknowledge and fix issues in your app. It helps to be transparent and
-list known issues on your product details page proactively. </li>
-<li>Publish updates as frequently as you are able, without sacrificing quality
-or annoying users with too-frequent updates. </li>
-<li>With each update, make sure to provide a summary of what's changed. You can
-enter this information in the Developer Console. Users will read it and
-appreciate that you are serious about improving the quality of your app. </li>
-</ul>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113477&topic=2364761&ctx=topic">Supporting your users
-</a></strong> — Help Center document describing options for supporting users.</li>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1153479">In-app Billing</a></strong> — Help Center document describing how to correctly set up In-app Billing.</li>
-<li><strong><a href="https://support.google.com/payments/answer/2741495?rd=1">Issuing Refunds</a></strong> — -- Help Center document describing how to issue refunds.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-
diff --git a/docs/html/distribute/googleplay/publish/register.jd b/docs/html/distribute/googleplay/publish/register.jd
deleted file mode 100644
index faade81..0000000
--- a/docs/html/distribute/googleplay/publish/register.jd
+++ /dev/null
@@ -1,80 +0,0 @@
-page.title=Get Started with Publishing
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>Help topics</h2>
-<ul>
- <li><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113468">Developer Registration</a></li>
- <li><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294&topic=2365624&ctx=topic">Supported Locations for Distributing Apps</a></li>
- <li><a href="http://support.google.com/googleplay/android-developer/bin/topic.py?hl=en&topic=2364761">Policy and Best Practices</a></li>
- <li><a href="http://support.google.com/googleplay/android-developer/">Developer Support</a></li>
-</ul>
-
-<h2>Get Started</h2>
-<ol>
- <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>You can set up to start publishing on Google Play in only a few minutes. Here's how you do it: </p>
-
-<ul>
-<li>Register for a Google Play publisher account</li>
-<li>If you will sell apps, set up a Google Wallet Merchant Account</li>
-<li>Explore the Google Play Developer Console and learn about the tools for publishing</li>
-</ul>
-
-
-<h3>Register for a publisher account</h3>
-
-<p>The first step is to visit the Google Play Developer Console and register for a publisher account.</p>
-
-<p>Here's what you will do during registration: </p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Tips</h2>
- <ul>
- <li>You need a Google account to register. You can create one during the process. </li>
- <li>If you are an organization, consider registering a new Google account rather than using a personal account.</li>
- <li>Review the <a href="https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294">developer countries</a> and <a href="https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=150324">merchant countries</a> where you can distribute and sell apps.</li>
- </ul>
-</div></div>
-
-
-<ol>
-<li>Visit the Google Play Developer Console at <a
-href="https://play.google.com/apps/publish/">https://play.google.com/apps/publish/</a>.
-<li>Enter basic information about your <strong>developer identity</strong> — developer
-name, email address, and so on. You can modify this information later.</li>
-<li>Read and accept the <strong>Developer Distribution Agreement</strong> that applies to your
-country or region. Note that apps and store listings that you publish on Google Play must comply
-with the Developer Program Policies and US export law,</li>
-<li>Pay a <strong>$25 USD registration fee</strong> using Google Wallet. If you don't have
-a Google Wallet account, you can quickly set one up during the process.</li>
-</ol>
-
-<p>When your registration is verified, you’ll be notified at the email address you specified during registration.</p>
-
-<h3>Set up a Google Wallet Merchant account</h3>
-
-<p>If you want to sell products on Google Play — priced apps, in-app products, or subscriptions — you will also need to set up a Google Wallet Merchant Account. You can do that at any time, but make sure to first review the list of <a href="https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=150324">merchant countries</a>.</p>
-
-<p>To set up a Merchant account from the Developer Console:</p>
-
-<ol>
-<li><strong>Sign in</strong> to your Google Play Developer Console at
-<a href="https://play.google.com/apps/publish/">https://play.google.com/apps/publish/</a>
-<li>Open <strong>Financial reports</strong> <img src="{@docRoot}images/distribute/console-reports.png"
- style="vertical-align:baseline;margin:0"> on the side navigation.
-<li>Click <strong>Setup a Merchant Account now</strong>.</li>
-</ol>
-
-<p>This takes you to the Google Wallet site to sign up as a Merchant;
-you'll need information about your business available to complete this step.</p>
-
-<h3>Explore the Developer Console</h3>
-<p>When your registration is verified, you can sign in to your Developer Console, which will be the home for your app publishing operations and tools on Google Play. </p>
diff --git a/docs/html/distribute/googleplay/quality/core.jd b/docs/html/distribute/googleplay/quality/core.jd
deleted file mode 100644
index 9e23bcc..0000000
--- a/docs/html/distribute/googleplay/quality/core.jd
+++ /dev/null
@@ -1,804 +0,0 @@
-page.title=Core App Quality Guidelines
-@jd:body
-
-<div id="qv-wrapper"><div id="qv">
-<h2>Quality Criteria</h2>
- <ol>
- <li><a href="#ux">Design and Interaction</a></li>
- <li><a href="#fn">Functionality</a></li>
- <li><a href="#ps">Performance and Stability</a></li>
- <li><a href="#listing">Google Play</a></li>
-
- </ol>
-
- <h2>Testing</h2>
- <ol>
- <li><a href="#test-environment">Setting Up a Test Environment</a></li>
- <li><a href="#tests">Test Procedures</a></li>
- </ol>
-
- <h2>You Should Also Read</h2>
- <ol>
- <li><a href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality Checklist</a></li>
- <li><a href="{@docRoot}distribute/googleplay/strategies/app-quality.html">Improving App Quality</a></li>
- </ol>
-
-
-</div>
-</div>
-
-<p>App quality directly influences the long-term success of your app—in
-terms of installs, user rating and reviews, engagement, and user retention.
-Android users expect high-quality apps, even more so if they've spent money on
-them.</p>
-
-<p>This document helps you assess basic aspects of quality in your app through a
-compact set of <em>core app quality criteria</em> and associated tests. All
-Android apps should meet these criteria.</p>
-
-<p>Before publishing your app, make sure to test it against these criteria to
-ensure that it functions well on many devices, meets Android standards for
-navigation and design, and is prepared for promotional opportunities in the
-Google Play Store. Your testing will go well beyond what's described here—the
-purpose of this document is to specify the essential characteristics
-of basic quality so that you can include them in your test plans.</p>
-
-<p>If your app is targeting tablet devices, make sure that it delivers a rich,
-compelling experience to your tablet customers. See the <a
-href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality
-Checklist</a> for recommendations on ways to optimize your app for tablets.</p>
-
-
-<h2 id="ux">Visual Design and User Interaction</h2>
-
-<p>These criteria ensure that your app provides standard Android visual design
-and interaction patterns where appropriate, for a consistent and intuitive
-user experience.</p>
-
-<table>
- <tr>
- <th style="width:2px;">
- Area
- </th>
- <th style="width:54px;">
- ID
- </th>
-
-
- <th>
- Description
- </th>
- <th style="width:54px;">
- Tests
- </th>
- </tr>
- <tr id="UX-B1">
- <td>Standard design</td>
- <td>
- UX-B1
- </td>
- <td>
- <p style="margin-bottom:.5em;">App follows <a href="{@docRoot}design/index.html">Android Design</a> guidelines and uses common <a href="{@docRoot}design/patterns/index.html">UI patterns and icons</a>:</p>
- <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
- <li>App does not redefine the expected function of a system icon (such as the Back button).</li>
- <li>App does not replace a system icon with a completely different icon if it triggers the standard UI behavior. </li>
- <li>If the app provides a customized version of a standard system icon, the icon strongly resembles the system icon and triggers the standard system behavior.</li>
- <li>App does not redefine or misuse Android UI patterns, such that icons or behaviors could be misleading or confusing to users.</li>
- </ol>
- </td>
- <td><a href="#core">CR-all</a></td>
- </tr>
-
-
- <tr>
- <td rowspan="3">Navigation</td>
- <td id="UX-N1">
- UX-N1
- </td>
-
- <td>
- <p>App supports standard system <a href="{@docRoot}design/patterns/navigation.html">Back button navigation</a> and does not make use of any custom, on-screen "Back button" prompts.</p>
- </td>
- <td><a href="#core">CR-3</a></td>
- </tr>
- <tr>
- <td id="UX-N2">
- UX-N2
- </td>
- <td>
- <p>All dialogs are dismissable using the Back button.</p>
- </td>
- <td><a href="#core">CR-3</a></td>
- </tr>
-
- <tr id="UX-N3">
- <td>
- UX-N3
- </td>
- <td>
- Pressing the Home button at any point navigates to the Home screen of the device.
- </td>
- <td><a href="#core">CR-1</a></td>
- </tr>
- <tr id="UX-S1">
- <td rowspan="2">Notifications</td>
- <td>
- UX-S1
- </td>
- <td>
- <p style="margin-bottom:.5em;">Notifications follow Android Design <a href="{@docRoot}design/patterns/notifications.html">guidelines</a>. In particular:</p>
- <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
- <li>Multiple notifications are stacked into a single notification object, where possible.</li>
- <li>Notifications are persistent only if related to ongoing events (such as music playback or a phone call).</li>
- <li>Notifications do not contain advertising or content unrelated to the core function of the app, unless the user has opted in.</li>
- </ol>
-
- </td>
- <td><a href="#core">CR-11</a></td>
- </tr>
- <tr id="UX-S2">
-
- <td>
- UX-S2
- </td>
-
- <td>
-
- <p style="margin-bottom:.5em;">App uses notifications only to:</p>
- <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
- <li>Indicate a change in context relating to the user personally (such as an incoming message), or</li>
- <li>Expose information/controls relating to an ongoing event (such as music playback or a phone call).</li>
- </ol>
- </td>
- <td><a href="#core">CR-11</a></td>
- </tr>
-
- </table>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}design/index.html">Android Design</a></strong> — Overview of design and user experience best practices for Android apps. </li>
-<li><strong><a href="{@docRoot}design/patterns/navigation.html">Navigation with Back and Up</a></strong> — Android Design document describing standard navigation patterns. </li>
-<li><strong><a href="{@docRoot}design/patterns/actionbar.html">Action Bar</a></strong> — Android Design document describing how to use the Action Bar. </li>
-<li><strong><a href="{@docRoot}design/style/iconography.html">Iconography</a></strong> — Android Design describing how to use various types of icons.</li>
-<li><strong><a href="{@docRoot}design/patterns/notifications.html">Notifications</a></strong> — Android Design document describing how to design and use notifications. </li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="fn">Functionality</h2>
-
-<p>These criteria ensure that your app provides expected functional behavior with the appropriate level of permissions. </p>
-
-<table>
- <tr>
- <th style="width:2px;">
- Area
- </th>
- <th style="width:54px;">
- ID
- </th>
-
-
- <th>
- Description
- </th>
- <th style="width:54px;">
- Tests
- </th>
- </tr>
-
- <tr id="FN-P1">
- <td rowspan="2">Permissions</td>
- <td>
- FN-P1
- </td>
- <td>App requests only the <em>absolute minimum</em> permissions that it needs to support core functionality.
- </td>
- <td rowspan="2"><a href="#core">CR-11</a></td>
- </tr>
- <tr id="FN-P2">
- <td>
- FN-P2
- </td>
- <td><p style="margin-bottom:.5em;">App does not request permissions to access sensitive data (such as Contacts or the System Log) or services that can cost the user money (such as the Dialer or SMS), unless related to a core capability of the app.
- </td>
- </tr>
- <tr id="FN-L1">
- <td>Install location</td>
- <td>
- FN-L1
- </td>
- <td>
- <p style="margin-bottom:.5em;">App functions normally when installed on SD card (if supported by app).</p>
-
- <p style="margin-bottom:.25em;">Supporting installation to SD card is recommended for most large apps (10MB+). See the <a href="{@docRoot}guide/topics/data/install-location.html">App Install Location</a> developer guide for information about which types of apps should support installation to SD card.</p>
- </td>
-
- <td><a href="#SD-1">SD-1</a>
- </td>
- </tr>
- <tr id="FN-A1">
- <td rowspan="4">Audio</td>
- <td>
- FN-A1
- </td>
-
- <td>
- Audio does not play when the screen is off, unless this is a core feature (for example, the app is a music player).
- </td>
- <td><a href="#core">CR-7</a></td>
- </tr>
- <tr id="FN-A2">
- <td>
- FN-A2
- </td>
- <td>
- Audio does not <a href="http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html">play behind the lock screen</a>, unless this is a core feature.
- </td>
- <td><a href="#core">CR-8</a></td>
- </tr>
- <tr id="FN-A3">
- <td>
- FN-A3
- </td>
- <td>
- Audio does not play on the home screen or over another app, unless this is a core feature.
- </td>
- <td><a href="#core">CR-1, <br />CR-2</a></td>
- </tr>
- <tr id="FN-A4">
- <td>
- FN-A4
- </td>
- <td>
- Audio resumes when the app returns to the foreground, or indicates to the user that playback is in a paused state.
- </td>
- <td><a href="#core">CR-1, CR-8</a></td>
- </tr>
- <tr id="FN-U1">
- <td rowspan="3">UI and Graphics</td>
- <td>
- FN-U1
- </td>
- <td>
- <p style="margin-bottom:.5em;">App supports both landscape and portrait orientations (if possible).</em></p>
- <p style="margin-bottom:.25em;">Orientations expose largely the same features and actions and preserve functional parity.
- Minor changes in content or views are acceptable.</p>
- </td>
- <td><a href="#core">CR-5</a></td>
- </tr>
- <tr id="FN-U2">
- <td>
- FN-U2
- </td>
- <td>
- <p style="margin-bottom:.5em;">App uses the whole screen in both orientations and does not letterbox to account for orientation changes.</em></p>
- <p style="margin-bottom:.25em;">Minor letterboxing to compensate for small variations in screen geometry is acceptable.</p>
- </td>
- <td><a href="#core">CR-5</a></td>
- </tr>
- <tr id="FN-U3">
- <td>
- FN-U3
- </td>
- <td>
- <p style="margin-bottom:.5em;">App correctly handles rapid transitions between display orientations without rendering problems.</p>
- </td>
- <td><a href="#core">CR-5</a></td>
- </tr>
-
- <tr id="FN-S1">
- <td rowspan="2">User/app state</td>
- <td>
- FN-S1
- </td>
- <td>
- <p style="margin-bottom:.5em;">App should not leave any services running when the app is in the background, unless related to a core capability of the app.</p>
- <p style="margin-bottom:.25em;">For example, the app should not leave services running to maintain a network connection for notifications, to maintain a Bluetooth connection, or to keep the GPS powered-on.</p>
- </td>
- <td><a href="#core">CR-6</a></td>
- </tr>
- <tr id="FN-S2">
- <td>
- FN-S2
- </td>
- <td>
- <p style="margin-bottom:.5em;">App correctly preserves and restores user or app state.</p>
- <p style="margin-bottom:.25em;">App preserves user or app state when leaving the foreground and prevents accidental data loss due to back-navigation and other state changes. When returning to the foreground, the app must restore the preserved state and any significant stateful transaction that was pending, such as changes to editable fields, game progress, menus, videos, and other sections of the app or game.</p>
- <ol style="margin-bottom:.25em;list-style-type:lower-alpha">
- <li>When the app is resumed from the Recents app switcher, the app returns the user to the exact state in which it was last used.</li>
- <li>When the app is resumed after the device wakes from sleep (locked) state, the app returns the user to the exact state in which it was last used.</li>
- <li>When the app is relaunched from Home or All Apps, the app restores the app state as closely as possible to the previous state.</li>
- <li>On Back keypresses, the app gives the user the option of saving any app or user state that would otherwise be lost on back-navigation.</li>
- </ol>
- </td>
- <td><a href="#core">CR-1, CR-3, CR-5</a></td>
- </tr>
-
-</table>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html">Making Android Apps that Play Nice</a></strong> — Developer blog post discussing the audio lifecycle and expected audio behaviors for Android apps. </li>
-<li><strong><a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back Stack</a></strong> — Developer guide describing how to implement back-navigation.</li>
-<li><strong><a href="{@docRoot}training/basics/activity-lifecycle/recreating.html">Recreating an Activity</a></strong> — Android Training class the shows how to preserve and restore app state.</li>
-
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="ps">Performance and Stability</h2>
-
-<p>To ensure a high user rating, your app needs to perform well and stay
-responsive on all of the devices and form factors and screens that it is
-targeting. These criteria ensure that the app provides the basic performance,
-stability, and responsiveness expected by users.</p>
-
-<table>
- <tr>
- <th style="width:2px;">
- Area
- </th>
- <th style="width:54px;">
- ID
- </th>
- <th>
- Description
- </th>
- <th style="width:54px;">
- Tests
- </th>
- </tr>
- <tr id="PS-S1">
- <td>Stability</td>
- <td>
- PS-S1
- </td>
- <td>
- App does not crash, force close, freeze, or otherwise function abnormally on any targeted device.
- </td>
- <td><a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>, <a href="#HA-1">HA-1</a></td>
- </tr>
-
- <tr id="PS-P1">
- <td rowspan="2">Performance</td>
- <td>
- PS-P1
- </td>
- <td>
- App loads quickly or provides onscreen feedback to the user (a progress indicator or similar cue) if the app
- takes longer than two seconds to load.
- </td>
- <td>
- <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>
- </td>
- </tr>
- <tr id="PS-P2">
-
- <td>
- PS-P2
- </td>
- <td>
- With StrictMode enabled (see <a href="#strictmode">StrictMode Testing</a>, below), no red flashes (performance warnings from StrictMode) are visible when exercising the app, including
- during game play, animations and UI transitions, and any other part of the app.
- </td>
- <td>
- <a href="#PM-1">PM-1</a>
- </td>
- </tr>
- <tr id="PS-M1">
- <td>Media</td>
- <td>
- PS-M1
- </td>
- <td>
- Music and video playback is smooth, without crackle, stutter, or other artifacts, during normal app usage and load.
- </td>
- <td>
- <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>, <a href="#HA-1">HA-1</a>
- </td>
- </tr>
- <tr id="PS-V1">
- <td rowspan="2">Visual quality</td>
- <td>
- PS-V1
- </td>
- <td>
- <p style="margin-bottom:.5em;">App displays graphics, text, images, and other UI elements without noticeable distortion, blurring, or pixelation.</p>
-
- <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
- <li>App provides high-quality graphics for all targeted screen sizes and form factors, including for <a href="{@docRoot}distribute/googleplay/quality/tablet.html">larger-screen devices such as tablets</a>.</li>
- <li>No aliasing at the edges of menus, buttons, and other UI elements is visible.</li>
- </ol>
- </td>
- <td rowspan="2"><a href="#core">CR-all</a></td>
- </tr>
- <tr id="PS-V2">
- <td>
- PS-V2
- </td>
- <td>
- <p style="margin-bottom:.5em;">App displays text and text blocks in an acceptable manner. </p>
-
- <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
- <li>Composition is acceptable in all supported form factors, including for larger-screen devices such as tablets.</li>
- <li>No cut-off letters or words are visible.</li>
- <li>No improper word wraps within buttons or icons are visible.</li>
- <li>Sufficient spacing between text and surrounding elements.</li>
- </ol>
- </td>
-
- </tr>
-</table>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://android-developers.blogspot.com/2010/12/new-gingerbread-api-strictmode.html">Using StrictMode</a></strong> — Developer blog post discussing StrictMode and how to use it for performance monitoring in your app. </li>
-<li><strong><a href="{@docRoot}guide/practices/responsiveness.html">Designing for Responsiveness</a></strong> — Developer guide describing best practices for keeping your app responsive.</li>
-<li><strong><a href="http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html">Multithreading for Performance</a></strong> — Developer blog post discussing ways to improve performance through multi-threading.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="listing">Google Play</h2>
-
-<p>To launch your app successfully on Google Play, raise its ratings, and make
-sure that it is ready for promotional activities in the store, follow the
-criteria below.</p>
-
-<table>
- <tr>
- <th style="width:2px;">
- Area
- </th>
- <th style="width:54px;">
- ID
- </th>
- <th>
- Description
- </th>
- <th style="width:54px;">
- Tests
- </th>
- </tr>
- <tr id="GP-P1">
- <td rowspan="2">Policies</td>
- <td>
- GP-P1
- </td>
- <td>
- App strictly adheres to the terms of the <a href="http://play.google.com/about/developer-content-policy.html">Google Play Developer Content Policy</a> and does not offer inappropriate content, does not use intellectual property or brand of others, and so on.
- </td>
- <td>
- <a href="#gp">GP-all</a>
- </td>
- </tr>
-
- <tr id="GP-P2">
- <td>
- GP-P2
- </td>
- <td>
- <p style="margin-bottom:.5em;">App maturity level is set appropriately, based on the
- <a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=188189">Content Rating Guidelines</a>.</p>
-
- <p style="margin-bottom:.25em;">Especially, note that apps that request permission to use the device location cannot be given the maturity level "Everyone". </p>
- </td>
- <td>
- <a href="#gp">GP-1</a>
- </td>
- </tr>
-
- <tr id="GP-D1">
- <td rowspan="3">App Details Page</td>
- <td>
- GP-D1
- </td>
- <td>
- <p style="margin-bottom:.5em;">App feature graphic follows the guidelines outlined in this
- <a href="http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">blog post</a>. Make sure that:</p>
-
- <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
- <li>The app listing includes a high-quality feature graphic.</li>
- <li>The feature graphic does not contain device images, screenshots, or small text that will be illegible when scaled down and displayed on the smallest screen size that your app is targeting.</li>
- <li>The feature graphic does not resemble an advertisement.</li>
- </ol>
-
-
- </td>
-
- <td>
- <a href="#gp">GP-1, GP-2</a>
- </td>
- </tr>
- <tr id="GP-D2">
- <td>
- GP-D2
- </td>
- <td>
- App screenshots and videos do not show or reference non-Android devices.
- </td>
- <td rowspan="2"><a href="#gp">GP-1</a></td>
- </tr>
- <tr id="GP-D3">
- <td>
- GP-D3
- </td>
- <td>
- App screenshots or videos do not
- represent the content and experience of your app in a misleading way.
- </td>
- </tr>
- <tr id="GP-X1">
- <td>User Support</td>
- <td>
- GP-X1
- </td>
- <td>Common user-reported bugs in the Reviews tab of the Google Play page are addressed if they are
- reproducible and occur on many different devices. If a bug occurs on only a few devices,
- you should still address it if those devices are particularly popular or new.
- </td>
-
- <td>
- <a href="#gp">GP-1</a>
- </td>
-
- </tr>
-</table>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="https://play.google.com/apps/publish/">Launch Checklist</a></strong> — Recommendations on how to prepare your app for publishing, test it, and launch successfully on Google Play.</li>
-<li><strong><a href="http://play.google.com/about/developer-content-policy.html">Google Play Developer Program Policies</a></strong> — Guidelines for what is acceptable conent in Google Play. Please read and understand the and understand the policies before publishing.</p>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=188189">Rating your application content for Google Play</a></strong> — Help Center document describing content ratings levels and how to choose the appropriate one for your app.</li>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1078870">Graphic Assets for your Application
-</a></strong> — Details about the graphic assets you need to upload before publishing.</li>
-<li><strong><a href="http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">Google Play Featured Image Guidelines
-</a></strong> — Blog post discussing how to create an attractive, effective Featured Image for your app.</li>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113477&topic=2364761&ctx=topic">Supporting your users
-</a></strong> — Help Center document describing options for supporting users.</li>
-</ul>
-</td></tr>
-</table>
-
-
-<h2 id="test-environment">Setting Up a Test Environment</h2>
-
-<p>To assess the quality of your app, you need to set up a suitable
-hardware or emulator environment for testing. </p>
-
-<p>The ideal test environment would
-include a small number of actual hardware devices that represent key form
-factors and hardware/software combinations currently available to consumers.
-It's not necessary to test on <em>every</em> device that's on the market —
-rather, you should focus on a small number of representative devices, even using
-one or two devices per form factor. </p>
-
-<p>If you are not able to obtain actual hardware devices for testing, you should
-<a href="{@docRoot}tools/devices/index.html">set up emulated devices (AVDs)</a>
-to represent the most common form factors and
-hardware/software combinations.</p>
-
-<p>To go beyond basic testing, you can add more devices, more form factors, or
-new hardware/software combinations to your test environment. You can also
-increase the number or complexity of tests and quality criteria. </p>
-
-
-<h2 id="tests">
- Test Procedures
-</h2>
-
-<p>These test procedures help you discover various types of quality issues in
-your app. You can combine the tests or integrate groups of tests together in
-your own test plans. See the sections above for references that associate
-specific criteria with specific tests. </p>
-
-<table>
- <tr>
- <th style="width:2px;">
- Type
- </th>
- <th style="width:54px;">
- Test
- </th>
- <th>
- Description
- </th>
- </tr>
- <tr>
- <td rowspan="12" id="core">Core Suite</td>
- <td>
- CR-0
- </td>
- <td><p style="margin-bottom:.5em;">Navigate to all parts of the app — all screens, dialogs, settings, and all user flows. </p>
-
- <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
- <li>If the application allows for editing or content creation, game play, or media playback, make sure to enter those flows to create or modify content.</li>
- <li>While exercising the app, introduce transient changes in network connectivity, battery function, GPS or location availability, system load, and so on. </li>
- </ol>
- </td>
- </tr>
- <tr id="tg2">
- <td id="core">
- CR-1
- </td>
- <td>From each app screen, press the device's Home key, then re-launch the app from the All Apps screen.
- </td>
- </tr>
- <tr id="CR-2">
- <td>
- CR-2
- </td>
- <td>From each app screen, switch to another running app and then return to the app under test using the Recents app switcher.
- </td>
- </tr>
-
- <tr id="CR-3">
- <td>
- CR-3
- </td>
- <td>From each app screen (and dialogs), press the Back button.
- </td>
- </tr>
- <tr id="CR-5">
- <td>
- CR-5
- </td>
- <td>From each app screen, rotate the device between landscape and portrait orientation at least three times.
- </td>
- </tr>
- <tr id="CR-6">
- <td>
- CR-6
- </td>
- <td>Switch to another app to send the test app into the background. Go to Settings and check whether the test app has any services running while in the background. In Android 4.0 and higher, go to the Apps screen and find the app in the "Running" tab. In earlier versions, use "Manage Applications" to check for running services.
- </td>
- </tr>
-
-
- <tr id="CR-7">
- <td>
- CR-7
- </td>
- <td>
- Press the power button to put the device to sleep, then press the power button again to
- awaken the screen.
- </td>
- </tr>
- <tr id="CR-8">
- <td>
- CR-8
- </td>
- <td>
- Set the device to lock when the power button is pressed. Press the power button to put the device to sleep, then press the power button again to
- awaken the screen, then unlock the device.
- </td>
- </tr>
- <tr id="CR-9">
- <!-- Hardware features -->
- <td>
- CR-9
- </td>
- <td>
- For devices that have slide-out keyboards, slide the keyboard in and out at least once. For devices that have keyboard docks, attach the device to the keyboard dock.
- </td>
- </tr>
- <tr id="CR-10">
- <td>
- CR-10
- </td>
- <td>
- For devices that have an external display port, plug-in the external display.
- </td>
- </tr>
- <tr id="CR-11">
- <td>
- CR-11
- </td>
- <td>Trigger and observe in the notications drawer all types of notifications that the app can display. Expand notifications where applicable (Android 4.1 and higher), and tap all actions offered.</td>
- </tr>
- <tr id="CR-12">
- <td>
- CR-12
- </td>
- <td>Examine the permissions requested by the app by going to Settings > App Info.
- </td>
- </tr>
- <tr id="tg3">
- <td>Install on SD Card</td>
- <td>
- SD-1
- </td>
- <td>
- <p style="margin-bottom:.5em;">Repeat <em>Core Suite</em> with app installed to <a href="{@docRoot}guide/topics/data/install-location.html">device SD card</a> (if supported by app).</p>
-
- <p style="margin-bottom:.25em;">To move the app to SD card, you can use Settings > App Info > Move to SD Card.</p>
- </td>
- </tr>
- <tr id="tg3">
- <td>Hardware acceleration</td>
- <td>
- HA-1
- </td>
- <td>
- <p style="margin-bottom:.5em;">Repeat <em>Core Suite</em> with hardware acceleration enabled.</p>
-
- <p style="margin-bottom:.25em;">To force-enable hardware acceleration (where supported by device), add <code>hardware-accelerated="true"</code> to the <code><application></code> in the app manifest and recompile.</p>
- </td>
- </tr>
- <tr id="tg3">
- <td>Performance Monitoring</td>
- <td>
- PM-1
- </td>
- <td>
- <p style="margin-bottom:.5em;">Repeat <em>Core Suite</em> with StrictMode profiling enabled <a href="#strictmode">as described below</a>. <p style="margin-bottom:.25em;">Pay close attention to garbage collection and its impact on the user experience.</p>
- </td>
- </tr>
- <tr id="gp">
- <td rowspan="3">Google Play</td>
- <td>
- GP-1
- </td>
- <td>
- Sign into the <a href="https://play.google.com/apps/publish/">Developer Console</a> to review your developer profile, app description, screenshots, feature graphic, maturity settings, and user feedback.
- </td>
- </tr>
- <tr id="GP-2">
- <td>
- GP-2
- </td>
- <td>
- Download your feature graphic and screenshots and scale them down to match the display sizes on the devices and form factors you are targeting.
- </td>
- </tr>
- <tr id="GP-3">
- <td>
- GP-3
- </td>
- <td>
- Review all graphical assets, media, text, code libraries, and other content packaged in the app or expansion file download.
- </td>
- </tr>
- <tr id="GP-4">
- <td>Payments</td>
- <td>
- GP-4
- </td>
- <td>
- Navigate to all screens of your app and enter all in-app purchase flows.
- </td>
-</tr>
-
-</table>
-
-<h3 id="strictmode">
-Testing with StrictMode
-</h3>
-
-<p>For performance testing, we recommend enabling
-{@link android.os.StrictMode} in your app
-and using it to catch operations on the main thread and other threads that could
-affect performance, network accesses, file reads/writes, and so on.</p>
-
-<p>You can set up a monitoring policy per thread using
-{@link android.os.StrictMode.ThreadPolicy.Builder} and enable all supported monitoring in the
-<code>ThreadPolicy</code> using
-{@link android.os.StrictMode.ThreadPolicy.Builder#detectAll()}.</p>
-
-<p>Make sure to enable <strong>visual notification</strong> of policy violations
-for the <code>ThreadPolicy</code> using {@link android.os.StrictMode.ThreadPolicy.Builder#penaltyFlashScreen() penaltyFlashScreen()}.</p>
diff --git a/docs/html/distribute/googleplay/quality/index.jd b/docs/html/distribute/googleplay/quality/index.jd
deleted file mode 100644
index ef537b1..0000000
--- a/docs/html/distribute/googleplay/quality/index.jd
+++ /dev/null
@@ -1,45 +0,0 @@
-page.title=App Quality
-@jd:body
-
-<p>App quality directly influences the long-term success of your app—in
-terms of installs, user rating and reviews, engagement, and user retention.
-Android users expect high-quality apps, even more so if they've spent money on
-them. At the same time, users enjoy and value apps that put a priority on
-continuous improvement. </p>
-
-<p>Before you publish an app on Google Play, it's important to make sure that
-your app meets the basic quality expectations of users, across all of the form
-factors and device types that the app is targeting. The documents in this
-section help you assess your app's fundamental quality and address any
-issues that you find. </p>
-
-<div class="vspace size-1">
-
-</div>
-<div class="layout-content-row">
- <div class="layout-content-col span-4">
- <h4>
- Core App Quality
- </h4>
- <p>
- A set of core quality criteria that all Android apps should meet on all targeted devices.
- </p><a href="{@docRoot}distribute/googleplay/quality/core.html">Learn more »</a>
- </div>
- <div class="layout-content-col span-4">
- <h4>
- Tablet App Quality
- </h4>
- <p>
- A set recommendations for delivering the best possible experience to tablet users.
- </p><a href="{@docRoot}distribute/googleplay/quality/tablet.html">Learn more »</a>
- </div>
- <div class="layout-content-col span-4">
- <h4>
- Improving App Quality
- </h4>
- <p>
- Tips on continuously improving your app's quality, ratings, reviews, downloads, and engagement.
- </p><a href="{@docRoot}distribute/googleplay/strategies/app-quality.html">Learn more
- »</a>
- </div>
-</div>
diff --git a/docs/html/distribute/googleplay/quality/tablet.jd b/docs/html/distribute/googleplay/quality/tablet.jd
deleted file mode 100644
index fe046d4..0000000
--- a/docs/html/distribute/googleplay/quality/tablet.jd
+++ /dev/null
@@ -1,969 +0,0 @@
-page.title=Tablet App Quality Checklist
-@jd:body
-
-<div id="qv-wrapper"><div id="qv">
-<h2>Checklist</h2>
-<ol>
-
-<li><a href="#core-app-quality">1. Test for Basic Tablet App Quality</a></li>
-<li><a href="#optimize-layouts">2. Optimize your layouts</a></li>
-<li><a href="#use-extra-space">3. Use the extra screen area</a></li>
-<li><a href="#use-tablet-icons">4. Use assets designed for tablets</a></li>
-<li><a href="#adjust-font-sizes">5. Adjust fonts and touch targets</a></li>
-<li><a href="#adjust-widgets">6. Adjust homescreen widgets</a></li>
-<li><a href="#offer-full-feature-set">7. Offer the app's full feature set</a></li>
-<li><a href="#android-versions">8. Target Android versions properly</a></li>
-<li><a href="#hardware-requirements">9. Declare dependencies properly</a></li>
-<li><a href="#support-screens">10. Declare tablet screens support</a></li>
-<li><a href="#google-play">11. Showcase your tablet UI</a></li>
-<li><a href="#google-play-best-practices">12. Follow publishing best practices</a></li>
-
-</ol>
-<h2>Testing</h2>
-<ol>
-<li><a href="#test-environment">Setting Up a Test Environment</a></li>
-</ol>
-</div></div>
-
-<p>Before you publish an app on Google Play, it's important to make sure that the app meets the basic expectations of tablet users through compelling features and an intuitive, well-designed UI. </p>
-
-<p>Tablets are a growing part of the Android installed base that offers new
-opportunities for <a
-href="{@docRoot}distribute/googleplay/spotlight/tablets.html">user engagement
-and monetization</a>. If your app is targeting tablet users, this document helps
-you focus on key aspects of quality, feature set, and UI that can have a
-significant impact on the app's success. Each focus area is given as checklist
-item, with each one comprising several smaller tasks or best practices.</p>
-
-<p>Although the checklist tasks below are numbered for convenience,
-you can handle them in any order and address them to the extent that you feel
-is right for your app. In the interest of delivering the best possible product
-to your customers, follow the checklist recommendations
-to the greatest extent possible. </p>
-
-<p>As you move through the checklist, you'll find links to support resources
-that can help you address the topics raised in each task.</p>
-
-
-<h2 id="core-app-quality" style="margin-top:1.5em;">1. Test for basic tablet app quality</h2>
-
-<p>The first step in delivering a great tablet app experience is making sure
-that it meets the <em>core app quality criteria</em> for all of the devices
-and form factors that the app is targeting. For complete information, see the <a
-href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Guidelines</a>.
-</p>
-
-<p>
- Before publishing, also ensure that your app passes several basic
- technical checks and launch criteria, such as:
-</p>
-
-<ul>
- <li><a href="#android-versions">Targets appropriate Android versions</a></li>
- <li><a href="#hardware-requirements">Specifies any hardware dependencies properly</a></li>
- <li><a href="#support-screens">Declares support for appropriate screens</a></li>
- <li><a href="#use-extra-space">Uses all of the available screen space</a></li>
- <li><a href="#google-play">Screenshots are uploaded to Google Play</a></li>
-</ul>
-
-<p>If your app is already uploaded to the Google Play Developer Console, you
- can see how it is doing against these checks
- by visiting the <a href="#google-play-optimization-tips">Optimization
- Tips page</a>.</p>
-
-
-<h2 id="optimize-layouts">2. Optimize your layouts for larger screens</h2>
-
-<p>Android makes it easy to develop an app that runs well on a wide range of
-device screen sizes and form factors. This broad compatibility works in your
-favor, since it helps you design a single app that you can distribute widely to
-all of your targeted devices. However, to give your users the best possible
-experience on each screen configuration — in particular on tablets
-— you need to optimize your layouts and other UI components for each
-targeted screen configuration. On tablets, optimizing your UI lets you take
-full advantage of the additional screen available, such as to offer new features,
-present new content, or enhance the experience in other ways to deepen user
-engagement.</p>
-
-<p>If you developed your app for handsets and now want to distribute it to
-tablets, you can start by making minor adjustments to your layouts, fonts, and
-spacing. In some cases — such as for 7-inch tablets or for a game with
-large canvas — these adjustments may be all
-you need to make your app look great. In other cases, such as for larger
-tablets, you can redesign parts of your UI to replace "stretched UI" with an
-efficient multipane UI, easier navigation, and additional content. </p>
-
-<p>Here are some suggestions:</p>
-
-<div style="width:390px;float:right;margin:1.5em;margin-top:0em;">
-<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-bad.png"
-style="width:390px;padding:4px;margin-bottom:0em;">
-<p class="image-caption" style="padding:0em .5em .5em 2em"><span
-style="font-weight:500;">Get rid of "stretched" UI</span>: On tablets, single-pane
-layouts lead to awkward whitespace and excessive line lengths. Use padding to
-reduce the width of UI elements and consider using multi-pane layouts.</p>
-</div>
-
-<ul>
-<li>Provide custom layouts as needed for <code>large</code> and
-<code>xlarge</code> screens. You can also provide layouts that are loaded based
-on the screen's <a href="{@docRoot}guide/practices/screens_support.html#NewQualifiers">shortest
-dimension</a> or the <a href="{@docRoot}guide/practices/screens_support.html#NewQualifiers">minimum
-available width and height</a>. </li>
-<li>At a minimum, customize dimensions such as font sizes, margins, spacing for
-larger screens, to improve use of space and content legibility. </li>
-<li>Adjust positioning of UI controls so that they are easily accessible to
-users when holding a tablet, such as toward the sides when in
-landscape orientation.</li>
-<li>Padding of UI elements should normally be larger on tablets than on handsets. A
-<a href="{@docRoot}design/style/metrics-grids.html#48dp-rhythm">48dp rhythm</a> (and a 16dp
-grid) is recommended.</li>
-<li>Adequately pad text content so that it is not aligned directly along screen edges.
-Use a minimum <code>16dp</code> padding around content near screen edges.</li>
-</ul>
-
-<p>In particular, make sure that your layouts do not appear "stretched"
-across the screen:</p>
-
-<ul>
-<li>Lines of text should not be excessively long — optimize for a maximum
-100 characters per line, with best results between 50 and 75.</li>
-<li>ListViews and menus should not use the full screen width.</li>
-<li>Use padding to manage the widths of onscreen elements or switch to a
-multi-pane UI for tablets (see next section).</li>
-</ul>
-
-<div class="rel-resources">
- <h3>
- Related resources
- </h3>
-
- <ul>
- <li>
- <a href=
- "{@docRoot}design/style/metrics-grids.html">Metrics
- and Grids</a>—Android Design document that explains how to create
- layouts based on density-independent grids.
- </li>
-
- <li>
- <a href=
- "{@docRoot}design/style/devices-displays.html">Devices
- and Displays</a>—Android Design document that explains how to
- design a UI that works well on different devices and
- screen sizes.
- </li>
-
- <li>
- <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
- Screens</a>—Developer documentation that explains the details of
- managing UI for best display on multiple screen sizes.
- </li>
-
- <li>
- <a href=
- "{@docRoot}guide/practices/screens_support.html#ConfigurationExamples">
- Configuration examples</a>—Examples of how to declare layouts and
- other resources for specific screen sizes.
- </li>
- </ul>
-</div>
-
-
-<h2 id="use-extra-space">3. Take advantage of extra screen area available on tablets</h2>
-
-<div style="width:290px;float:right;margin:1.5em;margin-bottom:0;margin-top:0;">
-<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-good.png"
-style="width:280px;padding:4px;margin-bottom:0em;">
-<p class="image-caption" style="padding:0em .5em .5em 1.5em"><span
-style="font-weight:500;">Multi-pane layouts</span> result in a better visual
-balance on tablet screens, while offering more utility and legibility.</p>
-</div>
-
-<p>Tablet screens provide significantly more screen real estate to your app,
-especially when in landscape orientation. In particular, 10-inch tablets offer a
-greatly expanded area, but even 7-inch tablets give you more space for
-displaying content and engaging users. </p>
-
-<p>As you consider the UI of your app when running on tablets, make sure that it
-is taking full advantage of extra screen area available on tablets. Here are
-some suggestions:</p>
-
-<ul>
-<li>Look for opportunities to include additional content or use an alternative
-treatment of existing content.</li>
-<li>Use <a href="{@docRoot}design/patterns/multi-pane-layouts.html">multi-pane
-layouts</a> on tablet screens to combine single views into a compound view. This
-lets you use the additional screen area more efficiently and makes it easier for
-users to navigate your app. </li>
-<li>Plan how you want the panels of your compound views to reorganize when
-screen orientation changes.</li>
-
-<div style="width:490px;margin:1.5em auto 1.5em 0;">
-<div style="">
-<img src="{@docRoot}images/ui-ex-single-panes.png"
-style="width:490px;padding:4px;margin-bottom:0em;" align="middle">
-<img src="{@docRoot}images/ui-ex-multi-pane.png" style="width:490px;padding:4px;margin-bottom:0em;">
-<p class="image-caption" style="padding:.5em"><span
-style="font-weight:500;">Compound views</span> combine several single views from a
-handset UI <em>(above)</em> into a richer, more efficient UI for tablets
-<em>(below)</em>. </p>
-</div>
-</div>
-
-<li>While a single screen is implemented as an {@link android.app.Activity}
-subclass, consider implementing individual content panels as {@link
-android.app.Fragment} subclasses. This lets you
-maximize code reuse across different form factors and across screens that
-share content.</li>
-<li>Decide on which screen sizes you'll use a multi-pane UI, then provide the
-different layouts in the appropriate screen size buckets (such as
-<code>large</code>/<code>xlarge</code>) or minimum screen widths (such as
-<code>sw600dp</code>/<code>sw720</code>).</li>
-</ul>
-
-<div class="rel-resources">
- <h3>
- Related resources
- </h3>
-
- <ul>
- <li>
- <a href="{@docRoot}design/patterns/multi-pane-layouts.html">Multi-pane
- Layouts</a>—Android Design guide for using multi-pane UI, including
- examples of how to flatten navigation and integrate more content into
- your tablet UI.
- </li>
-
- <li>
- <a href=
- "{@docRoot}training/design-navigation/multiple-sizes.html">Planning for Multiple
- Touchscreen Sizes</a>—Android Training class that walks you through
- the essentials of planning an intuitive, effective navigation for tablets
- and other devices.
- </li>
-
- <li>
- <a href="{@docRoot}training/multiscreen/index.html">Designing for
- Multiple Screens</a>—Android Training class that walks you through
- the essentials of planning an intuitive, effective navigation for tablets
- and other devices.
- </li>
- </ul>
-</div>
-
-
-<h2 id="use-tablet-icons">4. Use Icons and other assets that are designed
-for tablet screens</h2>
-
-<p>To ensure your app looks its best, provide icons and other bitmap
-assets for each density in the range commonly supported by tablets. Specifically, you should
-design your icons for the action bar, notifications, and launcher according to the
-<a href="{@docRoot}design/style/iconography.html">Iconography</a> guidelines and
-provide them in multiple densities, so they appear at the appropriate size on all screens
-without blurring or other scaling artifacts.</p>
-
-<p class="table-caption"><strong>Table 1</strong>. Raw asset sizes for icon types.<table>
-<tr>
-<th>Density</th>
-<th>Launcher</th>
-<th>Action Bar</th>
-<th>Small/Contextual</th>
-<th>Notification</th>
-</tr>
-<tr>
-<td><code>mdpi</code></td>
-<td>48x48 px</td>
-<td>32x32 px</td>
-<td>16x16 px</td>
-<td>24x24 px</td>
-</tr>
-<tr>
-<td><code>hdpi</code></td>
-<td>72x72 px</td>
-<td>48x48 px</td>
-<td>24x24 px</td>
-<td>36x36 px</td>
-</tr>
-<tr>
-<td><code>tvdpi</code></td>
-<td><em>(use hdpi)</em></td>
-<td><em>(use hdpi)</em></td>
-<td><em>(use hdpi)</em></td>
-<td><em>(use hdpi)</em></td>
-</tr>
-<tr>
-<td><code>xhdpi</code></td>
-<td>96x96 px</td>
-<td>64x64 px</td>
-<td>32x32 px</td>
-<td>48x48 px</td>
-</tr>
-<tr>
-<td><code>xxhdpi</code></td>
-<td>144x144 px</td>
-<td>96x96 px</td>
-<td>48x48 px</td>
-<td>72x72 px</td>
-</tr>
-
-</table>
-
-<p>Your app should supply a version of each icon and bitmap asset that's optimized
-for <strong>at least one</strong> the following common tablet screen densities:</p>
-
-<ul>
- <li><code>hdpi</code></li>
- <li><code>xhdpi</code></li>
- <li><code>xxhdpi</code></li>
-</ul>
-
-<p>Other tips:</p>
-
-<ul>
-<li>When possible, use vector shapes for your icon designs so you can scale them
-without loss of detail and edge crispness.</li>
-<li>Use density-specific <a
-href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">
-resource qualifiers</a> to ensure that the proper icons are loaded for each screen density.</li>
-<li>Tablets and other large screen devices often request a launcher icon that is one density
-size larger than the device's actual density, so you should provide your launcher
-icon at the highest density possible. For example, if a tablet has an {@code xhdpi} screen,
-it will request the {@code xxhdpi} version of the launcher icon.</li>
-</ul>
-
-<div class="rel-resources">
- <h3>
- Related resources
- </h3>
-
- <ul>
- <li>
- <a href="{@docRoot}design/style/iconography.html">Iconography</a>—
- Design guidelines and tips about how to create various types of icons.
- </li>
-
- <li>
- <a href=
- "{@docRoot}guide/topics/resources/providing-resources.html">Providing
- Resources</a>—Developer documentation on how to provide
- sets of layouts and drawable resources for specific ranges of device
- screens.
- </li>
-
- <li>
- <a href="{@docRoot}guide/practices/screens_support.html">Supporting
- Multiple Screens</a>—API Guide documentation that
- explains the details of managing UI for best display on multiple screen
- sizes.
- </li>
-
- <li>
- <a href=
- "{@docRoot}training/basics/supporting-devices/screens.html">Supporting Different
- Screens</a>—Android Training class that takes you
- through the process of optimizing the user experience for different
- screen sizes and densities.
- </li>
- </ul>
-</div>
-
-
-<h2 id="adjust-font-sizes">5. Adjust font sizes and touch targets for tablet screens</h2>
-
-<p>To make sure your app is easy to use on tablets, take some time to adjust the
-font sizes and touch targets in your tablet UI, for all of the screen
-configurations you are targeting. You can adjust font sizes through <a
-href="{@docRoot}guide/topics/ui/themes.html">styleable attributes</a> or <a
-href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">dimension
-resources</a>, and you can adjust touch targets through layouts and bitmap
-drawables, as discussed above. </p>
-
-<p>Here are some considerations:</p>
-<ul>
-<li>Text should not be excessively large or small on tablet screen sizes and
-densities. Make sure that labels are sized appropriately for the UI elements they
-correspond to, and ensure that there are no improper line breaks in labels,
-titles, and other elements.</li>
-<li>The recommended touch-target size for onscreen elements is 48dp (32dp
-minimum) — some adjustments may be needed in your tablet UI. Read <a
-href="{@docRoot}design/style/metrics-grids.html">Metrics and
-Grids
-</a> to learn about implementation strategies to help most of your users. To
-meet the accessibility needs of certain users, it may be appropriate to use
-larger touch targets. </li>
-<li>When possible, for smaller icons, expand the touchable area to more than
-48dp using {@link android.view.TouchDelegate}
-or just centering the icon within the transparent button.</li>
-</ul>
-
-<div class="rel-resources">
- <h3>
- Related resources
- </h3>
-
- <ul>
- <li>
- <a href=
- "{@docRoot}design/style/metrics-grids.html">Metrics
- and Grids</a> —Android Design document that explains how to arrange
- and size touch targets and other UI elements on the screen.
- </li>
-
- <li>
- <a href="{@docRoot}design/style/typography.html">Typography</a>—Android
- Design document that gives an overview of how to use typography in your
- apps.
- </li>
-
- <li>
- <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
- Screens</a>—Developer documentation that explains the details of
- managing UI for best display on multiple screen sizes.
- </li>
-
- <li>
- <a href="{@docRoot}training/multiscreen/screendensities.html">Supporting
- Different Densities</a>—Android Training class that shows you how
- to provide sets of layouts and drawable resources for specific ranges of
- device screens.
- </li>
- </ul>
-</div>
-
-
-<h2 id="adjust-widgets">6. Adjust sizes of home screen widgets for tablet screens</h2>
-
-<p>If your app includes a home screen widget, here are a few points to consider
-to ensure a great user experience on tablet screens: </p>
-
-<ul>
-<li>Make sure that the widget's default height and width are set appropriately
-for tablet screens, as well as the minimum and maximum resize height and width.
-</li>
-<li>The widget should be resizable to 420dp or more, to span 5 or more home
-screen rows (if this is a vertical or square widget) or columns (if this is a
-horizontal or square widget). </li>
-<li>Make sure that 9-patch images render correctly.</li>
-<li>Use default system margins.</li>
-<li>Set the app's <code>targetSdkVersion</code> to 14 or higher, if
-possible.</li>
-</ul>
-
-<div class="rel-resources">
- <h3>
- Related resources
- </h3>
-
- <ul>
- <li>
- <a href="{@docRoot}guide/topics/appwidgets/index.html#MetaData">Adding the
- AppWidgetProviderInfo Metadata</a> —API Guide that explains how to
- set the height and width dimensions of a widget.
- </li>
-
- <li>
- <a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget
- Design Guidelines</a>—API Guide that provides best practices and
- techniques for designing and managing the size of widgets.
- </li>
- </ul>
-</div>
-
-
-<h2 id="offer-full-feature-set">7. Offer the app's full feature set to tablet users</h2>
-
-<p>Let your tablet users experience the best features of your app. Here are
-some recommendations:</p>
-
-<ul>
-<li>Design your app to offer at least the same set of features on tablets as it does on
-handsets. </li>
-<li>In exceptional cases, your app might omit or replace certain features on
-tablets if they are not supported by the hardware or use-case of most tablets.
-For example:
-<ul>
-<li>If the handset uses telephony features but telephony is not available on the
-current tablet, you can omit or replace the related functionality.</li>
-<li>Many tablets have a GPS sensor, but most users would not normally carry
-their tablets while running. If your phone app provides functionality to let the
-user record a GPS track of their runs while carrying their phones, the app would not need to
-provide that functionality on tablets because the use-case is not
-compelling.</li>
-</ul>
-</li>
-<li>If you will omit a feature or capability from your tablet UI, make sure
-that it is not accessible to users or that it offers “graceful degradation”
-to a replacement feature (also see the section below on hardware features).</li>
-</ul>
-
-<h2 id="android-versions">8. Target Android versions properly</h2>
-
-<p>To ensure the broadest possible distribution to tablets, make sure that your
-app properly targets the Android versions that support tablets. Initial support for
-tablets was added in <a href="{@docRoot}about/versions/android-3.0.html">Android 3.0</a>
-(API level 11). Unified UI
-framework support for tablets, phones, and other devices was introduced in <a
-href="{@docRoot}about/versions/android-4.0.html">Android 4.0</a> (API level 14) and is
-supported in later versions.
-
-<p>You can set the app's
-range of targeted Android versions in the manifest file, in the
-<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code><uses-sdk></code></a> element. In most cases, you can target Android versions properly by setting the element's <code>targetSdkVersion</code> attribute to the highest API level available.</p>
-
-<p style="margin-bottom:.5em;">At a minimum, check the <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code><uses-sdk></code></a>
- element to make sure that:</p>
-
- <ol style="list-style-type:lower-alpha;margin-top:0em;">
- <li><code>targetSdkVersion</code> is declared with value 11 or higher (14 or higher is recommended), OR</li>
- <li><code>minSdkVersion</code> is declared with value 11 or higher.</li>
- <li>If a <code>maxSdkVersion</code> attribute is declared, it must have a value of 11 or higher. Note that, in general, the use of <code>maxSdkVersion</code> is <em>not recommended</em>.</li>
-</ol>
-
-<div class="rel-resources">
-<h3>
- Related resources
-</h3>
-
-<ul>
- <li>
- <a href=
- "{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">Android API
- Levels</a>—Introduces API levels and how they relate to compatibility.
- A reference of available API levels is included.
- </li>
- <li>
- <a href="{@docRoot}training/basics/supporting-devices/platforms.html">Supporting Different Platform Versions</a>—Training class showing how to declare support for
- minimum and target API levels in your app.
- </li>
-</ul>
-</div>
-
-<h2 id="hardware-requirements">9. Declare hardware feature dependencies properly</h2>
-
-<p>
- Handsets and tablets typically offer slightly different hardware support for
- sensors, camera, telephony, and other features. For example, many tablets are
- available in a "Wi-Fi" configuration that does not include telephony support.
-</p>
-
-<p>
- So that you can distribute a single APK broadly across your full customer
- base of phones and tablets, make sure that your app doesn't declare
- requirements for hardware features that aren't commonly available on tablets.
- Instead, properly declare the hardware features as <em>not required</em> in the app
- manifest, as described below.
-</p>
-
-<ul>
-<li>In your app manifest, locate any <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code><uses-feature></code></a>
-elements. In particular, look for hardware features that might not be
-available on some tablets, such as:
-
-<ul>
-<li><code>android.hardware.telephony</code></li>
-<li><code>android.hardware.camera</code> (refers to back camera), or</li>
-<li><code>android.hardware.camera.front</code></li>
-</ul></li>
-
-<li>Declare the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code><uses-feature></code></a>
-elements as <em>not required</em> by including the <code>android:required=”false”</code>
-attribute.
-
-<p>
- For example, here's the proper way to declare a dependency on
- <code>android.hardware.telephony</code>, such that you can still
- distribute the app broadly, even to devices that don't offer telephony:
-</p>
-
-<pre><uses-feature android:name="android.hardware.telephony" android:required="false" /></pre></li>
-
-<li>Similarly, check the manifest for <a href="/guide/topics/manifest/permission-element.html"><code><permission></code></a> elements that
-<a href="/guide/topics/manifest/uses-feature-element.html#permissions">imply hardware
-feature requirements</a> that not be appropriate for tablets. If you find such
-permissions, make sure to explicitly declare a corresponding
-<code><uses-feature></code> element for the features and includes the
-<code>android:required=”false”</code> attribute.</li>
-</ul>
-
-
-<p>
- After declaring hardware features as <em>not required</em>, make sure to test
- your app on a variety of devices. The app should function normally when the
- hardware features it uses are not available, and it should offer "graceful
- degradation" and alternative functionality where appropriate.
-</p>
-
-<p>
- For example, if an app normally uses GPS to set the location but GPS is not
- supported on the device, the app could let the user set the location manually
- instead. The app can check for device hardware capabilities at runtime and handle
- as needed.
-</p>
-
-<div class="rel-resources">
-<h3>
- Related resources
-</h3>
-
-<ul>
- <li>
- <a href=
- "{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions">Permissions
- that Imply Feature Requirements</a>—A list of permissions that may
- cause unwanted filtering if declared in your app's manifest.
- </li>
- <li>
- <a href=
- "{@docRoot}guide/topics/manifest/uses-feature-element.html"><code><uses-feature></code></a>—Description
- and reference documentation for the <code><uses-feature></code>
- manifest element.
- </li>
-
- <li>
- <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#testing">Testing
- the features required by your application</a>—Description of how to
- determine the actual set of hardware and software requirements (explicit or
- implied) that your app requires.
- </li>
-</ul>
-</div>
-
-<h2 id="support-screens">10. Declare support for tablet screens</h2>
-
-<p>To ensure that you can distribute your app to a broad range of tablets, your app should
-declare support for tablet screen sizes in its manifest file, as follows:</p>
-
-<ul>
- <li>A
- <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code><supports-screens></code></a>
- element, if declared, must not specify <code>android:largeScreens="false"</code>
- or <code>android:xlargeScreens="false"</code>.</li>
- <li>For apps targeting <code>minSdkVersion</code> value less than 13, a
- <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code><supports-screens></code></a>
- element must be declared with both <code>android:largeScreens="true"</code> and
- <code>android:xlargeScreens="true"</code>.</li>
-</ul>
-
-<p>If the app declares a
-<a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html"><code><compatible-screens></code></a>
-element in the manifest, the element should include attributes that specify
-<em>all of the size and density combinations for tablet screens</em> that the
-app supports. Note that, if possible, you should avoid using the
-<a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html"><code><compatible-screens></code></a>
-element in your app.</p>
-
-<div class="rel-resources">
- <h3>
- Related resources
- </h3>
-
- <ul>
- <li>
- <a href=
- "{@docRoot}guide/practices/screens_support.html#DeclaringScreenSizeSupport">Declaring
- Screen Size Support</a>—Developer documentation that explains the
- details of managing UI for best display on multiple screen sizes.
- </li>
- </ul>
-</div>
-
-
-<h2 id="google-play">11. Showcase your tablet UI in Google Play</h2>
-
-<p>
- After you've done the work to create an rich, optimized UI for your tablet
- app, make sure that you let your customers know about it! Here are some key
- ways to promote your tablet app to users on Google Play.
-</p>
-
-<h4>
- Upload screenshots of your tablet UI
-</h4>
-
-<p>
- Tablet users want to know what your app is like on a tablet device, not on a
- phone. If you developed a tablet app, make sure to upload screenshots
- of your tablet UI to the Google Play Developer Console. Here are some guidelines:
- </p>
-
-<ul style="margin-top:0;">
- <li>Your screenshots should show the core functionality of your app, not a
- startup or sign-in page. Wherever users will spend most of their time, that's
- what you should show in your screenshots.
- </li>
-
- <li>Add screenshots taken on both 7-inch and 10-inch tablets.
- </li>
-
- <li>It's recommended that you add screenshots taken in both landscape and
- portrait orientations, if possible.
- </li>
-
- <li>Use screen captures if possible. Avoid showing actual device hardware in your
- screenshots.</li>
-
- <li>The recommended resolution of your tablet screenshots is <strong>1280 x 720</strong>
- or higher in each orientation.
- </li>
-
- <li>You can upload as many as 8 screenshots of your tablet UI for 7-inch tablets
- and an additional 8 for 10-inch tablets.
- </li>
-</ul>
-
-<h4>
- Update your app description and release notes
-</h4>
-
-<ul>
- <li>In your app description, make sure to highlight that your app offers
- tablet-optimized UI and great features for tablet users. Consider adding some
- detail about how your tablet UI works and why users will like it.
- </li>
-
- <li>Include information about tablet support in the app's release notes and
- update information.
- </li>
-</ul>
-
-<h4>
- Update your promotional video
-</h4>
-
-<p>
- Many users view an app's promotional video to get an idea of what the app is
- like and whether they'll enjoy it. For tablet users, capitalize on this
- interest by highlighting your app's tablet UI in your promotional video. Here
- are some tips and guidelines:
-</p>
-
-<ul>
- <li>Add one or more shots of your app running on a tablet. To engage with
- tablet users most effectively, it's recommended that you promote your tablet
- UI in approximately equal proportion to your phone UI.
- </li>
-
- <li>Show your tablet UI as early as possible in the video. Don't assume that
- tablet users will wait patiently through a feature walkthrough on a phone UI.
- Ideally, you should engage them immediately by showing the tablet UI within
- the first 10 seconds, or at the same point that you introduce the phone UI.
- </li>
-
- <li>To make it clear that you are showing a tablet UI, include shots of your
- app running on a hand-held tablet device.
- </li>
-
- <li>Highlight your app's tablet UI in the video's narrative or voiceover.
- </li>
-</ul>
-
-<h4>
- Feature your tablet UI in your promotional campaigns
-</h4>
-
-<p>
- Make sure to let tablet users know about your tablet UI in your promotional
- campaigns, web site, social posts, advertisements, and elsewhere. Here are
- some suggestions:
-</p>
-
-<ul>
- <li>Plan a marketing or advertising campaign that highlights the use of your
- app on tablets.</li>
-
- <li>Show your tablet app at its best in your promotional campaigns—use the <a href=
- "{@docRoot}distribute/promote/device-art.html">Device Art Generator</a> to
- quickly generate a high-quality promotional image of your app running on a
- 7-inch or 10-inch tablet, in the orientation of your choice, with or without
- drop-shadow and screen glare. It's as simple as capture, drag, and drop.
- </li>
-
- <li>Include a Google Play badge in your online promotions to let users link
- directly to your app's store listing. You can generate a badge in a variety
- of languages using the <a href=
- "{@docRoot}distribute/googleplay/promote/badges.html">Badge Generator</a>.
- </li>
-</ul>
-
-<div class="rel-resources">
- <h3>
- Related resources
- </h3>
-
- <ul>
- <li>
- <a href="{@docRoot}distribute/googleplay/publish/preparing.html">Publishing
- Checklist</a>
- —Recommendations on how to prepare your app for publishing, test
- it, and launch successfully on Google Play.
- </li>
-
- <li>
- <a href="https://play.google.com/apps/publish/">Google Play
- Developer Console</a>—The tools console for publishing
- your app to Android users.
- </li>
- <li>
- <a href=
- "{@docRoot}distribute/googleplay/promote/badges.html">Google Play
- Badge Generator</a>—Create "Get it on Google Play" badges for your
- app in a variety of languages with a single click.
- </li>
- <li>
- <a href=
- "{@docRoot}distribute/promote/device-art.html">Device Art
- Generator</a>—Drag and drop tool that lets you instantly create production-
- ready art showing your app running on a tablet device.
- </li>
- </ul>
-</div>
-
-<h2 id="google-play-best-practices">12. Follow best practices for publishing in Google Play</h2>
-
-<p>Here are some best practices for delivering a successful tablet app on Google Play.</p>
-
-<h4 id="google-play-optimization-tips">Check out your app's Optimization Tips</h4>
-
-<p>The Google Play Developer Console now offers an Optimization Tips page that
-lets you quickly check how your app is doing against basic guidelines for tablet app
-distribution and quality. To visit the page, sign into the Developer Console,
-load the app from All Applications, and click Optimization Tips in
-the left navigation.</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2 style="line-height:1em;">How to send feedback</h2>
-
-<p>Please use the link below to send
-feedback or request a manual review of your Optimization Tips.</p>
-
-<p>Make sure to read the relevant sections of the Tablet App Quality
-Guidelines prior to sending feedback.</p>
-
-<p><strong><a href="https://support.google.com/googleplay/android-developer/contact/tabletq"
-target="_googleplay" style="white-space:nowrap">Designed for Tablets Contact Form »</a></strong></p>
-</div>
-</div>
-
-<p>The Developer Console creates your app's Optimization Tips page
-by running a series of checks to verify basic quality
-criteria. If it finds any issues, it alerts you to them as "To Do"
-items in the Optimization Tips page.</p>
-
-<p>If you've developed a tablet experience for your app, make sure
-to visit the Optimization Tips page to see how your app is doing
-against the basic checks. If there are any issues listed, we
-recommend addressing them in your app and uploading a new binary for
-distribution, if needed. </p>
-
-<p>If the Optimization Tips page lists "To Do" issues that you feel don't
-apply to your app or affect its quality on tablets, please notify us
-using the <a href="https://support.google.com/googleplay/android-developer/contact/tabletq"
-target="_googleplay" style="white-space:nowrap">Designed for Tablets Contact Form »</a>. We
-will review your app and update your Optimization Tips page as
-appropriate.</p>
-
-
-<h4>Confirm the app's filtering</h4>
-
-<p>After you've uploaded the app to the <a href="https://play.google.com/apps/publish/">Developer Console</a>, check the APK's Supported Devices list to make sure that the app is not filtered from tablet devices that you want to target.</p>
-
-<h4>Distribute as a single APK</h4>
-
-<p>
- It's recommended that you publish your app as a single APK for all screen
- sizes (phones and tablets), with a single Google Play listing. This approach
- has several important advantages.
-</p>
-
-<ul style="margin-top:.25em;">
- <li>Easier for users to find your app from search, browsing, or promotions
- </li>
-
- <li>Easier for users to restore your app automatically if they get a new
- device.
- </li>
-
- <li>Your ratings and download stats are consolidated across all devices.
- </li>
-
- <li>Publishing a tablet app in a second listing can dilute ratings for your
- brand.
- </li>
-</ul>
-
-<p>
- If necessary, you can alternatively choose to deliver your app using <a href=
- "{@docRoot}google/play/publishing/multiple-apks.html">Multiple APK Support</a>,
- although in most cases using a single APK to reach all devices is strongly
- recommended.
-</p>
-
-<div class="rel-resources">
-<h3>Related resources</h3>
-<ul>
-<li><a href="{@docRoot}distribute/googleplay/publish/preparing.html">Publishing
- Checklist</a>—
- Recommendations on how to prepare your app for publishing, test it, and launch
- successfully on Google Play.</li>
-<li><a href="https://play.google.com/apps/publish/">Google Play Developer
- Console</a>—The tools console for publishing your app to Android users.</li>
-</ul>
-</div>
-
-
-<h2 id="test-environment">Setting Up a Test Environment for Tablets</h2>
-
-<p>To assess the quality of your app on tablets — both for core app quality
-and tablet app quality — you need to set up a suitable
-hardware or emulator environment for testing. </p>
-
-<p>The ideal test environment would
-include a small number of actual hardware devices that represent key form
-factors and hardware/software combinations currently available to consumers.
-It's not necessary to test on <em>every</em> device that's on the market —
-rather, you should focus on a small number of representative devices, even using
-one or two devices per form factor. The table below provides an overview of
-devices you could use for testing.</p>
-
-<p>If you are not able to obtain actual hardware devices for testing, you should
-<a href="{@docRoot}tools/devices/index.html">set up emulated devices (AVDs)</a>
-to represent the most common form factors and
-hardware/software combinations. See the table below for suggestions on the emulator
-configurations to use. </p>
-
-<p>To go beyond basic testing, you can add more devices, more form factors, or
-new hardware/software combinations to your test environment. For example, you
-could include mid-size tablets, tablets with more or fewer hardware/software
-features, and so on. You can also increase the number or complexity of tests
-and quality criteria. </p>
-
-<p class="table-caption"><strong>Table 1</strong>. A typical tablet test environment might
-include one or two devices from each row in the table below, with one of the
-listed platform versions, screen configurations, and hardware feature configurations.</p>
-
-<table>
-<tr>
-<th>Type</th>
-<th>Size</th>
-<th>Density</th>
-<th>Version</th>
-<th>AVD Skin</th>
-</tr>
-
-<tr>
-<td>7-inch tablet</td>
-<td><span style="white-space:nowrap"><code>large</code> or</span><br /><code>-sw600</code></td>
-<td><code>hdpi</code>,<br /><code>tvdpi</code></td>
-<td>Android 4.0+ (API level 14 and higher)</td>
-<td>WXGA800-7in</td>
-</tr>
-<tr>
-<td><span style="white-space:nowrap">10-inch</span> tablet</td>
-<td><span style="white-space:nowrap"><code>xlarge</code> or</span><br /><code>-sw800</code></td>
-<td><code>mdpi</code>,<br /><code>hdpi</code>,<br /><code>xhdpi</code></td>
-<td>Android 3.2+ (API level 13 and higher)</td>
-<td>WXGA800</td>
-</tr>
-</table>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/spotlight/games.jd b/docs/html/distribute/googleplay/spotlight/games.jd
deleted file mode 100644
index 1fbc03f..0000000
--- a/docs/html/distribute/googleplay/spotlight/games.jd
+++ /dev/null
@@ -1,245 +0,0 @@
-page.title=Developer Stories: Google Play Game Services
-walkthru=0
-header.hide=0
-
-@jd:body
-
-<p>One of the goals of <a href="https://developers.google.com/games/">Google
-Play game services</a> is to allow developers to focus on what they’re good at
-as game developers — creating great gaming experiences for their users, by
-building on top of what Google is good at: mobile and cloud services. Integral
-to that is an easy integration process, one that provides a whole host of
-features with little engineering work required.</p>
-
-<p>The gaming studios below understood the opportunity that Google Play game
-services unlocked, and are starting to see real results following their
-successful integrations. </p>
-
-<div style="margin-bottom:2em;"><!-- START STORY -->
-
-<h3>Concrete Software — Straightforward, easy to implement</h3>
-
-<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 12px 20px 9px 20px;"
- src="//lh6.ggpht.com/_UOay5HBxf077suKYzmikU2IbnYOJub3X0inz-LoUsVh4TX758BEyArjoR7owXijkAA=w124">
-
-<div style="list-style: none;height:100%;
- float: right;
- border-top: 1px solid #9C0;
- width: 220px;
- margin: 4px 20px;padding: .5em;">
-
- <h5>About the developer</h5>
- <ul>
- <li><a href="https://play.google.com/store/apps/developer?id=Concrete%20Software%2C%20Inc.">Concrete Software</a>,
- makers of <a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket&hl=en">PBA
- Bowling Challenge</a></li>
- <li>Added support for multiplayer, leaderboards and achievements through Google Play game
- services</li>
- </ul>
-
- <h5>Results</h5>
- <ul>
- <li>Session lengths have increased more than 15%</li>
- </ul>
-
- <div style="padding:.5em 0 0 1em;">
- <a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket&hl=en">
- <img alt="Android app on Google Play" src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
- </a>
- </div>
-</div>
-
-<div style="line-height:1.4em;">
-<p style="margin-top:0;margin-bottom:12px;">Concrete Software added several
-features from Google Play game services into one of their top titles,
-<a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket">PBA
-Bowling Challenge</a>, including support for multiplayer, leaderboards, and
-achievements.</p>
-
-<p>So far, their users have loved the new additions: average session length
-is up more than 15%. Keith Pichelman, CEO of Concrete Software, explains: </p>
-
-<p>"The Google Play game services were straightforward and easy to implement. We
-had been researching options for multiplayer services, so when Google Play game
-services came out, it was an easy decision for us. Not only were they easy to
-integrate, but the features have worked flawlessly. </p>
-
-<p>"PBA Bowling Challenge now has real-time multiplayer which our users instantly
-were thrilled with; you can see in the reviews how people immediately raved about
-the new game experience. </p>
-
-<p>"We also included achievements, leaderboards, and most recently cloud
-synchronization from the Google Play game services as well. Using the game
-services in PBA Bowling Challenge was a huge success, enough so that we are now
-going back to our other titles, adding the features to them as well."</p>
-</div>
-
-<div style="clear:both;margin-top:40px;width:auto;">
-
- <img src="{@docRoot}images/distribute/concrete-pbc-gpgames.jpg">
-
- <div style="width:600px;margin-top:0px;padding:0 90px;">
- <p class="image-caption"><span style="font-weight:500;">Session lengths up:</span>
- After adding support for multiplayer with Google Play game services, Concrete
- Software saw an increase in session lengths of more than 15% for PBA Bowling
- Challenge.</p>
- </div>
-</div>
-</div> <!-- END STORY -->
-
-<div style="margin:3em auto"><!-- START STORY -->
-
-<h3>Glu: It’s a must-have for all titles</h3>
-
-<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 12px 20px 30px 20px;"
- src="//lh4.ggpht.com/Q7mQJsdhulW4_s039R9aaRhQkGnyzLkhF00j5EnyhHOivijnyi7P7b5A8qG0xk1r-jQ=w124">
-
-<div style="list-style: none;height:100%;
- float: right;
- border-top: 1px solid #9C0;
- width: 220px;
- margin: 4px 20px;padding: .5em;">
-
- <h5>About the developer</h5>
- <ul>
- <li><a href="https://play.google.com/store/apps/developer?id=Glu+Mobile">Glu
- Mobile</a>, creators of <a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">Eternity
- Warriors 2</a></li>
- <li>Has already integrated 5 titles with Google Play game services</li>
- </ul>
-
- <h5>Results</h5>
- <ul>
- <li>In Eternity Warriors 2, 7-day user retention is up 40%</li>
- <li>20% increase in play sessions per day as well</li>
- </ul>
-
- <div style="padding:.5em 0 0 1em;">
- <a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">
- <img alt="Android app on Google Play" src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
- </a>
- </div>
-</div>
-
-<div style="line-height:1.4em;">
-<p style="margin-top:0;margin-bottom:12px;">Glu was one of the first developers
-to integrate Google Play game services, with
-<a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">Eternity
-Warriors 2</a>. Based on this first success, Glu has integrated game services
-into several more games, including Samurai vs. Zombies 2, Frontline Commando:
-D-Day, Contract Killer 2, and Zombies Ate My Friends.</p>
-
-<p>Already supported in Eternity Warriors 2, they’ve seen a 40% increase in 7-day
-user retention and a 20% increase in play sessions per day. Sourabh Ahuja, Glu's
-Vice President of Android Development, explains:</p>
-
-<p>“Multiplayer, leaderboards, achievements — these are all things that we
-had to build individually for our titles. The availability of these features in
-Google Play game services helps us make our games stickier, and it’s awesome that
-it comes directly from Google. </p>
-
-<p>"It’s flexible enough that we were able to make it interoperable with our
-in-house systems. We look forward to utilizing game services extensively across
-our portfolio."</p>
-</div>
-
-<div style="clear:both;margin-top:40px;width:auto;">
-
- <img src="{@docRoot}images/distribute/glu-ew-gpgames.jpg"></a>
-
- <div style="width:600px;margin-top:0px;padding:0 90px;">
- <p class="image-caption"><span style="font-weight:500;">User retention up:</span>
- Glu saw a 40% increase in 7-day user retention for Eternity Warriors 2 after
- integrating with Google Play game services.</p>
- </div>
-</div>
-</div> <!-- END STORY -->
-
-
-<div style="margin-bottom:2em;"><!-- START STORY -->
-
-<h3>Vector-Unit: An awesome multiplayer experience</h3>
-
-<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 12px 20px 9px 20px;" src=
- "https://lh3.ggpht.com/dTUrKLffqXHJtPuIlp8fjDhROuzrTcpidbNFprugR65hMrPLX7Omd8SGop0xMXXKzcw=w124">
-
-<div style="list-style: none;height:100%;
- float: right;
- border-top: 1px solid #9C0;
- width: 220px;
- margin: 4px 20px;padding: .5em;">
-
- <h5>About the developer</h5>
- <ul>
- <li><a href="https://play.google.com/store/apps/developer?id=Vector+Unit">Vector
- Unit</a>, creators of <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">Riptide
- GP2</a></li>
- <li>Added multiplayer to Riptide GP2 through Google Play game services </li>
- </ul>
-
- <h5>Results</h5>
- <ul>
- <li>With an easy multiplayer solution, they were able to focus on the
- gameplay</li>
- <li>Early reviews of Riptide GP2 called multiplayer “one of the sweetest
- cherries on top!”</li>
- </ul>
-
- <div style="padding:.5em 0 0 1em;">
- <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">
- <img alt="Android app on Google Play" src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
- </a>
- </div>
-</div>
-
-<div style="line-height:1.4em;">
-<p style="margin-top:0;margin-bottom:12px;">Vector Unit just launched their
-latest title, <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">Riptide
-GP2</a>, with Google Play game services integration, and it has one of the strongest
-integrations of multiplayer yet. Early reviews call multiplayer “one of the sweetest
-cherries on top!”.</p>
-
-<p>Ralf Knoesel, CTO of Vector Unit, tells more about how they've used Google Play game
-services:</p>
-
-<p>“We wanted to provide a really compelling multiplayer experience for our users, and
-Google Play game services allowed us to do just that. With multiplayer, you can show off
-your skills and your custom-tuned hydro jet in 4-way online battles with friends and
-players around the world. </p>
-
-<p>"By providing an easy way to power this multiplayer experience, we were able to focus
-on making the gameplay come alive — like the stunts, which are more daring and
-slicker than ever (with more of them to master), or the realistic detail of the water
-splashing against the camera lens.”</p>
-
-</div>
-
-<div style="clear:both;margin-top:40px;width:auto;">
-
- <img src="{@docRoot}images/distribute/vector-unit-rt-gpgames.jpg"></a>
-
- <div style="width:600px;margin-top:0px;padding:0 90px;">
- <p class="image-caption"><span style="font-weight:500;">Multiplayer and more:</span>
- Google Play game services helped Vector Unit pack an awesome multiplayer experience
- into Riptide GP 2, so they could focus on building a great gaming experience.</p>
- </div>
-</div>
-</div> <!-- END STORY -->
-
-
-
diff --git a/docs/html/distribute/googleplay/spotlight/index.jd b/docs/html/distribute/googleplay/spotlight/index.jd
deleted file mode 100644
index fc2e162..0000000
--- a/docs/html/distribute/googleplay/spotlight/index.jd
+++ /dev/null
@@ -1,162 +0,0 @@
-page.title=Spotlight
-page.tags="videos, google play, monetize, inapp"
-meta.tags="stories, googleplay, monetizing, landing"
-page.image=/images/video-kiwi.jpg
-walkthru=0
-header.hide=0
-
-@jd:body
-
-
-<p>Android developers, their apps, and their successes with Android and Google Play. </p>
-
-<div id="Kiwi" style="background: #F0F0F0;
- border-top: 1px solid #DDD;
- padding: 0px 0 24px 0;
- overflow: auto;
- clear:both;
- margin-bottom:40px;
- margin-top:30px;">
- <div style="padding:0 0 0 29px;">
- <h4>Developer Story: Kiwi, Inc.</h4>
- <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 17px 20px 9px 0;"
- src="//lh4.ggpht.com/qUI-8MJy70l4qoVBR_sx-56ckR_m0R_ZXcJ1DiTYUR3R_owWzsCFTYkAk4p5DMnaSdY3=w124" >
- <div style="width:700px;">
- <p style="margin-top:26px;
- margin-bottom:12px;">
- Android-first developer <a href="//play.google.com/store/apps/developer?id=Kiwi,+Inc." target="_android">Kiwi, Inc.</a> has had 5 titles in the top 25 grossing on Google Play, including <a href="https://play.google.com/store/apps/details?id=com.kiwi.shipwrecked" target="_android">Shipwrecked: Lost Island</a>, <a href="https://play.google.com/store/apps/details?id=com.kiwi.monsterpark" target="_android">Monsterama Park</a>, and <a href="https://play.google.com/store/apps/details?id=com.kiwi.mysteryestate" target="_android">Hidden Object: Mystery Estate</a>. Hear how Google Play helped them double revenue every six months with features like instant updates, staged rollouts, and more.</p>
- </div>
- <iframe style="float:left;
- margin-right:24px;
- margin-top:14px;" width="700" height="394" src=
- "http://www.youtube.com/embed/WWArLD6nqrk?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
- </iframe>
- </div>
-</div>
-<div style="background: #F0F0F0;
- border-top: 1px solid #DDD;
- padding: 0px 0 24px 0;
- overflow: auto;
- clear:both;
- margin-bottom:40px;
- margin-top:30px;">
- <div style="padding:0 0 0 29px;">
- <h4>Developer Story: Colopl</h4>
- <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 17px 20px 9px 0;"
- src="//lh3.ggpht.com/sx2ILNaXQYOsHfR91T5tUWGlfXE1FutHCBN02Fll6mi9gIaG6RZCGbeJMtIvOoegCPTh=w124" >
- <div style="width:700px;">
- <p style="margin-top:26px;
- margin-bottom:12px;">
- The creators of Kuma The Bear, Japan-based <a href="https://play.google.com/store/apps/developer?id=COLOPL,+Inc." target="_android">Colopl</a>, talk about how Google Play and Android allowed them to grow their business to become one of the most profitable games publishers in APAC to date. </p>
- </div>
- <iframe style="float:left;
- margin-right:24px;
- margin-top:14px;" width="700" height="394" src=
- "http://www.youtube.com/embed/CbpoZeQCNe4?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
- </iframe>
- </div>
-</div>
-
-<div style="background: #F0F0F0;
- border-top: 1px solid #DDD;
- padding: 0px 0 24px 0;
- overflow: auto;
- clear:both;
- margin-bottom:40px;
- margin-top:30px;">
- <div style="padding:0 0 0 29px;">
- <h4>Developer Story: redBus.in</h4>
- <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 17px 20px 9px 0;" src=
- "//lh4.ggpht.com/kvI2XfzBPGBDASvxvP18MCCj7YPEmLcG4nh1BlYW4XzaW12gg3iXtcM2ZqDnAfLLB9ed=w124">
- <div style="width:700px;">
- <p style="margin-top:26px;
- margin-bottom:12px;">
- Bangalore-based developers <a href="//play.google.com/store/apps/details?id=in.redbus.android">redBus.in</a> are bringing the sophistication and convenience of air-travel booking to bus transit. Hear how Android is helping them deliver a superior travel experience to millions of daily bus riders in India.</p>
- </div>
- <iframe style="float:left;
- margin-right:24px;
- margin-top:14px;" width="700" height="394" src=
- "http://www.youtube.com/embed/O8i4HUw7JYA?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
- </iframe>
- </div>
-</div>
-
-<div style="background: #F0F0F0;
- border-top: 1px solid #DDD;
- padding: 0px 0 24px 0;
- overflow: auto;
- clear:both;
- margin-bottom:40px;
- margin-top:30px;">
- <div style="padding:0 0 0 29px;">
- <h4>Developer Story: Smule</h4>
- <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 17px 20px 9px 0;" src=
- "//lh6.ggpht.com/z5wl9PuHl9JfO54uefjRTUX70SuLY-1DRpPxQ5mg7XEDfnYhBDssh1RrPZjN1tbwzhg=w124">
- <div style="width:700px;">
- <p style="margin-top:26px;
- margin-bottom:12px;">
- The creators of <a href="//play.google.com/store/apps/details?id=com.smule.autorap">AutoRap</a>, <a href="//play.google.com/store/apps/details?id=com.smule.magicpiano">Magic Piano</a>, and <a href="//play.google.com/store/apps/details?id=com.smule.songify">Songify</a> talk about their experiences launching on Android, the explosive global growth they’ve seen on Google Play, and some of the techniques they use to market and monetize their products effectively across the world.</p>
- </div>
- <iframe style="float:left;
- margin-right:24px;
- margin-top:14px;" width="700" height="394" src=
- "http://www.youtube.com/embed/RRelFvc6Czo?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
- </iframe>
- </div>
-</div>
-
-<div style="background: #F0F0F0;
- border-top: 1px solid #DDD;
- padding: 0px 0 24px 0;
- overflow: auto;
- clear:both;
- margin-bottom:-10px;
- margin-top:30px;">
- <div style="padding:0 0 0 29px;">
- <h4>Developer Story: Robot Invader</h4>
- <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 17px 20px 9px 0;" src=
- "//g0.gstatic.com/android/market/com.robotinvader.knightmare/hi-256-0-9e08d83bc8d01649e167131d197ada1cd1783fb0">
- <div style="width:700px;">
- <p style="margin-top:26px;margin-bottom:12px;">Robot Invader chose
- Android and Google Play as the launch platform for their first game,<br />
- <a data-g-event="Developers Page" data-g-label="Case Study Link" href=
- "//play.google.com/store/apps/details?id=com.robotinvader.knightmare"><em>Wind-up
- Knight</em></a>.
- </p>
- <p>
- Hear from the developers how Android helped them reach millions of users
- and more than 100 device models with a single app binary, then iterate rapidly to ensure
- a great user experience.
- </p>
- </div>
- <iframe style="float:left;
- margin-right:24px;
- margin-top:14px;" width="700" height="394" src=
- "http://www.youtube.com/embed/hTtlLiUTowY" frameborder="0" allowfullscreen></iframe>
- </div>
-</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/spotlight/localization.jd b/docs/html/distribute/googleplay/spotlight/localization.jd
deleted file mode 100644
index ae5993d..0000000
--- a/docs/html/distribute/googleplay/spotlight/localization.jd
+++ /dev/null
@@ -1,328 +0,0 @@
-page.title=Developer Stories: Localization in Google Play
-walkthru=0
-header.hide=0
-
-@jd:body
-
-<p>
- As you build your app and distribute it across the world through Google Play,
- localization becomes an increasingly important tool to reach more users.
- Localization involves a <a href=
- "{@docRoot}distribute/googleplay/publish/localizing.html">variety of tasks</a>, but
- most important is creating quality translations of your app's UI strings and
- marketing materials.
-</p>
-
-<p>
- Managing the translation process across multiple languages can be a
- challenge, especially if you need to locate translators on your own. That’s
- why Google Play offers the App Translation Service right from the Developer
- Console. It's a single place where you can go to source professional
- translators, get cost estimates, and then send your strings and other
- materials for translation.
-</p>
-
-<p>
- Here are some stories from developers who have used Google Play's App Translation
- Service to localize their apps and the results they've seen as they've
- expand their offerings beyond a single language.
-</p>
-
-<!-- START STORY -->
-
-<div style="margin-bottom:2em;padding-top:10px;" id="zombieragdoll">
-
-<h3 style="line-height:1.25em">Zombie Ragdoll: Improved user engagement<br /> with localized versions</h3>
-
- <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 12px 20px 9px 20px;" src=
- "https://lh4.ggpht.com/m-Ew8c8C_nGctbP6PSPGOaVNnGFryReOE2yHXJ9Z6Prk1nsDyx5w5TmWfg-P5N3HypA=w124">
-
- <div style="list-style: none;height:100%;
- float: right;
- border-top: 1px solid #9C0;
- width: 220px;
- margin: 4px 20px;padding: .5em;">
-
- <h5>About the app</h5>
-
- <ul>
- <li><a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">Zombie Ragdoll</a></li>
- <li>A fun zombie-based physics game</li>
- </ul>
-
- <h5>Localization Results</h5>
-
- <ul>
- <li>Increased engagement because of appeal of the localized version</li>
- <li>80% of installs came from users of non-English languages</li>
- </ul>
-
- <div style="padding:.5em 0 0 1em;">
- <a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">
- <img alt="Android app on Google Play"
- src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
- </a>
-
- </div>
- </div>
-
- <div style="line-height:1.4em;">
-
-<p>
- The 2013 Google I/O talks about <a href=
- "https://developers.google.com/events/io/sessions/326345917">Building Android
- Apps for a Global Audience</a> and <a href=
- "https://developers.google.com/events/io/sessions/326455375">What’s New for
- Developers in Google Play</a> inspired developers at RV AppStudios to go global
- from very beginning for their new game, Zombie Ragdoll. They launched Zombie
- Ragdoll in August 2013, localized into 20 languages.
-</p>
-
-<p>
- They quickly saw the impact of their decision to ship simultaneously in
- multiple languages through increased non-English installs and improved
- engagement with users worldwide. In addition, they started getting
- significant usage in countries where their apps had not been as popular
- before. They are seeing great traction in countries like Vietnam, Russia,
- Philippines and Thailand.
-</p>
-
-<p>
- Vivek Dave, founder of RV AppStudios, credits the success of Zombie Ragdoll
- to localization:
-</p>
-
-<p>
- "The value of localization is clear, it helps discoverability and helps
- connect with the users in other countries. So when the localization
- opportunity arose, we immediately jumped on it. Android is worldwide, and we
- would be severely limiting ourselves if we focused on English as the only
- language.
-</p>
-
-<p>
- "The App Translation Service offered in the Google Play Developer Console is
- extremely easy to use and the pricing is very attractive. Developers with
- limited localization experience can easily create, upload, and translate
- their app."
-</p>
-
-
-<p>
- RV AppStudios not only localizes the text within the game, but also localizes
- the game assets to a specific country/culture. Dave says, “Users want a
- personalized experience, and by offering a localized game with translation of
- text and graphic assets, we believe users will connect at a much deeper level
- with the game.”
-</p>
-
-
- <div style="margin-top:8px;float:left;margin-right:24px;">
- <img src="{@docRoot}images/distribute/zombie-ragdoll-n5-land.jpg" style="width:470px;">
- </div>
-
-
- <div style="margin-top:128px;">
- <p class="img-caption"><strong>Hindi version of Zombie Ragdoll</strong>:
- Localized screenshots and videos in the app's Google Play listing go a
- long way toward increasing the number of installs.</p>
- </div>
-
- </div>
-
-</div> <!-- END STORY -->
-
-<!-- START STORY -->
-
-<div style="margin-bottom:2em;padding-top:18px;clear:both;" id="sayhichat">
-
-<h3>SayHi Chat: Install growth and user engagement<br />
- from professional translations</h3>
-
- <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 12px 20px 9px 20px;" src=
- "https://lh5.ggpht.com/qiL6CF1Hktz618T3mbGrxvm_OoeheQ78FgG7zr90C2MCRiz4IDQsbKuHT4xQGiWEU8o=w124">
-
- <div style="list-style: none;height:100%;
- float: right;
- border-top: 1px solid #9C0;
- width: 220px;
- margin: 4px 20px;padding: .5em;">
-
- <h5>About the app</h5>
-
- <ul>
- <li><a href="https://play.google.com/store/apps/details?id=com.unearby.sayhi">SayHi Chat,
- Love, Meet, Dating</a></li>
- <li>A social app to help you find people nearby</li>
- </ul>
-
- <h5>Localization Results</h5>
-
- <ul>
- <li>120% growth in language installs for new languages added</li>
- <li>~20% increase in revenue and ~50% increase in User Reviews in the new
- languages</li>
- </ul>
-
- <div style="padding:.5em 0 0 1em;">
- <a href="https://play.google.com/store/apps/details?id=com.unearby.sayhi">
- <img alt="Android app on Google Play"
- src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
- </a>
-
- </div>
- </div>
-
- <div style="line-height:1.4em;">
-
-<p>
- The SayHi Chat app started out only in Japanese, Chinese and English. It soon
- became one of the most popular apps in Japan, Hong Kong, and Taiwan. The
- SayHi team realized it was time to launch in more languages, as the language
- barrier was restricting how fast SayHi could grow globally. </p>
-
- <p>Yan Shi, senior
- developer at SayHi, says: "We checked Google Analytics for our DAU and user
- growth numbers in each country, we also looked at total Android and iOS users
- in those markets before finalizing our next set of languages.
-</p>
-
- <div style="margin-top:8px;float:left;width:270px;">
- <img src="{@docRoot}images/distribute/hichat-n5-port.jpg" style="width:240px;margin-right:48px;">
- </div>
-
-<p>
- SayHi used the App Translation Service to launch in 13 additional languages
- in August 2013 and immediately saw 120% increase in install rates. In
- addition, they are seeing their app ranked in Top 10 apps in countries like
- Poland and Italy.
-</p>
-
-<p>Notably, they saw steady growth in Spain after replacing their previous
- non-professional Spanish translation with a professional one produced through
- the App Translation Service.</p>
-
-<p>
- Yan Shi adds, “The App Translation Service is really easy to use and
- the completion time for translation requests is very good.”
-</p>
-
- <div style="width:600px;margin-top:98px;padding:0;">
- <p class="img-caption"><strong>Arabic version of SayHi Chat</strong>:
- User engagement increased significantly with
- the localized version.</p>
- </div>
-
- </div>
-</div> <!-- END STORY -->
-
-
-<div style="margin-bottom:2em;clear:both;padding-top:18px;" id="g4a"><!-- START STORY -->
-
-<h3 style="line-spacing:1.25em;">G4A Indian Rummy: Benefitting from ease-of-use and<br /> fast turnaround time</h3>
-
- <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 12px 20px 9px 20px;" src=
- "https://lh4.ggpht.com/IxSyQgO0LWzPRoLfCrER06-0kr6aMAa2azF7eNYB30EBZAGOLYJUZulknPockbTlDYU=w124">
-
- <div style="list-style: none;height:100%;
- float: right;
- border-top: 1px solid #9C0;
- width: 220px;
- margin: 4px 20px;padding: .5em;">
-
- <h5>About the app</h5>
-
- <ul>
- <li><a href="https://play.google.com/store/apps/details?id=org.games4all.android.games.indianrummy.prod">G4A Indian Rummy</a></li>
- <li>A card game in which the players try to form sets and sequences of cards</li>
- </ul>
-
- <h5>Localization Results</h5>
-
- <ul>
- <li>Double the number of users in French and German languages</li>
- <li>300% increase in user engagement with localized version</li>
- </ul>
-
- <div style="padding:.5em 0 0 1em;">
- <a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">
- <img alt="Android app on Google Play"
- src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
- </a>
- </div>
- </div>
-
- <div style="line-height:1.4em;">
-
-<p>
- Games4All (G4A) is the developer of Indian Rummy and a variety of games that
- they distribute broadly to users around the world. After noticing that
- certain apps had become especially popular in specific countries, they
- decided to localize those apps. Initially they used a local agency to do
- the translation and got great results — the number of users in
- that language increased tremendously when they released the localized
- version.
-</p>
-
-<p>
- Building on that success, G4A expanded their localization goals but
- found that translation quality varied across their vendors and costs limited the
- language/game combinations they could try. That's when G4A decided to try the
- App Translation Service.
-</p>
-
-<p>
- Founder Pieter Olivier says, "When we heard that the App Translation
- Service was available in the Developer Console, we jumped at the opportunity.
- We've now been using the App Translation Service for several months and found
- that the cost per translation is much lower than with local companies and the
- process is much easier."
-</p>
-
-<p>So far, G4A has translated the game Indian Rummy into five languages through
- the App Translation Service.</p>
-
-<p>
- Olivier continues, "The first thing we did was convert all of our texts into
- the strings.xml format. After that using the service was extremely easy and
- straightforward. In contrast, our previous experiences with translation
- agencies were much more difficult: files often required extensive conversion
- operations to make them usable, and turnaround times varied wildly.
-</p>
-
-<p>
- "With the App Translation Service, the turnaround time is usually measured in
- days instead of weeks that we were used to with traditional translation
- agencies."
-</p>
-
- <div style="margin-top:14px;float:left;margin-right:24px;">
- <img src="{@docRoot}images/distribute/indian-rummy-n4-land.jpg" style="width:470px;">
- </div>
-
- <div style="margin-top:158px;">
- <p class="img-caption"><strong>Dutch
- version of Indian Rummy</strong>: Making slight changes to games rules based on
- local nuances was key to success of the game.</p>
- </div>
-
- </div>
-
-
-
-</div> <!-- END STORY -->
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/spotlight/tablets.jd b/docs/html/distribute/googleplay/spotlight/tablets.jd
deleted file mode 100644
index 7a98755..0000000
--- a/docs/html/distribute/googleplay/spotlight/tablets.jd
+++ /dev/null
@@ -1,367 +0,0 @@
-page.title=Developer Stories: The Opportunity of Android Tablets
-walkthru=0
-header.hide=0
-
-@jd:body
-
-
-<p>More and more, developers are investing in a full tablet experience
-for their apps and are seeing those investments pay off big. The increased
-screen area on tablets opens up a world of possibilities, allowing for more
-engagement with the user — which can mean an increase in usage as well as
-more monetization opportunities. And with the growing wave of Android tablets that
-continue to hit the market, it’s an important piece of any developer’s mobile
-offering. </p>
-
-<p>Here are some stories from developers who are seeing real results as they
-expand their offering to include Android tablets.</p>
-
-
-<div style="margin-bottom:2em;" id="rememberthemilk"><!-- START STORY -->
-
-<h3>Remember The Milk: Lifting installs with tablet design</h3>
-
- <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 12px 20px 9px 20px;" src=
- "//lh3.ggpht.com/xmnal18taauP2mjQFEhr1PhcItQ_W32IRuaD86IoL2U_4E-mfeKiliKtkISgOuA6Ln9n=w124">
-
- <div style="list-style: none;height:100%;
- float: right;
- border-top: 1px solid #9C0;
- width: 220px;
- margin: 4px 20px;padding: .5em;">
-
-
- <h5>About the app</h5>
-
-
- <ul>
- <li><a href="//play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">Remember The Milk</a></li>
- <li>A feature-packed to-do list app; never forget the milk (or anything else) again</li>
- </ul>
-
- <h5>Tablet Results</h5>
-
- <ul>
- <li>83% jump in tablet installs following update </li>
- <li>Nexus 7 is most popular Android device for app </li>
- <li>Single APK for phones and tablets</li>
- </ul>
-
- <div style="padding:.5em 0 0 1em;">
- <a href="//play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">
- <img alt="Android app on Google Play"
- src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
- </a>
-
- </div>
- </div>
-
- <div style="line-height:1.4em;">
- <p style="margin-top:0;margin-bottom:12px;">When the Android tablet guidelines
- came out in 2012, the team at Remember The Milk had already been thinking about
- a redesign for their <a href="//play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">feature-packed
- to-do list app</a>. Omar Kilani, Co-founder of Remember The Milk, explains how
- <a href="//blog.rememberthemilk.com/2013/04/the-all-new-remember-the-milk-for-android-and-tablets-too/">updating</a>
- their app to meet the tablet guidelines lead to an 83% jump in tablet installs: </p>
-
- <p>“We took this as an opportunity to think about how we were going to approach
- Android tablets differently from a user experience perspective. The guidelines
- were a helpful resource, and with the extra screen real estate tablets afford,
- users have the opportunity to see all of their data in context and drill down
- on more items. All of this is accomplished using a single APK on Play, even though
- the phone and tablet versions each capture completely different use cases for us.”</p>
-
- <p>“In the month after updating, we saw our tablet installs on Google Play jump 83%,
- and the Nexus 7 is now the most popular Android device amongst our users. For us,
- designing for tablets was an investment that has really paid off.”</p>
-
- <p>The team also came out with a number of other goodies — including a new set of
- widgets and richer notifications, and more ways to provide an immersive experience
- for their users.</p>
- </div>
-
- <div style="clear:both;margin-top:30px;width:auto;">
-
- <img src="{@docRoot}images/distribute/rememberthemilk.png">
-
- <div style="width:600px;margin-top:0px;padding:0 90px;">
- <p class="image-caption"><span style="font-weight:500;">Tablet redesign led to lift
- in installs</span>: Following the redesign of the Android app, in part to meet the tablet
- design criteria, Remember The Milk saw an 83% increase in tablet installs.</p>
- </div>
-
- </div>
-
-</div> <!-- END STORY -->
-
-
-<div style="margin-bottom:2em;" id="mint"><!-- START STORY -->
-
-<h3>Mint: More screen real estate = more engagement</h3>
-
- <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 12px 20px 9px 20px;" src=
- "https://lh5.ggpht.com/0xAIZJ1uE05b4RHNHgBBTIH6nRdPTY660T104xY7O2GbHXwab6YVmpU5yYg8yacfBg=w124">
-
- <div style="list-style: none;height:100%;
- float: right;
- border-top: 1px solid #9C0;
- width: 220px;
- margin: 4px 20px;padding: .5em;">
-
-
- <h5>About the app</h5>
-
-
- <ul>
- <li><a href="http://play.google.com/store/apps/details?id=com.mint">Mint.com Personal Finance</a> by Intuit Inc.</li>
- <li>Financial management app targeting 7- to 10-inch tablets and phones</li>
- </ul>
-
- <h5>Tablet Results</h5>
-
- <ul>
- <li>Able to offer richer UI features</li>
- <li>Much higher user engagement</li>
- <li>Longer sessions — more Android tablet users have sessions longer than 5 minutes</li>
- </ul>
-
- <div style="padding:.5em 0 0 1em;">
-<a href="http://play.google.com/store/apps/details?id=com.mint">
- <img alt="Android app on Google Play"
- src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
-</a>
-
- </div>
- </div>
-
- <div style="line-height:1.4em;">
- <p style="margin-top:0;margin-bottom:12px;">When Intuit was thinking about
-expanding their Mint mobile offering to include a version optimized for Android
-tablets, they knew that taking the layout that worked for phones and simply
-showing an enlarged version wouldn’t take full advantage of the opportunities
-that tablets afford.</p>
-
- <p>“We knew we had a lot more real estate, and we wanted to provide a more
-immersive experience for our users” said Ken Sun, Intuit Group Product Manager
-at Mint.</p>
-
-<p>Intuit’s Mint app, which has a 4-star rating on Google Play, brings a number
-of features to Android tablets that aren’t available for phones, including a
-more visual presentation of personal financial data.</p>
-
-<p>“Whereas our app for phones is used throughout the day for quick sessions,
-we’ve seen a larger percentage of our tablet usage happen in the evening, for
-much longer sessions,” said Sun. “People are doing a lot more than just checking
-their spending. They’re looking at historical trends, re-categorizing
-transactions, analyzing the data and setting financial goals for the future
-— digging much deeper and being more thoughtful. One example is how much
-users are interacting with their own budgets in the tablet app. Customer budget
-operations (view, edit, drill-down, etc.) are 7x higher on Android tablets than
-they are on phones.”</p>
-
-<p>Fifty percent more Android tablet users have Mint sessions of 5 minutes or
-longer than they do on phones. “We’ve found that phone usage is indicative of a
-customer’s regular financial check-in, while tablet usage points towards more
-analysis and interaction with that customer’s personal financial data. This is
-the sort of immersive engagement experience we were looking for; the tablet and
-phone apps serve as great complements to each other."</p>
- </div>
-
- <div style="clear:both;margin-top:40px;width:auto;">
-
- <img src="{@docRoot}images/distribute/mint.png">
-
- <div style="width:600px;margin-top:0px;padding:0 90px;">
- <p class="image-caption"><span style="font-weight:500;">Making the most of tablet screens</span>: Mint used the extra screen area on tablets to offer quick access to additional tools and information.</p>
- </div>
-
- </div>
-
-</div> <!-- END STORY -->
-
-
-<div style="margin:3em auto"><!-- START STORY -->
-
-
-<h3>TinyCo: Monetization opportunities abound on tablets</h3>
-
- <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 12px 20px 30px 20px;" src=
- "https://lh6.ggpht.com/QTy7lOGRTS58NW4XEeym2sxpWKDmRNod_n3kBrHlqTRIyzIv2gkw8DfwiR4GIAdxiHw=w124">
-
-
- <div style="list-style: none;height:100%;
- float: right;
- border-top: 1px solid #9C0;
- width: 220px;
- margin: 4px 20px;padding: .5em;">
-
- <h5>About the app</h5>
-
- <ul>
- <li><a href="http://play.google.com/store/apps/details?id=com.tinyco.village">Tiny Village</a> by TinyCo</li>
- <li>Game targeting 7- to 10-inch tablets and phones</li>
- </ul>
-
- <h5>Tablet Results</h5>
-
- <ul>
- <li>35% higher average revenue per paying user (ARPPU)</li>
- <li>Consistent increase in user retention</li>
- <li>3x increase in downloads to Android tablets in the last 6 months</li>
- </ul>
-
- <div style="padding:.5em 0 0 1em;">
-<a href="http://play.google.com/store/apps/details?id=com.tinyco.village">
- <img alt="Android app on Google Play"
- src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
-</a>
-
- </div>
- </div>
-
- <div style="line-height:1.4em;">
- <p style="margin-top:0;margin-bottom:12px;">
-
-<p>Over a year ago, app developer TinyCo, makers of a suite of games such as
-Tiny Monsters, decided to prioritize launching across multiple platforms
-effectively. They chose Android as one of their primary launch platforms because
-of its large installed base and global reach. They also knew that the growing
-base of Android tablet users represented a huge opportunity.</p>
-
- <p>Tiny Village was their first title to take advantage of the strategy, and
-it proved to be a winning one — especially in terms of Android
-tablets.</p>
-
- <p> “With continued optimization of the gameplay experience and a genuine
-commitment to our Android offering through our Griffin engine, all of our
-metrics started to rise,” said Rajeev Nagpal, Head of Product at TinyCo. In
-fact, they’ve seen Android tablet downloads more than triple in the last six
-months.</p>
-
- <p>One of the first things they noticed about usage of Tiny Village on
-tablets was an increase in average revenue per paying user (ARPPU)—about 35%
-higher than on smaller-screen devices such as phones. Additionally, average
-revenue per user ARPU is now about 35% higher as well. “The game is just much
-more immersive on tablet.”</p>
-
- <p>In addition to an increase in monetization metrics, they’ve also seen a
-consistent increase in retention over other platforms. “These are really
-important metrics for games — if you can get users to both stay around
-longer and spend more while they’re there, you have a recipe for success.”</p>
- </div>
-
- <div style="clear:both;margin-top:40px;width:auto;">
-
- <img src="{@docRoot}images/distribute/tinyvillage.png">
-
- <div style="width:600px;margin-top:0px;padding:0 90px;">
- <p class="image-caption"><span style="font-weight:500;">More monetization
-on tablets</span>: On Android tablets TinyCo has seen higher ARPPU and user
-retention than on phones.</p>
- </div>
-
- </div>
-
-</div> <!-- END STORY -->
-
-
-<div style="margin-bottom:2em;"><!-- START STORY -->
-
-<h3>Instapaper: Riding the growing wave of Android tablets</h3>
-
-
- <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 12px 20px 9px 20px;" src=
- "https://lh3.ggpht.com/30KKcrIFO8V_wRfhnHaI9l0CLH_orIVFE7Xywtr9TBxAf0hi2BaZkKyBOs63Yfavpg=w124">
-
-
- <div style="list-style: none;height:100%;
- float: right;
- border-top: 1px solid #9C0;
- width: 220px;
- margin: 4px 20px;padding: .5em;">
-
-
-
-
- <h5>About the app</h5>
- <ul>
- <li><a href="http://play.google.com/store/apps/details?id=com.instapaper.android">Instapaper</a> by Mobelux</li>
- <li>Content-browsing utility that targets 7- to 10-inch tablets and phones</li>
- </ul>
-
- <h5>Tablet Results</h5>
-
- <ul>
- <li>Tablets are now 50% of the app's installed base.</li>
- </ul>
-
- <div style="padding:.5em 0 0 1em;">
-<a href="http://play.google.com/store/apps/details?id=com.instapaper.android">
- <img alt="Android app on Google Play"
- src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
-</a>
-
- </div>
- </div>
-
- <div style="line-height:1.4em;">
- <p style="margin-top:0;margin-bottom:12px;">Instapaper for Android is an app
-for saving web content to read later. Developer Mobelux decided that creating a
-great UI for Android tablet users would be an essential part of their initial launch
-plan.</p>
-
- <p>The app launched at the beginning of the summer of 2012, just in time to
-take advantage of a new tide of Android tablets, including the <span
-style="white-space:nowrap;">Nexus 7</span> tablet. The app has since seen huge
-popularity among tablet users, in particular, on Nexus 7. On the day that
-pre-orders of Nexus 7 began arriving, Mobelux saw a 600% jump in downloads of
-its app on Google Play.</p>
-
- <p>“We saw a promising new set of Android tablets about to hit the market
-and wanted to position ourselves to be ready for them” said Jeff Rock of
-Mobelux. “It was a market that others were hesitant to explore, but the decision
-to prioritize tablets has paid off very well for us.”</p>
-
- <p>Since that initial 600% jump in downloads, Instapaper for Android has
-continued to see a successful run on Android tablets. In fact, Android tablets
-now represent about 50% of their installed base. “With more and more Android
-tablets coming online, we’re excited to see how our investment in Android
-tablets continues to pay off.”</p>
- </div>
-
- <div style="clear:both;margin-top:40px;width:auto;">
-
- <img src="{@docRoot}images/distribute/instapaper.png">
-
- <div style="width:600px;margin-top:0px;padding:0 90px;">
- <p class="image-caption"><span style="font-weight:500;">Popular with
-tablet users</span>: A great tablet UI and browsing convenience make Instapaper
-popular with Android tablet users.</p>
- </div>
-
- </div>
-
-</div> <!-- END STORY -->
-
-
-
diff --git a/docs/html/distribute/googleplay/start.jd b/docs/html/distribute/googleplay/start.jd
new file mode 100644
index 0000000..6dc397b
--- /dev/null
+++ b/docs/html/distribute/googleplay/start.jd
@@ -0,0 +1,163 @@
+page.title=Get Started with Publishing
+page.metaDescription=Start publishing on Google Play in minutes by registering for a developer account.
+meta.tags="publishing"
+page.tags="google play", "publishing", "register", "signup"
+page.image=/distribute/images/getting-started.jpg
+
+@jd:body
+
+<div class="top-right-float" style="margin-right:24px;margin-top:-18px">
+ <a href="https://play.google.com/apps/publish/"><img src=
+ "{@docRoot}images/gp-start-button.png"></a>
+</div>
+
+<p>
+ Start publishing on Google Play in minutes by:
+</p>
+
+<ul>
+ <li>Registering for a Google Play publisher account
+ </li>
+
+ <li>Setting up a Google Wallet Merchant Account, if you will sell apps or
+ in-app products.
+ </li>
+
+ <li>Exploring the <a href="https://play.google.com/apps/publish/">Google Play
+ Developer Console</a> and publishing tools.
+ </li>
+</ul>
+
+<p>
+ When you're ready, use the Start button to go to the Developer Console.
+</p>
+
+<div class="headerLine">
+ <h1>
+ Register for a Publisher Account
+ </h1>
+
+ <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+ <div class="sidebox">
+ <h2>
+ Tips
+ </h2>
+
+ <ul>
+ <li>You need a Google account to register. You can create one during the
+ process.
+ </li>
+
+ <li>If you are an organization, consider registering a new Google account
+ rather than using a personal account.
+ </li>
+
+ <li>Review the <a href=
+ "https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294">
+ developer countries</a> and <a href=
+ "https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=150324">
+ merchant countries</a> where you can distribute and sell apps.
+ </li>
+ </ul>
+ </div>
+</div>
+
+<ol>
+ <li>Visit the <a href="https://play.google.com/apps/publish/">Google Play
+ Developer Console</a>.
+ </li>
+
+ <li>Enter basic information about your <strong>developer identity</strong>
+ — name, email address, and so on. You can modify this information
+ later.
+ </li>
+
+ <li>Read and accept the <strong>Developer Distribution Agreement</strong> for
+ your country or region. Note that apps and store listings that you publish on
+ Google Play must comply with the Developer Program Policies and US export
+ law.
+ </li>
+
+ <li>Pay a <strong>$25 USD registration fee</strong> using Google Wallet. If
+ you don't have a Google Wallet account, you can quickly set one up during the
+ process.
+ </li>
+
+ <li>When your registration is verified, you’ll be notified at the email
+ address you entered during registration.
+ </li>
+</ol>
+
+<div class="headerLine">
+ <h1 id="merchant-account">
+ Set Up a Google Wallet Merchant Account
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure" style="width:200px;">
+ <img src="{@docRoot}images/gp-start-wallet-icon.png">
+</div>
+
+<p>
+ If you want to sell priced apps, in-app products, or subscriptions, you’ll
+ need a Google Wallet Merchant Account. You can set one up at any time, but
+ first review the list of <a href=
+ "https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=150324">
+ merchant countries</a>.<br>
+ <br>
+ To set up a Google Wallet Merchant Account:<br>
+ <br>
+</p>
+
+<ol>
+ <li>
+ <strong>Sign in</strong> to your Google Play Developer Console at <a href=
+ "https://play.google.com/apps/publish/" target=
+ "_blank">https://play.google.com/apps/publish/</a>.
+ </li>
+
+ <li>Open <strong>Financial reports</strong> <img src=
+ "{@docRoot}images/distribute/console-reports.png"> on the side navigation.
+ </li>
+
+ <li>Click <strong>Setup a Merchant Account now</strong>.
+ </li>
+</ol>
+
+<p>
+ This takes you to the Google Wallet site; you'll need information about your
+ business to complete this step.
+</p>
+
+<div class="headerLine">
+ <h1>
+ Explore the Developer Console
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ When your registration is verified, you can sign in to your Developer
+ Console, which is the home for your app publishing operations and tools on
+ Google Play.
+</p>
+
+<div>
+ <img src="{@docRoot}images/gp-dc-home.png" class="border-img">
+</div>
+
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr />
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/googleplay/gettingstarted"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="6"></div>
diff --git a/docs/html/distribute/googleplay/strategies/app-quality.jd b/docs/html/distribute/googleplay/strategies/app-quality.jd
deleted file mode 100644
index eb2cd2b..0000000
--- a/docs/html/distribute/googleplay/strategies/app-quality.jd
+++ /dev/null
@@ -1,121 +0,0 @@
-page.title=Improving App Quality After Launch
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>Strategies</h2>
-<ol>
-<li><a href="#listen">Listen to Your Users</a></li>
-<li><a href="#stability">Improve Stability and Eliminate Bugs</a></li>
-<li><a href="#responsiveness">Improve UI Responsiveness</a></li>
-<li><a href="#usability">Improve Usability</a></li>
-<li><a href="#appearance">Professional Appearance and Aesthetics</a></li>
-<li><a href="#features">Deliver the Right Set of Features</a></li>
-<li><a href="#integrate">Integrate with the System and Third-Party Apps</a></li>
-<li><a href="#details">Pay Attention to Details</a></li>
-</ol>
-
-<h2>You Should Also Read</h2>
-<ol>
-<li><a href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Guidelines</a></li>
-<li><a href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality Checklist</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>
-With thousands of new apps being published in Google Play every week, it's important to look for any available way to get the most visibility and the highest ratings possible. One way of improving your app's visibility in the ecosystem is by deploying well-targeted mobile advertising campaigns and cross-app promotions. Another time-tested method of fueling the impression-install-ranking cycle is simply: <em>improve the product</em>!</p>
-<p>
-A better app can go a very long way: a higher quality app will translate to higher user ratings, generally better rankings, more downloads, and higher retention (longer install periods). High-quality apps also have a much higher likelihood of getting some unanticipated positive publicity such as being featured in Google Play or getting social media buzz.</p>
-<p>
-The upside to having a higher-quality app is obvious. However, it's not always clear how to make an app "better". This document looks at some of the key factors in app quality and ways of improving your app over time, after you've launched the app.</p>
-
-<h2 id="listen">Listen to Your Users</h2>
-<p>
-Most ways of measuring the "success" of an app are dependent on user behavior. User-related metrics such as number of downloads, daily active installs, retention rates, and so on highlight the importance of users. If you aren't doing so already, it's a good idea to start thinking of your app's quality as it relates to your users.</p>
-<p>
-The most obvious way to listen to users is by reading and addressing comments on your app in Google Play. Although the comments aren't always productive or constructive, some will provide valuable insight on aspects of your app that you may not have consciously considered before. It's important to remember that users have the opportunity to change their ratings and comments about an app as much as they'd like.</p>
-<p>
-One way to reach users and help them address their concerns is to set up your own support and discussion destination(s). There are some great support tools out there that can put you in touch with your users directly, from forums such as <a href="http://groups.google.com">Google Groups</a> to comprehensive customer support products and destinations. Once you get set up with such a tool, make sure to fill in the support link in your Google Play product details page — users do click through to these.</p>
-<p>
-Another way to better listen to your users is by having a public beta or trusted tester program. It's crucial to have some amount of real user testing before releasing something in Google Play. Fortunately, you can distribute your apps to users outside of Google Play via a website; this website can require a login or be publicly accessible — it's entirely up to you. Take advantage of this opportunity by offering your next planned update to some early adopters, before submitting to Google Play. You'll be surprised by how many little, yet impactful, improvements can come out of crowd-sourced, real-user testing.</p>
-
-
-<h2 id="stability">Improve Stability and Eliminate Bugs</h2>
-
-<p>
-The effect of overall app stability of ratings and user satisfaction is very well-known and there are many tools and techniques for testing and profiling your app on different devices and user scenarios.</p>
-<p>
-One noteworthy and yet relatively underused tool for catching stability issues such as crashes is the <a href="{@docRoot}tools/help/monkey.html">UI/Application Exerciser Monkey</a> (Monkey). Monkey will send random UI events to your app's activities, allowing you to trigger user flows that can uncover stability problems.</p>
-<p>
-Also, with the Google error-reporting features built into most Android devices, users now have a way to report application crashes to developers. The error reports show up in aggregate in the Google Play Developer Console. Make sure to read these reports often and act on them appropriately.</p>
-<p>
-Last, keep an external bug and feature request tracker and let users know how to find it. This will enable them to engage with the app at a closer level, by following features and bugs that affect them. User frustration with app problems can be effectively managed with diligent issue tracking and communication. Some of the community support tools listed above offer issue tracking features, and if your project is open source, most popular repository hosting sites will offer this as well.</p>
-
-<h2 id="responsiveness">Improve UI Responsiveness</h2>
-<p>
-One sure-fire way to lose your users is to give them a slow, unresponsive UI. Research has shown that <a href="http://googleresearch.blogspot.com/2009/06/speed-matters.html">speed matters</a>... for any interface, be it desktop, web, or mobile. In fact, the importance of speed is amplified on mobile devices since users often need their information on the go and in a hurry.</p>
-<p>
-You can improve your apps's UI responsiveness by moving long-running operations off the main thread to worker threads. Android offers built-in debugging facilities such as StrictMode for analyzing your app's performance and activities on the main thread. You can see more recommendations in <a href="http://www.youtube.com/watch?v=c4znvD-7VDA">Writing Zippy Android Apps</a>, a developer session from Google I/O 2010,</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h3>More resources</h3>
-<ul>
-<li><a href="{@docRoot}design/index.html">Android Design</a></li>
-<li><a href="{@docRoot}guide/practices/performance.html">Designing for Performance</a></li>
-<li><a href="{@docRoot}guide/practices/responsiveness.html">Designing for Responsiveness</a>
-<li><a href="{@docRoot}guide/practices/seamlessness.html">Designing for Seamlessness</a>
-</li>
-</ul>
-</div></div>
-<p>
-A great way to improve UI performance is to minimize the complexity of your layouts. If you open up <a href="{@docRoot}tools/help/hierarchy-viewer.html">hierarchyviewer</a> and see that your layouts are more than 5 levels deep, it may be time to simplify your layout. Consider refactoring those deeply nested LinearLayouts into RelativeLayout. The impact of View objects is cumulative — each one costs about 1 to 2 KB of memory, so large view hierarchies can be a recipe for disaster, causing frequent VM garbage collection passes which block the main (UI) thread. You can learn more in <a href="http://www.youtube.com/watch?v=wDBM6wVEO70">World of ListView</a>, another session at Google I/O.</p>
-<p>
-Lastly, pointed out in the blog post <a href="http://android-developers.blogspot.com/2010/10/traceview-war-story.html">Traceview War Story</a>, tools like <a href="{@docRoot}tools/help/traceview.html">traceview</code> and <a href="{@docRoot}tools/help/ddms.html">ddms</a> can be your best friends in improving your app by profiling method calls and monitoring VM memory allocations, respectively.</p>
-
-
-<h2 id="usability">Improve Usability</h2>
-<p>
-In usability and in app design too, you should listen carefully to your users. Ask a handful of real Android device users (friends, family, etc.) to try out your app and observe them as they interact with it. Look for cases where they get confused, are unsure of how to proceed, or are surprised by certain behaviors. Minimize these cases by rethinking some of the interactions in your app, perhaps working in some of the <a href="http://www.youtube.com/watch?v=M1ZBjlCRfz0">user interface patterns</a> the Android UI team discussed at Google I/O.</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<p>
-As you are designing or evaluating your app's UI, make sure to read and become familiar with the <a href="/design/index.html">Android Design</a> guidelines. Included are many examples of UI patterns, styles, and building blocks, as well as tools for the design process.</p>
-</div></div>
-
-<p>
-In the same vein, two problems that can plague some Android user interfaces are small tap targets and excessively small font sizes. These are generally easy to fix and can make a big impact on usability and user satisfaction. As a general rule, optimize for ease of use and legibility, while minimizing, or at least carefully balancing, information density.</p>
-
-<p>
-Another way to incrementally improve usability, based on real-world data, is to implement <a href="http://code.google.com/mobile/analytics/docs/">Analytics</a> throughout your app to log usage of particular sections. Consider demoting infrequently used sections to the overflow menu in the <a href="{@docRoot}design/patterns/actionbar.html">Action bar</a>, or removing them altogether. For often-used sections and UI elements, make sure they're immediately obvious and easily accessible in your app's UI so that users can get to them quickly.</p>
-<p>
-Lastly, usability is an extensive and well-documented subject, with close ties to interface design, cognitive science, and other disciplines.</p>
-
-<h2 id="appearance">Professional Appearance and Aesthetics</h2>
-<p>
-There's no substitute for a real user interface designer — ideally one who's well-versed in mobile and Android, and ideally handy with both interaction and visual design. One popular venue to post openings for designers is <a href="http://jobs.smashingmagazine.com">jobs.smashingmagazine.com</a>, and leveraging social networks can also surface great talent.</p>
-<p>
-If you don't have the luxury of working with a UI designer, there are some ways in which you can improve your app's appearance yourself. First, get familiar with Adobe Photoshop, Adobe Fireworks, or some other raster image editing tool. Mastering the art of the pixel in these apps takes time, but honing this skill can help build polish across your interface designs. Also, master the resources framework by studying the framework UI assets and layouts and reading through the <a href="{@docRoot}guide/topics/resources/index.html">resources documentation</a>. Techniques such as 9-patches and resource directory qualifiers are somewhat unique to Android, and are crucial in building flexible yet aesthetic UIs.</p>
-<p>
-Before you get too far in designing your app and writing the code, make sure to visit the Android Design site and learn about the vision, the building blocks, and the tools of designing beautiful and inspiring user interfaces.</p>
-
-<h2 id="features">Deliver the Right Set of Features</h2>
-<p>
-Having the <em>right</em> set of features in your app is important. It's often easy to fall into the trap of feature-creep, building as much functionality into your app as possible. Providing instant gratification by immediately showing the most important or relevant information is crucial on mobile devices. Providing too much information can be as frustrating (or even more so) than not providing enough of it.</p>
-<p>
-Again, listen to your users by collecting and responding to feature requests. Be careful, though, to take feature requests with a grain of salt. Requests can be very useful in aggregate, to get a sense of what kinds of functionality you should be working on, but not every feature request needs to be implemented.</p>
-
-<h2 id="integrate">Integrate with the System and Third-Party apps</h2>
-<p>
-A great way to deliver a delightful user experience is to integrate tightly with the operating system. Features like <a href="{@docRoot}guide/topics/appwidgets/index.html">Home screen widgets</a>, <a href="{@docRoot}design/patterns/notifications.html">rich notifications</a>, <a href="{@docRoot}guide/topics/search/index.html">global search integration</a>, and {@link android.widget.QuickContactBadge Quick Contacts} are fairly low-hanging fruit in this regard. </p>
-
-<p>For some app categories, basic features like home screen widgets are par for the course. Not including them is a sure-fire way to tarnish an otherwise positive user experience. Some apps can achieve even tighter OS integration with Android's contacts, accounts, and sync APIs. </p>
-<p>
-Third-party integrations can provide even more user delight and give the user a feeling of device cohesiveness. It's also a really nice way of adding functionality to your app without writing any extra code (by leveraging other apps' functionalities). For example, if you're creating a camera app, you can allow users to edit their photos in another app before saving them to their collection, if they have that third-party application installed. More information on this subject is available in the Android Training class <a href="{@docRoot}training/basics/intents/index.html">Interacting with Other Apps</a>.</p>
-
-<h2 id="details">Pay Attention to Details</h2>
-<p>
-One particular detail to pay close attention to is your app's icon quality and consistency. Make sure your app icons (especially your launcher icon) are crisp and pixel-perfect at all resolutions, and follow the <a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">icon guidelines</a> as much as possible. If you're having trouble or don't have the resources to design the icons yourself, consider using the <a href="http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html">Android Asset Studio</a> tool to generate a set.</p>
diff --git a/docs/html/distribute/googleplay/strategies/featuring.jd b/docs/html/distribute/googleplay/strategies/featuring.jd
deleted file mode 100644
index 4c4e67e..0000000
--- a/docs/html/distribute/googleplay/strategies/featuring.jd
+++ /dev/null
@@ -1,4 +0,0 @@
-page.title=Preparing for Featuring
-@jd:body
-
-<p>Placeholder...</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/strategies/index.jd b/docs/html/distribute/googleplay/strategies/index.jd
deleted file mode 100644
index 3794bbf..0000000
--- a/docs/html/distribute/googleplay/strategies/index.jd
+++ /dev/null
@@ -1,33 +0,0 @@
-page.title=Success Strategies
-page.metaDescription=
-header.hide=1
-footer.hide=1
-
-@jd:body
-
-
-
-<style>
-#landing-graphic-container {
- position: relative;
-}
-
-#text-overlay {
- position: absolute;
- left: 0;
- top: 472px;
- width: 280px;
-}
-</style>
-
-<div id="landing-graphic-container">
- <div id="text-overlay">
- Strategies for building ratings, improving reviews, monetizing, and more.
- <br><br>
- <a href="/distribute/googleplay/promote/product-pages.html" class="landing-page-link">Preparing for Featuring</a>
- </div>
-
- <a href="{@docRoot}distribute/googleplay/promote/index.html">
- <img src="{@docRoot}design/media/index_landing_page.png">
- </a>
-</div>
\ No newline at end of file
diff --git a/docs/html/distribute/images/about-play-education.jpg b/docs/html/distribute/images/about-play-education.jpg
new file mode 100644
index 0000000..1fe6b2c
--- /dev/null
+++ b/docs/html/distribute/images/about-play-education.jpg
Binary files differ
diff --git a/docs/html/distribute/images/about-play.jpg b/docs/html/distribute/images/about-play.jpg
new file mode 100644
index 0000000..e62cb58
--- /dev/null
+++ b/docs/html/distribute/images/about-play.jpg
Binary files differ
diff --git a/docs/html/distribute/images/advertising.jpg b/docs/html/distribute/images/advertising.jpg
new file mode 100644
index 0000000..9625671
--- /dev/null
+++ b/docs/html/distribute/images/advertising.jpg
Binary files differ
diff --git a/docs/html/distribute/images/advertising.png b/docs/html/distribute/images/advertising.png
new file mode 100644
index 0000000..5dc0ed4
--- /dev/null
+++ b/docs/html/distribute/images/advertising.png
Binary files differ
diff --git a/docs/html/distribute/images/alt-distribution.jpg b/docs/html/distribute/images/alt-distribution.jpg
new file mode 100644
index 0000000..39c0514
--- /dev/null
+++ b/docs/html/distribute/images/alt-distribution.jpg
Binary files differ
diff --git a/docs/html/distribute/images/android-support-card.jpg b/docs/html/distribute/images/android-support-card.jpg
new file mode 100644
index 0000000..b1883c0
--- /dev/null
+++ b/docs/html/distribute/images/android-support-card.jpg
Binary files differ
diff --git a/docs/html/distribute/images/build-buzz.jpg b/docs/html/distribute/images/build-buzz.jpg
new file mode 100644
index 0000000..3f83a1a
--- /dev/null
+++ b/docs/html/distribute/images/build-buzz.jpg
Binary files differ
diff --git a/docs/html/distribute/images/core-quality-guidelines.jpg b/docs/html/distribute/images/core-quality-guidelines.jpg
new file mode 100644
index 0000000..d0c2479
--- /dev/null
+++ b/docs/html/distribute/images/core-quality-guidelines.jpg
Binary files differ
diff --git a/docs/html/distribute/images/create-listing.jpg b/docs/html/distribute/images/create-listing.jpg
new file mode 100644
index 0000000..befb936
--- /dev/null
+++ b/docs/html/distribute/images/create-listing.jpg
Binary files differ
diff --git a/docs/html/distribute/images/default.jpg b/docs/html/distribute/images/default.jpg
new file mode 100644
index 0000000..8050744
--- /dev/null
+++ b/docs/html/distribute/images/default.jpg
Binary files differ
diff --git a/docs/html/distribute/images/developer-console.jpg b/docs/html/distribute/images/developer-console.jpg
new file mode 100644
index 0000000..09f4a86
--- /dev/null
+++ b/docs/html/distribute/images/developer-console.jpg
Binary files differ
diff --git a/docs/html/distribute/images/ecommerce.jpg b/docs/html/distribute/images/ecommerce.jpg
new file mode 100644
index 0000000..0b2efdc
--- /dev/null
+++ b/docs/html/distribute/images/ecommerce.jpg
Binary files differ
diff --git a/docs/html/distribute/images/edu-guidelines.jpg b/docs/html/distribute/images/edu-guidelines.jpg
new file mode 100644
index 0000000..280dcfee
--- /dev/null
+++ b/docs/html/distribute/images/edu-guidelines.jpg
Binary files differ
diff --git a/docs/html/distribute/images/expand-into-new-markets.jpg b/docs/html/distribute/images/expand-into-new-markets.jpg
new file mode 100644
index 0000000..0f17f13
--- /dev/null
+++ b/docs/html/distribute/images/expand-into-new-markets.jpg
Binary files differ
diff --git a/docs/html/distribute/images/freemium.jpg b/docs/html/distribute/images/freemium.jpg
new file mode 100644
index 0000000..6919202
--- /dev/null
+++ b/docs/html/distribute/images/freemium.jpg
Binary files differ
diff --git a/docs/html/distribute/images/getting-started.jpg b/docs/html/distribute/images/getting-started.jpg
new file mode 100644
index 0000000..47f524a
--- /dev/null
+++ b/docs/html/distribute/images/getting-started.jpg
Binary files differ
diff --git a/docs/html/distribute/images/gp-app-practices.png b/docs/html/distribute/images/gp-app-practices.png
new file mode 100644
index 0000000..0afc4cb
--- /dev/null
+++ b/docs/html/distribute/images/gp-app-practices.png
Binary files differ
diff --git a/docs/html/distribute/images/gp-edu-apps-image.jpg b/docs/html/distribute/images/gp-edu-apps-image.jpg
new file mode 100644
index 0000000..8785db1
--- /dev/null
+++ b/docs/html/distribute/images/gp-edu-apps-image.jpg
Binary files differ
diff --git a/docs/html/distribute/images/gp-games-practices.png b/docs/html/distribute/images/gp-games-practices.png
new file mode 100644
index 0000000..e2b63c5
--- /dev/null
+++ b/docs/html/distribute/images/gp-games-practices.png
Binary files differ
diff --git a/docs/html/distribute/images/gp-optimize-card.jpg b/docs/html/distribute/images/gp-optimize-card.jpg
new file mode 100644
index 0000000..4c91f1c
--- /dev/null
+++ b/docs/html/distribute/images/gp-optimize-card.jpg
Binary files differ
diff --git a/docs/html/distribute/images/gpfe-faq.jpg b/docs/html/distribute/images/gpfe-faq.jpg
new file mode 100644
index 0000000..cf10a95
--- /dev/null
+++ b/docs/html/distribute/images/gpfe-faq.jpg
Binary files differ
diff --git a/docs/html/distribute/images/know-your-user.jpg b/docs/html/distribute/images/know-your-user.jpg
new file mode 100644
index 0000000..9336125
--- /dev/null
+++ b/docs/html/distribute/images/know-your-user.jpg
Binary files differ
diff --git a/docs/html/distribute/images/launch-checklist.jpg b/docs/html/distribute/images/launch-checklist.jpg
new file mode 100644
index 0000000..c571c9e
--- /dev/null
+++ b/docs/html/distribute/images/launch-checklist.jpg
Binary files differ
diff --git a/docs/html/distribute/images/localization-checklist.jpg b/docs/html/distribute/images/localization-checklist.jpg
new file mode 100644
index 0000000..26765fe
--- /dev/null
+++ b/docs/html/distribute/images/localization-checklist.jpg
Binary files differ
diff --git a/docs/html/distribute/images/payment-method.jpg b/docs/html/distribute/images/payment-method.jpg
new file mode 100644
index 0000000..a9f8b19
--- /dev/null
+++ b/docs/html/distribute/images/payment-method.jpg
Binary files differ
diff --git a/docs/html/distribute/images/play-education.jpg b/docs/html/distribute/images/play-education.jpg
new file mode 100644
index 0000000..8780993
--- /dev/null
+++ b/docs/html/distribute/images/play-education.jpg
Binary files differ
diff --git a/docs/html/distribute/images/premium.jpg b/docs/html/distribute/images/premium.jpg
new file mode 100644
index 0000000..210fddb
--- /dev/null
+++ b/docs/html/distribute/images/premium.jpg
Binary files differ
diff --git a/docs/html/distribute/images/subscription.jpg b/docs/html/distribute/images/subscription.jpg
new file mode 100644
index 0000000..9b6f112
--- /dev/null
+++ b/docs/html/distribute/images/subscription.jpg
Binary files differ
diff --git a/docs/html/distribute/images/tablet-guidelines-color.jpg b/docs/html/distribute/images/tablet-guidelines-color.jpg
new file mode 100644
index 0000000..ffb1a03
--- /dev/null
+++ b/docs/html/distribute/images/tablet-guidelines-color.jpg
Binary files differ
diff --git a/docs/html/distribute/images/tablet-guidelines.jpg b/docs/html/distribute/images/tablet-guidelines.jpg
new file mode 100644
index 0000000..b16b48c
--- /dev/null
+++ b/docs/html/distribute/images/tablet-guidelines.jpg
Binary files differ
diff --git a/docs/html/distribute/index.jd b/docs/html/distribute/index.jd
index 6c6e113..da960ce 100644
--- a/docs/html/distribute/index.jd
+++ b/docs/html/distribute/index.jd
@@ -1,38 +1,21 @@
-page.title=Distribute Apps
+page.title=Distribute Your Apps
page.viewport_width=970
+section.landing=true
header.hide=1
+nonavpage=true
+page.metaDescription=The most visited store in the world for Android apps. Cloud-connected and always synced, it's never been easier for users to find and download your apps.
@jd:body
-
-
-<div class="marquee">
- <div class="madin-img" style="position:absolute;margin-left:42px;margin-top:76px;">
- <img src="{@docRoot}images/home/google-play.png">
- </div>
- <div class="copy" style="position:relative;left:480px;width:360;">
- <h1 style="margin-bottom:10px;">Your Apps on Google Play</h1>
- <p>The most visited store in the world for Android apps. Cloud-connected and always synced,
- it's never been easier for users to find and download your apps.</p>
- <p><a class="button" href="https://play.google.com/apps/publish/"
- >Go to Developer Console »</a></p>
- </div>
-</div>
-<div class="distribute-features col-13" style="clear:both;margin-top:246px;">
- <ul>
- <li><h5>Growth Engine</h5>
- A billion downloads a month and growing. Get your apps in front of millions of users at Google's scale.<br />
- <a href="{@docRoot}distribute/googleplay/about/visibility.html">Read More ›</a>
- <li><h5>Build Your Business</h5> Sell your app in over 130 countries. Flexible monetization options with in-app purchase, subscriptions, and more. <br />
- <a href="{@docRoot}distribute/googleplay/about/monetizing.html">Read More ›</a></li>
- <li class="last"><h5>Distribution Control</h5> Deliver your apps to the users you want, on the devices you want, on <em>your</em> schedule. <br />
- <a href="{@docRoot}distribute/googleplay/about/distribution.html">Read More ›</a></li>
- </ul>
-</div>
-
-
-
-
-
-
+ <div class="resource-widget resource-carousel-layout col-16"
+ style="height:420px;margin-top:20px;padding-top:0"
+ data-query="type:youtube+tag:googleplay+tag:developerstory+tag:featured, type:blog+tag:googleplay+tag:distribute+tag:featured"
+ data-sortOdrder="-timestamp"
+ data-maxResults="4"></div>
+
+ <div class="resource-widget resource-flow-layout col-16"
+ data-query="collection:launch/static"
+ data-sortOrder=""
+ data-cardSizes="6x6,6x6,6x2x3,12x6,6x6,6x2x3,6x6,6x6,12x6,6x6"
+ data-maxResults="24"></div>
diff --git a/docs/html/distribute/monetize/ads.jd b/docs/html/distribute/monetize/ads.jd
new file mode 100644
index 0000000..40120c3
--- /dev/null
+++ b/docs/html/distribute/monetize/ads.jd
@@ -0,0 +1,114 @@
+page.title=Monetize with Ads
+page.metaDescription=Ads are a quick and easy way to incorporate a monetization option into both your free and paid apps.
+page.tags="monetizing", "free", "freemium", "ads"
+page.image=/distribute/images/advertising.png
+
+@jd:body
+
+<div class="figure">
+ <img src="{@docRoot}distribute/images/advertising.jpg" style="width:460px;">
+</div>
+
+<p>
+ In-app advertising offers a quick and easy way to incorporate a monetization
+ option into both your <a href=
+ "{@docRoot}distribute/monetize/freemium.html">freemium</a>, <a href=
+ "{@docRoot}distribute/monetize/premium.html">premium</a>, and <a href=
+ "{@docRoot}distribute/monetize/subscriptions.html">subscription</a> apps. </p>
+
+<p>Using <a href=
+ "http://www.google.com/ads/admob/monetize.html#subid=us-en-et-dac">AdMob</a>
+ and the <a href="{@docRoot}google/play-services/ads.html">Google
+ Mobile Ads SDK</a> included in Google Play Services, you’re able to add
+ advertising into your apps, with just a few lines of code.
+</p>
+
+<p>
+ When including ads in your apps you should consider:
+</p>
+
+<ul>
+ <li>
+ <p>
+ <strong>Placement within your apps</strong> — Well placed ads will
+ optimize your revenue by making it more likely that users will ‘click
+ through’. Poorly placed ads can result in low click-through rates, and in
+ the worse cases poor rating and users rapidly abandoning your apps. You
+ can get advice on how to best place ads from the developer training on
+ <a href=
+ "{@docRoot}training/monetization/ads-and-ux.html">using
+ ads</a>.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <strong>Ad formats</strong> — Every app offers a different type of
+ experience for users, so it’s important to consider the format of ads
+ you’re using to ensure it’s compatible with the experience. While banner
+ ads may work well for a flashlight utility app, an immersive gaming app
+ may benefit more from a video interstitial. Mismatched ad formats may
+ negatively affect your users’ experience and ad revenue, so try to select
+ formats that fit well with the content and flow of your apps.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <strong>Maximizing your performance</strong> — Ensure you’re optimizing
+ your advertising revenue by maximizing your CPMs <em>and</em> fill rate.
+ Often ad providers will cite very high CPMs but will have a low fill rate
+ that can severely decrease your effective CPM, so look at both of these
+ figures. Also consider using a <a href=
+ "https://support.google.com/admob/v2/answer/3063564?hl=en&ref_topic=3063091#subid=us-en-et-dac">
+ mediation</a> solution if you’d like to use multiple ad providers in your
+ apps. Look for solutions that offer yield management or <a href=
+ "https://support.google.com/admob/v2/answer/3379794?hl=en&ref_topic=3379793#subid=us-en-et-dac">
+ network optimization</a> features to serve the highest paying ad for each
+ impression.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <strong>Exercising control options</strong> — A variety of ads promoting a
+ broad selection of other services or apps may show up within you apps.
+ Depending on your goals and the type of experience you want to provide
+ your users, it may make sense to <a href=
+ "https://support.google.com/admob/v2/answer/3150235?hl=enl#subid=us-en-et-dac">
+ block</a> certain advertisements from appearing. Some developers don’t
+ want apps in a similar category showing to their users, but some don’t
+ mind.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ <strong>Cross promoting your other apps</strong> — Ads can be used for
+ more than just earning revenue. Consider using <a href=
+ "https://support.google.com/admob/v2/answer/3210452?hl=en#subid=us-en-et-dac">
+ house ads</a> within your apps to create awareness and promote your
+ entire portfolio of apps. When launching new apps, an easy way to quickly
+ attract users is to promote directly to your existing customers.
+ </p>
+ </li>
+</ul>
+
+<p>
+ To start monetizing with ads sign up for <a href=
+ "http://www.google.com/ads/admob/#subid=us-en-et-dac">AdMob</a> and integrate
+ the <a href="https://developers.google.com/mobile-ads-sdk/download">Google
+ Mobile Ads SDK</a> into your apps. If you also need to manage direct deals
+ with advertisers, consider using <a href=
+ "http://www.google.com/doubleclick/publishers/small-business/index.html#subid=us-en-et-dac">
+ DoubleClick for Publishers Small Business</a>.
+</p>
+
+<div class="headerLine"><h1 id="related-resources">Related resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/monetize/advertising"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/monetize/ecommerce.jd b/docs/html/distribute/monetize/ecommerce.jd
new file mode 100644
index 0000000..b3f790d
--- /dev/null
+++ b/docs/html/distribute/monetize/ecommerce.jd
@@ -0,0 +1,59 @@
+page.title=E-commerce
+page.image=/distribute/images/ecommerce.jpg
+page.metaImage=With Instant Buy you can sell physical goods and services from your web pages.
+page.tags="monetizing", "physical goods", "wallet"
+@jd:body
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-ecom-0.png" style="width:300px;">
+ <p class="img-caption">
+ Product Purchase with Instant Buy
+ </p>
+</div>
+
+<p>
+ With Google Wallet Instant Buy, you've the added flexibility of selling
+ physical goods and services, such as clothing or movie tickets, through your
+ apps using <a href=
+ "https://developers.google.com/wallet/instant-buy/">Instant Buy for
+ Android</a> in the US.
+</p>
+
+<p>
+ You can use this option where your app is the store-front for retail or
+ webtail operations. However, you can also combine it with your <a href=
+ "{@docRoot}distribute/monetize/premium.html">premium</a> and <a href=
+ "{@docRoot}distribute/monetize/freemium.html">freemium</a> apps by offering
+ related products.
+</p>
+
+<p>
+ Your customers purchase goods and services with any Google Wallet payment
+ method — credit card, gift card, or Wallet balance. Google Wallet
+ Instant Buy helps you minimize user data entry by enabling your payment flow
+ to retrieve information directly from the user’s wallet.
+</p>
+
+<p>
+ You also keep your existing payment infrastructure and leverage Google Wallet
+ to optimize your payment flow — users can make purchases in as a few as
+ two clicks and the flow is simplified with features to retrieve information
+ directly from the user’s wallet and intelligent auto-completion of addresses.
+ To get started, set up a <a href=
+ "{@docRoot}distribute/googleplay/start.html#merchant-account">Merchant
+ Account</a>.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="related-resources">
+ Related Resources
+ </h1>
+
+ <hr>
+</div>
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/monetize/ecommerce"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/monetize/freemium.jd b/docs/html/distribute/monetize/freemium.jd
new file mode 100644
index 0000000..ec86d19
--- /dev/null
+++ b/docs/html/distribute/monetize/freemium.jd
@@ -0,0 +1,80 @@
+page.title=Monetize Freemium Apps
+page.image=/distribute/images/freemium.jpg
+page.metaDescription=Use Google Play In-app Billing and other tools to monetize your free apps.
+page.tags="in-app", "billing", "iap", "monetizing"
+@jd:body
+
+<p>
+ Users are more likely to download free apps and games compared to priced
+ ones. However, we provide you with a number of ways to monetize free apps,
+ using <a href="{@docRoot}google/play/billing/index.html">In-app
+ Billing</a>. With this tool you can sell digital goods that are:
+</p>
+
+<ul>
+ <li>Durable — once purchased the item will always be available to the
+ user, such as additional app features.
+ </li>
+
+ <li>Consumable — items that might be used progressively or expire after
+ a period of time, such as a game booster or news subscription.
+ </li>
+</ul>
+
+<p>
+ A basic approach is to offer a free download with limited features or full
+ features for a limited time. Then use an in-app purchase to unlock the full,
+ unlimited app.
+</p>
+
+<div class="center-img" style="width:620px">
+<div style="float:right; width:300px; padding-left:1em;">
+ <img src="{@docRoot}images/gp-freemium-1.jpg" class="border-img">
+ <p class="img-caption">
+ Consumable product purchase
+ </p>
+</div>
+
+<div style="width:300px;float:left;">
+ <img src="{@docRoot}images/gp-freemium-0.jpg" class="border-img">
+ <p class="img-caption">
+ Durable goods purchase
+ </p>
+</div>
+</div>
+
+<p class="clearfloat">
+ A more advanced approach is to offer a range of features and content items
+ through in-app purchases. For example, in games you can offer users new
+ levels, playing pieces, or other game features. In apps you can offer
+ features or functionality that enhance the user experience either by
+ extending existing features or offering new ones. Using this approach you can
+ generate a continuing revenue stream from each app install.
+</p>
+
+<p>
+ Any item offered as an in-app purchase can also be offered as a subscription.
+</p>
+
+<p>
+ To get started with In-app Billing you need to set-up a Google Wallet
+ <a href="{@docRoot}distribute/googleplay/start.html#merchant-account">Merchant
+ Account</a> from Developer Console. You then define <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html#in-app-products">in-app
+ products</a> in the Developer Console, integrate the In-app Billing API into
+ your apps, and add the mechanisms to unlock features or deliver content.
+</p>
+
+<div class="headerLine">
+ <h1 id="related-resources">
+ Related Resources
+ </h1>
+
+ <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/monetize/freemium"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3,9x3,9x3,9x3,6x3,6x3"
+ data-maxResults="6"></div>
diff --git a/docs/html/distribute/monetize/index.jd b/docs/html/distribute/monetize/index.jd
new file mode 100644
index 0000000..7350a24
--- /dev/null
+++ b/docs/html/distribute/monetize/index.jd
@@ -0,0 +1,36 @@
+page.title=Monetize
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+<p>
+ There are many ways to make money with your apps on Google Play, and we offer
+ a variety of tools to make it easy. Take advantage of Google Play’s
+ phenomenal growth by using one or more of the business models available.
+</p>
+
+<p>
+ To get started, set up your <a href=
+ "{@docRoot}distribute/googleplay/start.html#merchant-account">Merchant Account</a>
+ from your Developer Console. This will not only help you get paid, but also
+ help you track where your money is coming from.
+</p>
+
+<div class="dynamic-grid">
+
+ <div class="resource-widget resource-flow-layout landing col-16"
+ data-query="collection:distribute/monetize"
+ data-cardSizes="6x6"
+ data-maxResults="9">
+ </div>
+
+<h3>Related resources</h3>
+
+ <div class="resource-widget resource-flow-layout col-16"
+ data-query="tag:monetizing"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x3"
+ data-maxResults="6">
+ </div>
+</div>
diff --git a/docs/html/distribute/monetize/monetize_toc.cs b/docs/html/distribute/monetize/monetize_toc.cs
new file mode 100644
index 0000000..aeb6cf8
--- /dev/null
+++ b/docs/html/distribute/monetize/monetize_toc.cs
@@ -0,0 +1,47 @@
+<ul id="nav">
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/premium.html">
+ <span class="en">Premium</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/freemium.html">
+ <span class="en">Freemium</span>
+ </a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/subscriptions.html">
+ <span class="en">Subscriptions</span>
+ </a
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/ecommerce.html">
+ <span class="en">E-commerce</span>
+ </a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/ads.html">
+ <span class="en">Ads</span>
+ </a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/payments.html">
+ <span class="en">Purchasing</span>
+ </a>
+ </div>
+ </li>
+
+</ul>
+
+
+<script type="text/javascript">
+<!--
+ buildToggleLists();
+ changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html/distribute/monetize/payments.jd b/docs/html/distribute/monetize/payments.jd
new file mode 100644
index 0000000..37b4d44
--- /dev/null
+++ b/docs/html/distribute/monetize/payments.jd
@@ -0,0 +1,104 @@
+page.title=Convenient, Frictionless Purchasing
+page.image=/distribute/images/payment-method.jpg
+page.metaDescription=Users can purchase instantly with a choice of payment methods.
+page.tags="google play", "payments", "gift card"
+
+@jd:body
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-start-wallet-icon.png" style="width:200px;">
+</div>
+
+<p>
+ Google Play makes it fast and easy for your customers to buy your products,
+ whether from a phone, a tablet, or a desktop computer. They can purchase
+ instantly with a streamlined, consistent purchasing process and convenient
+ payment methods.
+</p>
+
+<div class="headerLine">
+ <h1 id="dcb">
+ Direct Carrier Billing
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Users pay by charging their monthly carrier bills . The benefit of Direct
+ Carrier Billing is that it opens up markets where credit cards are less
+ common, as purchases are charged to your customers’ monthly mobile phone
+ bills. This option is available to users in key markets
+ around the world. Many more will get the option in the months ahead.
+</p>
+
+<div class="headerLine">
+ <h1 id="credit">
+ Credit Cards
+ </h1>
+ <hr>
+</div>
+
+<p>
+ Users can pay using any credit card that they’ve registered in Google Play.
+ Credit Cards added to Google Play are stored in the user’s Google Wallet and
+ available for in-app purchases and instant buys too. To make it easy for
+ users to get started, registration is offered as a part of the initial device
+ setup process.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="gift-cards">
+ Google Play Gift Cards
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-payments-1.png">
+</div>
+
+<p>
+ Gift cards enable users to add value to their Google Play balance by entering
+ a unique code printed on a card purchased online or from major retailers.
+ More information gift cards can be found <a href=
+ "http://play.google.com/intl/en-US_us/about/giftcards/" target=
+ "_android">here</a>.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="balance">
+ Google Play Balance
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-balance.png">
+</div>
+
+<p>
+ Google Play balance, also known as stored value, is a stored account balance
+ in Google Play. Users can increase their balance by redeeming <a href=
+ "https://play.google.com/intl/en-US_us/about/giftcards/">gift cards</a> or by
+ earning rewards through the <a href=
+ "https://play.google.com/store/apps/details?id=com.google.android.apps.paidtasks&hl=en">
+ Google Opinions Rewards app</a>, and they can use their balance to make
+ purchases of apps, games, or other content.
+</p>
+
+<p>
+ The payment methods available to users may vary based on location, carrier
+ network, and other factors.
+</p>
+
+<div class="headerLine clearfloat"><h1 id="related-resources">Related Resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/monetize/paymentmethods"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="8"></div>
+
diff --git a/docs/html/distribute/monetize/premium.jd b/docs/html/distribute/monetize/premium.jd
new file mode 100644
index 0000000..b66cd03
--- /dev/null
+++ b/docs/html/distribute/monetize/premium.jd
@@ -0,0 +1,49 @@
+page.title=Monetize Premium Apps
+page.image=/distribute/images/premium.jpg
+page.metaDescription=Charging users to download your apps is a simple, convenient monetization model.
+page.tags="monetizing", "paid"
+
+@jd:body
+
+<div class="figure"><img src="{@docRoot}images/gp-premium-0.png" />
+<p class="img-caption" style="width:300px">Paid app</p>
+</div>
+<p>
+ Charging users to download your apps is a simple, convenient monetization
+ model. After creating your <a href=
+ "/distribute/googleplay/start.html#merchant-account">Merchant
+ Account</a>, you <a href=
+ "/distribute/googleplay/developer-console.html#selling-pricing-your-products">set prices for your
+ apps</a> in the Developer Console. You can optionally include advertising or use
+ <a href="{@docRoot}google/play/billing/index.html">In-app
+ Billing</a> to sell additional features or content.
+</p>
+
+<p>
+ This model could work well for any app or game, but might be particularly
+ relevant to those with extensive features or that address a narrow niche in
+ the market. Certain categories of apps, such as games for children, should be
+ monetized by paying for them up front instead of advertising or in-app
+ purchases.
+</p>
+
+<p>
+ However, this model may limit your apps monetization potential, particularly
+ in developing markets. You may be able to achieve greater revenue using the
+ <a href="{@docRoot}distribute/monetize/freemium.html">freemium</a>, <a href=
+ "{@docRoot}distribute/monetize/subscriptions.html">subscriptions</a> or
+ <a href="{@docRoot}distribute/monetize/ads.html">advertising</a> models.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1>
+ Related Resources
+ </h1>
+ <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/monetize/premium"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/distribute/monetize/subscriptions.jd b/docs/html/distribute/monetize/subscriptions.jd
new file mode 100644
index 0000000..a838e30
--- /dev/null
+++ b/docs/html/distribute/monetize/subscriptions.jd
@@ -0,0 +1,71 @@
+page.title=Monetize with Subscriptions
+page.image=/distribute/images/subscription.jpg
+page.metaDescription=Sell subscriptions to your products to create continuing revenue streams.
+page.tags="in-app", "iap", "monetizing", "free", "trials"
+@jd:body
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-subscription-0.jpg">
+ <p class="img-caption" style="width:300px;">
+ In-App Subscriptions
+ </p>
+</div>
+
+<p>
+ Subscriptions provide an excellent opportunity to create continuing revenue
+ streams. Subscriptions are similar to digital goods offered through <a href=
+ "{@docRoot}google/play/billing/index.html">In-app Billing</a> but made
+ available on a recurring monthly or annual basis.
+</p>
+
+<p>
+ When users purchase subscriptions in your apps, Google Play handles all
+ checkout details so your apps never have to directly process any financial
+ transactions. Google Play processes all payments for subscriptions through
+ Google Wallet, just as it does for standard in-app products and app
+ purchases. This ensures a consistent and familiar purchase flow for your
+ users and reduces cart abandonment rates.
+</p>
+
+<p>
+ At a basic level you can offer use of your apps or access to their content on
+ a subscription basis, using a <a href=
+ "{@docRoot}google/play/billing/billing_subscriptions.html#trials">free trial
+ subscription</a> to allow users to explore the apps or content.
+</p>
+
+<p>
+ A more advanced approach is to offer specific features or content items as
+ subscriptions within your apps. This way you can offer users basic or core
+ features or content for free or part of the initial purchase and extended
+ features or content as subscriptions. You can have multiple subscriptions
+ active in an app at any one time.
+</p>
+
+<p>
+ To get started with subscriptions you need to set-up a Google Wallet <a href=
+ "{@docRoot}distribute/googleplay/start.html#merchant-account">Merchant
+ Account</a> from the Developer Console. You then define subscriptions for
+ published or draft apps in the <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html#in-app-billing">In-app
+ Products</a> section of the Developer Console, integrate the In-app Billing
+ API into your apps, and add the mechanisms to unlock subscribed features or
+ deliver content.
+</p>
+
+<div class="sidebox" style="width:400px;float:left;margin-left:0">
+ <p>
+ <strong>Tip:</strong> Due to some direct carrier billing limits, we
+ recommend monthly subscriptions. Annual subscriptions may exceed limits,
+ causing the purchase to be blocked and you to lose that revenue.
+ </p>
+</div>
+
+<div class="headerLine clearfloat"><h1 id="related-resources">Related Resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/monetize/subscriptions"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/open.jd b/docs/html/distribute/open.jd
deleted file mode 100644
index f9e9c3b..0000000
--- a/docs/html/distribute/open.jd
+++ /dev/null
@@ -1,107 +0,0 @@
-page.title=Open Distribution
-@jd:body
-
-<p>As an open platform, Android offers choice. You
-distribute your Android apps to users in any way you want, using any
-distribution approach or combination of approaches that meets your needs.
-From publishing in an app marketplace to serving your apps from a web site or
-emailing them directly users, you are never locked into any
-particular distribution platform.</p>
-
-<p>The process for building and packaging your app for distribution is the same,
-regardless of how you will distribute your app. This saves you time and lets you
-automate parts of the process as needed. You can read <a
-href="{@docRoot}tools/publishing/preparing.html">Preparing
-for Release</a> for more information.</p>
-
-<p>The sections below highlight some of the alternatives for distributing
-your apps to users.</p>
-
-<h2 id="publishing-marketplace">Distributing through an App Marketplace</h2>
-
-<p>Usually, to reach the broadest possible audience, you would distribute your
-apps through a marketplace, such as Google Play.</p>
-
-<p>Google Play is the premier marketplace for Android apps and is particularly
-useful if you want to distribute your applications to a large global audience.
-However, you can distribute your apps through any app marketplace you want or
-you can use multiple marketplaces.</p>
-
-<h2 id="publishing-email">Distributing your application through email</h2>
-
-<div class="figure" style="width:246px">
- <img src="{@docRoot}images/publishing/publishing_via_email.png"
- alt="Screenshot showing the graphical user interface users see when you send them an app"
- style="width:240px;" />
- <p class="img-caption">
- <strong>Figure 1.</strong> Users can simply click <strong>Install</strong> when you send them
- an application via email.
- </p>
-</div>
-
-<p>The easiest and quickest way to release your application is to send it to users through
-email. To do this, you prepare your application for release and then attach it to an email
-and send it to a user. When users open your email message on their Android-powered device,
-the Android system will recognize the APK and display an <strong>Install Now</strong>
-button in the email message (see figure 1). Users can install your application by touching the
-button.</p>
-
-<p class="note"><strong>Note:</strong> The <strong>Install Now</strong> button
-shown in Figure 1 appears only if users have configured their device to allow
-installation from <a href="#unknown-sources">unknown sources</a> and have opened your
-email with the native Gmail application.</p>
-
-<p>Distributing applications through email is convenient if you are sending your application to
-only a few trusted users, but it provides few protections from piracy and unauthorized
-distribution; that is, anyone you send your application to can simply forward it to someone else.</p>
-
-<h2 id="publishing-website">Distributing through a web site</h2>
-
-<p>If you do not want to release your app on a marketplace like Google Play, you
-can make the app available for download on your own website or server, including
-on a private or enterprise server. To do this, you must first prepare your
-application for release in the normal way. Then all you need to do is host the
-release-ready APK file on your website and provide a download link to users.
-</p>
-
-<p>When users browse to the download link from their Android-powered devices,
-the file is downloaded and Android system automatically starts installing it on
-the device. However, the installation process will start automatically only if
-users have configured their Settings to allow the installation of apps from
-<a href="#unknown-sources">unknown sources</a>.</p>
-
-<p>Although it is relatively easy to release your application on your own
-website, it can be inefficient. For example, if you want to monetize your
-application you will have to process and track all financial transactions
-yourself and you will not be able to use Google Play's <a
-href="{@docRoot}google/play/billing/index.html">In-app Billing service</a>
-to sell in-app products. In addition, you will not be able to use the <a
-href="{@docRoot}google/play/licensing/index.html">Licensing service</a> to
-help prevent unauthorized installation and use of your application.</p>
-
-
-<h2 id="unknown-sources">User Opt-In for Apps from Unknown Sources</h2>
-
-<div class="figure" style="width:246px;margin-top:0;">
- <img src="{@docRoot}images/publishing/publishing_unknown_sources_sm.png"
- alt="Screenshot showing the setting for accepting download and install of
- apps from unknown sources." style="width:240px;" />
- <p class="img-caption">
- <strong>Figure 2.</strong> Users must enable the <strong>Unknown sources</strong>
- setting before they can install apps not downloaded from Google Play.
- </p>
-</div>
-
-<p>Android protects users from inadvertent download and install of apps from
-locations other than Google Play (which is trusted). It blocks such installs
-until the user opts-in <strong>Unknown sources</strong> in
-Settings <strong>></strong> Security, shown in Figure 2. To allow
-the installation of applications from other sources, users need to enable the
-Unknown sources setting on their devices, and they need to make this
-configuration change <em>before</em> they download your application to their
-devices.</p>
-
-<p class="note">Note that some network providers do not allow users to install
-applications from unknown sources.</p>
-
-
diff --git a/docs/html/distribute/promote/device-art.jd b/docs/html/distribute/promote/device-art.jd
deleted file mode 100644
index b3b414e..0000000
--- a/docs/html/distribute/promote/device-art.jd
+++ /dev/null
@@ -1,693 +0,0 @@
-page.title=Device Art Generator
-@jd:body
-
-<p>The device art generator allows you to quickly wrap your app screenshots in real device artwork.
-This provides better visual context for your app screenshots on your web site or in other
-promotional materials.</p>
-
-<p class="note"><strong>Note</strong>: Do <em>not</em> use graphics created here in your 1024x500
-feature image or screenshots for your Google Play app listing.</p>
-
-<hr>
-
-<div class="supported-browser">
-
-<div class="layout-content-row">
- <div class="layout-content-col span-3">
- <h4>Step 1</h4>
- <p>Drag a screenshot from your desktop onto a device to the right.</p>
- </div>
- <div class="layout-content-col span-10">
- <ul class="device-list primary"></ul>
- <a href="#" id="archive-expando">Older devices</a>
- <ul class="device-list archive"></ul>
- </div>
-</div>
-
-<hr>
-
-<div class="layout-content-row">
- <div class="layout-content-col span-3">
- <h4>Step 2</h4>
- <p>Customize the generated image and drag it to your desktop to save.</p>
- <p id="frame-customizations">
- <input type="checkbox" id="output-shadow" checked="checked" class="form-field-checkbutton">
- <label for="output-shadow">Shadow</label><br>
- <input type="checkbox" id="output-glare" checked="checked" class="form-field-checkbutton">
- <label for="output-glare">Screen Glare</label><br><br>
- <a class="button" id="rotate-button">Rotate</a>
- </p>
- </div>
- <div class="layout-content-col span-10">
- <!-- position:relative fixes an issue where dragging an image out of a inline-block container
- produced no drag feedback image in Chrome 28. -->
- <div id="output" style="position:relative">No input image.</div>
- </div>
-</div>
-
-</div>
-
-<div class="unsupported-browser" style="display: none">
- <p class="warning"><strong>Error:</strong> This page requires
- <span id="unsupported-browser-reason">certain features</span>, which your web browser
- doesn't support. To continue, navigate to this page on a supported web browser, such as
- <strong>Google Chrome</strong>.</p>
- <a href="https://www.google.com/chrome/" class="button">Get Google Chrome</a>
- <br><br>
-</div>
-
-<style>
- h4 {
- text-transform: uppercase;
- }
-
- .device-list {
- padding: 0;
- margin: 0;
- }
-
- .device-list li {
- display: inline-block;
- vertical-align: bottom;
- margin: 0;
- margin-right: 20px;
- text-align: center;
- }
-
- .device-list li .thumb-container {
- display: inline-block;
- }
-
- .device-list li .thumb-container img {
- margin-bottom: 8px;
- opacity: 0.6;
-
- -webkit-transition: -webkit-transform 0.2s, opacity 0.2s;
- -moz-transition: -moz-transform 0.2s, opacity 0.2s;
- transition: transform 0.2s, opacity 0.2s;
- }
-
- .device-list li.drag-hover .thumb-container img {
- opacity: 1;
-
- -webkit-transform: scale(1.1);
- -moz-transform: scale(1.1);
- transform: scale(1.1);
- }
-
- .device-list li .device-details {
- font-size: 13px;
- line-height: 16px;
- color: #888;
- }
-
- .device-list li .device-url {
- font-weight: bold;
- }
-
- #archive-expando {
- display: block;
- font-size: 13px;
- font-weight: bold;
- color: #333;
- text-transform: uppercase;
- margin-top: 16px;
- padding-top: 16px;
- padding-left: 28px;
- border-top: 1px solid transparent;
- background: transparent url({@docRoot}assets/images/styles/disclosure_down.png)
- no-repeat scroll 0 8px;
- -webkit-transition: border 0.2s;
- -moz-transition: border 0.2s;
- transition: border 0.2s;
- }
-
- #archive-expando.expanded {
- background-image: url({@docRoot}assets/images/styles/disclosure_up.png);
- border-top: 1px solid #ccc;
- }
-
- .device-list.archive {
- max-height: 0;
- overflow: hidden;
- opacity: 0;
-
- -webkit-transition: max-height 0.2s, opacity 0.2s;
- -moz-transition: max-height 0.2s, opacity 0.2s;
- transition: max-height 0.2s, opacity 0.2s;
- }
-
- .device-list.archive.expanded {
- opacity: 1;
- max-height: 300px;
- }
-
- #output {
- color: #f44;
- font-style: italic;
- }
-
- #output img {
- max-height: 500px;
- }
-</style>
-<script>
- // Global variables
- var g_currentImage;
- var g_currentDevice;
- var g_currentObjectURL;
- var g_currentBlob;
-
- // Global constants
- var MSG_INVALID_INPUT_IMAGE = 'Invalid screenshot provided. Screenshots must be PNG files '
- + 'matching the target device\'s screen aspect ratio in either portrait or landscape.';
- var MSG_NO_INPUT_IMAGE = 'Drag a screenshot (in PNG format) from your desktop onto a '
- + 'target device above.'
- var MSG_GENERATING_IMAGE = 'Generating device art…';
-
- var MAX_DISPLAY_HEIGHT = 126; // XOOM, to fit into 200px wide
-
- // Device manifest.
- var DEVICES = [
- {
- id: 'nexus_5',
- title: 'Nexus 5',
- url: 'http://www.google.com/nexus/5/',
- physicalSize: 5,
- physicalHeight: 5.43,
- density: 'XXHDPI',
- landRes: ['shadow', 'back', 'fore'],
- landOffset: [436,306],
- portRes: ['shadow', 'back', 'fore'],
- portOffset: [304,436],
- portSize: [1080,1920],
- },
- {
- id: 'nexus_7',
- title: 'Nexus 7',
- url: 'http://www.google.com/nexus/7/',
- physicalSize: 7,
- physicalHeight: 8,
- actualResolution: [1200,1920],
- density: 'XHDPI',
- landRes: ['shadow', 'back', 'fore'],
- landOffset: [326,245],
- portRes: ['shadow', 'back', 'fore'],
- portOffset: [244,326],
- portSize: [800,1280]
- },
- {
- id: 'nexus_10',
- title: 'Nexus 10',
- url: 'http://www.google.com/nexus/10/',
- physicalSize: 10,
- physicalHeight: 7,
- actualResolution: [1600,2560],
- density: 'XHDPI',
- landRes: ['shadow', 'back', 'fore'],
- landOffset: [227,217],
- portRes: ['shadow', 'back', 'fore'],
- portOffset: [217,223],
- portSize: [800,1280]
- },
- {
- id: 'xoom',
- title: 'Motorola XOOM',
- url: 'http://www.google.com/phone/detail/motorola-xoom',
- physicalSize: 10,
- physicalHeight: 6.61,
- density: 'MDPI',
- landRes: ['shadow', 'back', 'fore'],
- landOffset: [218,191],
- portRes: ['shadow', 'back', 'fore'],
- portOffset: [199,200],
- portSize: [800,1280],
- archived: true
- },
- {
- id: 'nexus_7_2012',
- title: 'Nexus 7 (2012)',
- url: 'http://www.google.com/nexus/7/',
- physicalSize: 7,
- physicalHeight: 7.81,
- density: '213dpi',
- landRes: ['shadow', 'back', 'fore'],
- landOffset: [315,270],
- portRes: ['shadow', 'back', 'fore'],
- portOffset: [264,311],
- portSize: [800,1280],
- archived: true
- },
- {
- id: 'nexus_4',
- title: 'Nexus 4',
- url: 'http://www.google.com/nexus/4/',
- physicalSize: 4.7,
- physicalHeight: 5.27,
- density: 'XHDPI',
- landRes: ['shadow', 'back', 'fore'],
- landOffset: [349,214],
- portRes: ['shadow', 'back', 'fore'],
- portOffset: [213,350],
- portSize: [768,1280],
- archived: true
- },
- {
- id: 'galaxy_nexus',
- title: 'Galaxy Nexus',
- url: 'http://www.android.com/devices/detail/galaxy-nexus',
- physicalSize: 4.65,
- physicalHeight: 5.33,
- density: 'XHDPI',
- landRes: ['shadow', 'back', 'fore'],
- landOffset: [371,199],
- portRes: ['shadow', 'back', 'fore'],
- portOffset: [216,353],
- portSize: [720,1280],
- archived: true
- },
- {
- id: 'nexus_s',
- title: 'Nexus S',
- url: 'http://www.google.com/phone/detail/nexus-s',
- physicalSize: 4.0,
- physicalHeight: 4.88,
- density: 'HDPI',
- landRes: ['shadow', 'back', 'fore'],
- landOffset: [247,135],
- portRes: ['shadow', 'back', 'fore'],
- portOffset: [134,247],
- portSize: [480,800],
- archived: true
- }
- ];
-
- DEVICES = DEVICES.sort(function(x, y) { return x.physicalSize - y.physicalSize; });
-
- var MAX_HEIGHT = 0;
- for (var i = 0; i < DEVICES.length; i++) {
- MAX_HEIGHT = Math.max(MAX_HEIGHT, DEVICES[i].physicalHeight);
- }
-
- // Setup performed once the DOM is ready.
- $(document).ready(function() {
- if (!checkBrowser()) {
- return;
- }
-
- polyfillCanvasToBlob();
- setupUI();
-
- // Set up Chrome drag-out
- $.event.props.push("dataTransfer");
- document.body.addEventListener('dragstart', function(e) {
- var target = e.target;
- if (target.classList.contains('dragout')) {
- e.dataTransfer.setData('DownloadURL', target.dataset.downloadurl);
- }
- }, false);
- });
-
- /**
- * Returns the device from DEVICES with the given id.
- */
- function getDeviceById(id) {
- for (var i = 0; i < DEVICES.length; i++) {
- if (DEVICES[i].id == id)
- return DEVICES[i];
- }
- return;
- }
-
- /**
- * Checks to make sure the browser supports this page. If not,
- * updates the UI accordingly and returns false.
- */
- function checkBrowser() {
- // Check for browser support
- var browserSupportError = null;
-
- // Must have <canvas>
- var elem = document.createElement('canvas');
- if (!elem.getContext || !elem.getContext('2d')) {
- browserSupportError = 'HTML5 canvas.';
- }
-
- // Must have FileReader
- if (!window.FileReader) {
- browserSupportError = 'desktop file access';
- }
-
- if (browserSupportError) {
- $('.supported-browser').hide();
-
- $('#unsupported-browser-reason').html(browserSupportError);
- $('.unsupported-browser').show();
- return false;
- }
-
- return true;
- }
-
- function setupUI() {
- $('#output').html(MSG_NO_INPUT_IMAGE);
-
- $('#frame-customizations').hide();
-
- $('#output-shadow, #output-glare').click(function() {
- createFrame();
- });
-
- // Build device list.
- $.each(DEVICES, function() {
- var resolution = this.actualResolution || this.portSize;
- var scaleFactorText = '';
- if (resolution[0] != this.portSize[0]) {
- scaleFactorText = '<br>' + (100 * (this.portSize[0] / resolution[0])).toFixed(0) +
- '% size output';
- } else {
- scaleFactorText = '<br> ';
- }
-
- $('<li>')
- .append($('<div>')
- .addClass('thumb-container')
- .append($('<img>')
- .attr('src', 'device-art-resources/' + this.id + '/thumb.png')
- .attr('height',
- Math.floor(MAX_DISPLAY_HEIGHT * this.physicalHeight / MAX_HEIGHT))))
- .append($('<div>')
- .addClass('device-details')
- .html((this.url
- ? ('<a class="device-url" href="' + this.url + '">' + this.title + '</a>')
- : this.title) +
- '<br>' + this.physicalSize + '" @ ' + this.density +
- '<br>' + (resolution[0] + 'x' + resolution[1]) + scaleFactorText))
- .data('deviceId', this.id)
- .appendTo(this.archived ? '.device-list.archive' : '.device-list.primary');
- });
-
- // Set up "older devices" expando.
- $('#archive-expando').click(function() {
- if ($(this).hasClass('expanded')) {
- $(this).removeClass('expanded');
- $('.device-list.archive').removeClass('expanded');
- } else {
- $(this).addClass('expanded');
- $('.device-list.archive').addClass('expanded');
- }
- return false;
- });
-
- // Set up drag and drop.
- $('.device-list li')
- .live('dragover', function(evt) {
- $(this).addClass('drag-hover');
- evt.dataTransfer.dropEffect = 'link';
- evt.preventDefault();
- })
- .live('dragleave', function(evt) {
- $(this).removeClass('drag-hover');
- })
- .live('drop', function(evt) {
- $('#output').empty().html(MSG_GENERATING_IMAGE);
- $(this).removeClass('drag-hover');
- g_currentDevice = getDeviceById($(this).closest('li').data('deviceId'));
- evt.preventDefault();
- loadImageFromFileList(evt.dataTransfer.files, function(data) {
- if (data == null) {
- $('#output').html(MSG_INVALID_INPUT_IMAGE);
- return;
- }
- loadImageFromUri(data.uri, function(img) {
- g_currentFilename = data.name;
- g_currentImage = img;
- createFrame();
- // Send the event to Analytics
- _gaq.push(['_trackEvent', 'Distribute', 'Create Device Art', g_currentDevice.title]);
- });
- });
- });
-
- // Set up rotate button.
- $('#rotate-button').click(function() {
- if (!g_currentImage) {
- return;
- }
-
- var w = g_currentImage.naturalHeight;
- var h = g_currentImage.naturalWidth;
- var canvas = $('<canvas>')
- .attr('width', w)
- .attr('height', h)
- .get(0);
-
- var ctx = canvas.getContext('2d');
- ctx.rotate(-Math.PI / 2);
- ctx.translate(-h, 0);
- ctx.drawImage(g_currentImage, 0, 0);
-
- loadImageFromUri(canvas.toDataURL('image/png'), function(img) {
- g_currentImage = img;
- createFrame();
- });
- });
- }
-
- /**
- * Generates the frame from the current selections (g_currentImage and g_currentDevice).
- */
- function createFrame() {
- var port;
-
- var aspect1 = g_currentImage.naturalWidth / g_currentImage.naturalHeight;
- var aspect2 = g_currentDevice.portSize[0] / g_currentDevice.portSize[1];
-
- if (aspect1 == aspect2) {
- port = true;
- } else if (aspect1 == 1 / aspect2) {
- port = false;
- } else {
- alert('The screenshot must have an aspect ratio of ' +
- aspect2.toFixed(3) + ' or ' + (1 / aspect2).toFixed(3) +
- ' (ideally ' + g_currentDevice.portSize[0] + 'x' + g_currentDevice.portSize[1] +
- ' or ' + g_currentDevice.portSize[1] + 'x' + g_currentDevice.portSize[0] + ').');
- $('#output').html(MSG_INVALID_INPUT_IMAGE);
- return;
- }
-
- // Load image resources
- var res = port ? g_currentDevice.portRes : g_currentDevice.landRes;
- var resList = {};
- for (var i = 0; i < res.length; i++) {
- resList[res[i]] = 'device-art-resources/' + g_currentDevice.id + '/' +
- (port ? 'port_' : 'land_') + res[i] + '.png'
- }
-
- var resourceImages = {};
- loadImageResources(resList, function(r) {
- resourceImages = r;
- continueWithResources_();
- });
-
- function continueWithResources_() {
- var width = resourceImages['back'].naturalWidth;
- var height = resourceImages['back'].naturalHeight;
- var offset = port ? g_currentDevice.portOffset : g_currentDevice.landOffset;
- var size = port
- ? g_currentDevice.portSize
- : [g_currentDevice.portSize[1], g_currentDevice.portSize[0]];
-
- var canvas = document.createElement('canvas');
- canvas.width = width;
- canvas.height = height;
-
- var ctx = canvas.getContext('2d');
- if (resourceImages['shadow'] && $('#output-shadow').is(':checked')) {
- ctx.drawImage(resourceImages['shadow'], 0, 0);
- }
- ctx.drawImage(resourceImages['back'], 0, 0);
- ctx.fillStyle = '#000';
- ctx.fillRect(offset[0], offset[1], size[0], size[1]);
- ctx.drawImage(g_currentImage, offset[0], offset[1], size[0], size[1]);
- if (resourceImages['fore'] && $('#output-glare').is(':checked')) {
- ctx.drawImage(resourceImages['fore'], 0, 0);
- }
-
- window.URL = window.URL || window.webkitURL;
- if (canvas.toBlob && window.URL.createObjectURL) {
- if (g_currentObjectURL) {
- window.URL.revokeObjectURL(g_currentObjectURL);
- g_currentObjectURL = null;
- }
- if (g_currentBlob) {
- if (g_currentBlob.close) {
- g_currentBlob.close();
- }
- g_currentBlob = null;
- }
-
- canvas.toBlob(function(blob) {
- if (!blob) {
- continueWithFinalUrl_(canvas.toDataURL('image/png'));
- return;
- }
- g_currentBlob = blob;
- g_currentObjectURL = window.URL.createObjectURL(blob);
- continueWithFinalUrl_(g_currentObjectURL);
- }, 'image/png');
- } else {
- continueWithFinalUrl_(canvas.toDataURL('image/png'));
- }
- }
-
- function continueWithFinalUrl_(imageUrl) {
- var filename = g_currentFilename
- ? g_currentFilename.replace(/^(.+?)(\.\w+)?$/, '$1_framed.png')
- : 'framed_screenshot.png';
-
- var $link = $('<a>')
- .attr('download', filename)
- .attr('href', imageUrl)
- .append($('<img>')
- .addClass('dragout')
- .attr('src', imageUrl)
- .attr('draggable', true)
- .attr('data-downloadurl', ['image/png', filename, imageUrl].join(':')))
- .appendTo($('#output').empty());
-
- $('#frame-customizations').show();
- }
- }
-
- /**
- * Loads an image from a data URI. The callback will be called with the <img> once
- * it loads.
- */
- function loadImageFromUri(uri, callback) {
- callback = callback || function(){};
-
- var img = document.createElement('img');
- img.src = uri;
- img.onload = function() {
- callback(img);
- };
- img.onerror = function() {
- callback(null);
- }
- }
-
- /**
- * Loads a set of images (organized by ID). Once all images are loaded, the callback
- * is triggered with a dictionary of <img>'s, organized by ID.
- */
- function loadImageResources(images, callback) {
- var imageResources = {};
-
- var checkForCompletion_ = function() {
- for (var id in images) {
- if (!(id in imageResources))
- return;
- }
- (callback || function(){})(imageResources);
- callback = null;
- };
-
- for (var id in images) {
- var img = document.createElement('img');
- img.src = images[id];
- (function(img, id) {
- img.onload = function() {
- imageResources[id] = img;
- checkForCompletion_();
- };
- img.onerror = function() {
- imageResources[id] = null;
- checkForCompletion_();
- }
- })(img, id);
- }
- }
-
- /**
- * Loads the first valid image from a FileList (e.g. drag + drop source), as a data URI. This
- * method will throw an alert() in case of errors and call back with null.
- *
- * @param {FileList} fileList The FileList to load.
- * @param {Function} callback The callback to fire once image loading is done (or fails).
- * @return Returns an object containing 'uri' representing the loaded image. There will also be
- * a 'name' field indicating the file name, if one is available.
- */
- function loadImageFromFileList(fileList, callback) {
- fileList = fileList || [];
-
- var file = null;
- for (var i = 0; i < fileList.length; i++) {
- if (fileList[i].type.toLowerCase().match(/^image\/(png|jpeg|jpg)/)) {
- file = fileList[i];
- break;
- }
- }
-
- if (!file) {
- alert('Please use a valid screenshot file (PNG or JPEG format).');
- callback(null);
- return;
- }
-
- var fileReader = new FileReader();
-
- // Closure to capture the file information.
- fileReader.onload = function(e) {
- callback({
- uri: e.target.result,
- name: file.name
- });
- };
- fileReader.onerror = function(e) {
- switch(e.target.error.code) {
- case e.target.error.NOT_FOUND_ERR:
- alert('File not found.');
- break;
- case e.target.error.NOT_READABLE_ERR:
- alert('File is not readable.');
- break;
- case e.target.error.ABORT_ERR:
- break; // noop
- default:
- alert('An error occurred reading this file.');
- }
- callback(null);
- };
- fileReader.onabort = function(e) {
- alert('File read cancelled.');
- callback(null);
- };
-
- fileReader.readAsDataURL(file);
- }
-
- /**
- * Adds a simple version of Canvas.toBlob if toBlob isn't available.
- */
- function polyfillCanvasToBlob() {
- if (!HTMLCanvasElement.prototype.toBlob && window.Blob) {
- HTMLCanvasElement.prototype.toBlob = function(callback, mimeType, quality) {
- if (typeof callback != 'function') {
- throw new TypeError('Function expected');
- }
- var dataURL = this.toDataURL(mimeType, quality);
- mimeType = dataURL.split(';')[0].split(':')[1];
- var bs = window.atob(dataURL.split(',')[1]);
- if (dataURL == 'data:,' || !bs.length) {
- callback(null);
- return;
- }
- for (var ui8arr = new Uint8Array(bs.length), i = 0; i < bs.length; ++i) {
- ui8arr[i] = bs.charCodeAt(i);
- }
- callback(new Blob([ui8arr.buffer /* req'd for Safari */ || ui8arr], {type: mimeType}));
- };
- }
- }
-</script>
diff --git a/docs/html/distribute/stories/games.jd b/docs/html/distribute/stories/games.jd
new file mode 100644
index 0000000..1a482b1
--- /dev/null
+++ b/docs/html/distribute/stories/games.jd
@@ -0,0 +1,246 @@
+page.title=Developer Stories: Google Play Game Services
+meta.tags="google play, developer story, games, global"
+page.image=/images/distribute/glu-ew-gpgames.jpg
+page.metaDescription=How gaming studios are using Google Play game services to deliver new gaming experiences for their users.
+
+@jd:body
+
+<p>One of the goals of <a href="https://developers.google.com/games/">Google
+Play game services</a> is to allow developers to focus on what they’re good at
+as game developers — creating great gaming experiences for their users, by
+building on top of what Google is good at: mobile and cloud services. Integral
+to that is an easy integration process, one that provides a whole host of
+features with little engineering work required.</p>
+
+<p>The gaming studios below understood the opportunity that Google Play game
+services unlocked, and are starting to see real results following their
+successful integrations. </p>
+
+<div style="margin-bottom:2em;"><!-- START STORY -->
+
+<h3>Concrete Software — Straightforward, easy to implement</h3>
+
+<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 12px 20px 9px 20px;"
+ src="http://lh6.ggpht.com/_UOay5HBxf077suKYzmikU2IbnYOJub3X0inz-LoUsVh4TX758BEyArjoR7owXijkAA=w124">
+
+<div style="list-style: none;height:100%;
+ float: right;
+ border-top: 1px solid #9C0;
+ width: 220px;
+ margin: 4px 20px;padding: .5em;">
+
+ <h5>About the developer</h5>
+ <ul>
+ <li><a href="https://play.google.com/store/apps/developer?id=Concrete%20Software%2C%20Inc.">Concrete Software</a>,
+ makers of <a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket&hl=en">PBA
+ Bowling Challenge</a></li>
+ <li>Added support for multiplayer, leaderboards and achievements through Google Play game
+ services</li>
+ </ul>
+
+ <h5>Results</h5>
+ <ul>
+ <li>Session lengths have increased more than 15%</li>
+ </ul>
+
+ <div style="padding:.5em 0 0 1em;">
+ <a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket&hl=en">
+ <img alt="Android app on Google Play" src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+ </a>
+ </div>
+</div>
+
+<div style="line-height:1.4em;">
+<p style="margin-top:0;margin-bottom:12px;">Concrete Software added several
+features from Google Play game services into one of their top titles,
+<a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket">PBA
+Bowling Challenge</a>, including support for multiplayer, leaderboards, and
+achievements.</p>
+
+<p>So far, their users have loved the new additions: average session length
+is up more than 15%. Keith Pichelman, CEO of Concrete Software, explains: </p>
+
+<p>"The Google Play game services were straightforward and easy to implement. We
+had been researching options for multiplayer services, so when Google Play game
+services came out, it was an easy decision for us. Not only were they easy to
+integrate, but the features have worked flawlessly. </p>
+
+<p>"PBA Bowling Challenge now has real-time multiplayer which our users instantly
+were thrilled with; you can see in the reviews how people immediately raved about
+the new game experience. </p>
+
+<p>"We also included achievements, leaderboards, and most recently cloud
+synchronization from the Google Play game services as well. Using the game
+services in PBA Bowling Challenge was a huge success, enough so that we are now
+going back to our other titles, adding the features to them as well."</p>
+</div>
+
+<div style="clear:both;margin-top:40px;width:auto;">
+
+ <img src="{@docRoot}images/distribute/concrete-pbc-gpgames.jpg">
+
+ <div style="width:600px;margin-top:0px;padding:0 90px;">
+ <p class="image-caption"><span style="font-weight:500;">Session lengths up:</span>
+ After adding support for multiplayer with Google Play game services, Concrete
+ Software saw an increase in session lengths of more than 15% for PBA Bowling
+ Challenge.</p>
+ </div>
+</div>
+</div> <!-- END STORY -->
+
+<div style="margin:3em auto"><!-- START STORY -->
+
+<h3>Glu: It’s a must-have for all titles</h3>
+
+<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 12px 20px 30px 20px;"
+ src="http://lh4.ggpht.com/Q7mQJsdhulW4_s039R9aaRhQkGnyzLkhF00j5EnyhHOivijnyi7P7b5A8qG0xk1r-jQ=w124">
+
+<div style="list-style: none;height:100%;
+ float: right;
+ border-top: 1px solid #9C0;
+ width: 220px;
+ margin: 4px 20px;padding: .5em;">
+
+ <h5>About the developer</h5>
+ <ul>
+ <li><a href="https://play.google.com/store/apps/developer?id=Glu+Mobile">Glu
+ Mobile</a>, creators of <a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">Eternity
+ Warriors 2</a></li>
+ <li>Has already integrated 5 titles with Google Play game services</li>
+ </ul>
+
+ <h5>Results</h5>
+ <ul>
+ <li>In Eternity Warriors 2, 7-day user retention is up 40%</li>
+ <li>20% increase in play sessions per day as well</li>
+ </ul>
+
+ <div style="padding:.5em 0 0 1em;">
+ <a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">
+ <img alt="Android app on Google Play" src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+ </a>
+ </div>
+</div>
+
+<div style="line-height:1.4em;">
+<p style="margin-top:0;margin-bottom:12px;">Glu was one of the first developers
+to integrate Google Play game services, with
+<a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">Eternity
+Warriors 2</a>. Based on this first success, Glu has integrated game services
+into several more games, including Samurai vs. Zombies 2, Frontline Commando:
+D-Day, Contract Killer 2, and Zombies Ate My Friends.</p>
+
+<p>Already supported in Eternity Warriors 2, they’ve seen a 40% increase in 7-day
+user retention and a 20% increase in play sessions per day. Sourabh Ahuja, Glu's
+Vice President of Android Development, explains:</p>
+
+<p>“Multiplayer, leaderboards, achievements — these are all things that we
+had to build individually for our titles. The availability of these features in
+Google Play game services helps us make our games stickier, and it’s awesome that
+it comes directly from Google. </p>
+
+<p>"It’s flexible enough that we were able to make it interoperable with our
+in-house systems. We look forward to utilizing game services extensively across
+our portfolio."</p>
+</div>
+
+<div style="clear:both;margin-top:40px;width:auto;">
+
+ <img src="{@docRoot}images/distribute/glu-ew-gpgames.jpg"></a>
+
+ <div style="width:600px;margin-top:0px;padding:0 90px;">
+ <p class="image-caption"><span style="font-weight:500;">User retention up:</span>
+ Glu saw a 40% increase in 7-day user retention for Eternity Warriors 2 after
+ integrating with Google Play game services.</p>
+ </div>
+</div>
+</div> <!-- END STORY -->
+
+
+<div style="margin-bottom:2em;"><!-- START STORY -->
+
+<h3>Vector-Unit: An awesome multiplayer experience</h3>
+
+<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 12px 20px 9px 20px;" src=
+ "http://lh3.ggpht.com/dTUrKLffqXHJtPuIlp8fjDhROuzrTcpidbNFprugR65hMrPLX7Omd8SGop0xMXXKzcw=w124">
+
+<div style="list-style: none;height:100%;
+ float: right;
+ border-top: 1px solid #9C0;
+ width: 220px;
+ margin: 4px 20px;padding: .5em;">
+
+ <h5>About the developer</h5>
+ <ul>
+ <li><a href="https://play.google.com/store/apps/developer?id=Vector+Unit">Vector
+ Unit</a>, creators of <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">Riptide
+ GP2</a></li>
+ <li>Added multiplayer to Riptide GP2 through Google Play game services </li>
+ </ul>
+
+ <h5>Results</h5>
+ <ul>
+ <li>With an easy multiplayer solution, they were able to focus on the
+ gameplay</li>
+ <li>Early reviews of Riptide GP2 called multiplayer “one of the sweetest
+ cherries on top!”</li>
+ </ul>
+
+ <div style="padding:.5em 0 0 1em;">
+ <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">
+ <img alt="Android app on Google Play" src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+ </a>
+ </div>
+</div>
+
+<div style="line-height:1.4em;">
+<p style="margin-top:0;margin-bottom:12px;">Vector Unit just launched their
+latest title, <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">Riptide
+GP2</a>, with Google Play game services integration, and it has one of the strongest
+integrations of multiplayer yet. Early reviews call multiplayer “one of the sweetest
+cherries on top!”.</p>
+
+<p>Ralf Knoesel, CTO of Vector Unit, tells more about how they've used Google Play game
+services:</p>
+
+<p>“We wanted to provide a really compelling multiplayer experience for our users, and
+Google Play game services allowed us to do just that. With multiplayer, you can show off
+your skills and your custom-tuned hydro jet in 4-way online battles with friends and
+players around the world. </p>
+
+<p>"By providing an easy way to power this multiplayer experience, we were able to focus
+on making the gameplay come alive — like the stunts, which are more daring and
+slicker than ever (with more of them to master), or the realistic detail of the water
+splashing against the camera lens.”</p>
+
+</div>
+
+<div style="clear:both;margin-top:40px;width:auto;">
+
+ <img src="{@docRoot}images/distribute/vector-unit-rt-gpgames.jpg"></a>
+
+ <div style="width:600px;margin-top:0px;padding:0 90px;">
+ <p class="image-caption"><span style="font-weight:500;">Multiplayer and more:</span>
+ Google Play game services helped Vector Unit pack an awesome multiplayer experience
+ into Riptide GP 2, so they could focus on building a great gaming experience.</p>
+ </div>
+</div>
+</div> <!-- END STORY -->
+
+
+
diff --git a/docs/html/distribute/stories/index.jd b/docs/html/distribute/stories/index.jd
new file mode 100644
index 0000000..ca7647d
--- /dev/null
+++ b/docs/html/distribute/stories/index.jd
@@ -0,0 +1,13 @@
+page.title=Developer Stories
+section.landing=true
+page.metaDescription=Android developers, their apps, and their successes with Android and Google Play.
+
+@jd:body
+
+<p>Android developers, their apps, and their successes with Android and Google Play.</p>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="type:youtube+tag:developerstory"
+ data-sortOrder="-timestamp"
+ data-cardSizes="18x12"
+ data-maxResults="32"></div>
diff --git a/docs/html/distribute/stories/localization.jd b/docs/html/distribute/stories/localization.jd
new file mode 100644
index 0000000..d6e6ccf
--- /dev/null
+++ b/docs/html/distribute/stories/localization.jd
@@ -0,0 +1,330 @@
+page.title=Developer Stories: Localization in Google Play
+meta.tags="google play, developer story, localization, global"
+page.tags="stories", "video", "case study"
+page.image=/images/distribute/zombie-ragdoll-n5-land.jpg
+page.metaDescription=Hear from Android developers who have successfully used the Google Play App Translation Service.
+
+@jd:body
+
+<p>
+ As you build your app and distribute it across the world through Google Play,
+ localization becomes an increasingly important tool to reach more users.
+ Localization involves a <a href=
+ "{@docRoot}distribute/googleplay/publish/localizing.html">variety of tasks</a>, but
+ most important is creating quality translations of your app's UI strings and
+ marketing materials.
+</p>
+
+<p>
+ Managing the translation process across multiple languages can be a
+ challenge, especially if you need to locate translators on your own. That’s
+ why Google Play offers the App Translation Service right from the Developer
+ Console. It's a single place where you can go to source professional
+ translators, get cost estimates, and then send your strings and other
+ materials for translation.
+</p>
+
+<p>
+ Here are some stories from developers who have used Google Play's App Translation
+ Service to localize their apps and the results they've seen as they've
+ expand their offerings beyond a single language.
+</p>
+
+<!-- START STORY -->
+
+<div style="margin-bottom:2em;padding-top:10px;" id="zombieragdoll">
+
+<h3 style="line-height:1.25em">Zombie Ragdoll: Improved user engagement<br /> with localized versions</h3>
+
+ <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 12px 20px 9px 20px;" src=
+ "https://lh4.ggpht.com/m-Ew8c8C_nGctbP6PSPGOaVNnGFryReOE2yHXJ9Z6Prk1nsDyx5w5TmWfg-P5N3HypA=w124">
+
+ <div style="list-style: none;height:100%;
+ float: right;
+ border-top: 1px solid #9C0;
+ width: 220px;
+ margin: 4px 20px;padding: .5em;">
+
+ <h5>About the app</h5>
+
+ <ul>
+ <li><a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">Zombie Ragdoll</a></li>
+ <li>A fun zombie-based physics game</li>
+ </ul>
+
+ <h5>Localization Results</h5>
+
+ <ul>
+ <li>Increased engagement because of appeal of the localized version</li>
+ <li>80% of installs came from users of non-English languages</li>
+ </ul>
+
+ <div style="padding:.5em 0 0 1em;">
+ <a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">
+ <img alt="Android app on Google Play"
+ src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+ </a>
+
+ </div>
+ </div>
+
+ <div style="line-height:1.4em;">
+
+<p>
+ The 2013 Google I/O talks about <a href=
+ "https://developers.google.com/events/io/sessions/326345917">Building Android
+ Apps for a Global Audience</a> and <a href=
+ "https://developers.google.com/events/io/sessions/326455375">What’s New for
+ Developers in Google Play</a> inspired developers at RV AppStudios to go global
+ from very beginning for their new game, Zombie Ragdoll. They launched Zombie
+ Ragdoll in August 2013, localized into 20 languages.
+</p>
+
+<p>
+ They quickly saw the impact of their decision to ship simultaneously in
+ multiple languages through increased non-English installs and improved
+ engagement with users worldwide. In addition, they started getting
+ significant usage in countries where their apps had not been as popular
+ before. They are seeing great traction in countries like Vietnam, Russia,
+ Philippines and Thailand.
+</p>
+
+<p>
+ Vivek Dave, founder of RV AppStudios, credits the success of Zombie Ragdoll
+ to localization:
+</p>
+
+<p>
+ "The value of localization is clear, it helps discoverability and helps
+ connect with the users in other countries. So when the localization
+ opportunity arose, we immediately jumped on it. Android is worldwide, and we
+ would be severely limiting ourselves if we focused on English as the only
+ language.
+</p>
+
+<p>
+ "The App Translation Service offered in the Google Play Developer Console is
+ extremely easy to use and the pricing is very attractive. Developers with
+ limited localization experience can easily create, upload, and translate
+ their app."
+</p>
+
+
+<p>
+ RV AppStudios not only localizes the text within the game, but also localizes
+ the game assets to a specific country/culture. Dave says, “Users want a
+ personalized experience, and by offering a localized game with translation of
+ text and graphic assets, we believe users will connect at a much deeper level
+ with the game.”
+</p>
+
+
+ <div style="margin-top:8px;float:left;margin-right:24px;">
+ <img src="{@docRoot}images/distribute/zombie-ragdoll-n5-land.jpg" style="width:470px;">
+ </div>
+
+
+ <div style="margin-top:128px;">
+ <p class="img-caption"><strong>Hindi version of Zombie Ragdoll</strong>:
+ Localized screenshots and videos in the app's Google Play listing go a
+ long way toward increasing the number of installs.</p>
+ </div>
+
+ </div>
+
+</div> <!-- END STORY -->
+
+<!-- START STORY -->
+
+<div style="margin-bottom:2em;padding-top:18px;clear:both;" id="sayhichat">
+
+<h3>SayHi Chat: Install growth and user engagement<br />
+ from professional translations</h3>
+
+ <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 12px 20px 9px 20px;" src=
+ "https://lh5.ggpht.com/qiL6CF1Hktz618T3mbGrxvm_OoeheQ78FgG7zr90C2MCRiz4IDQsbKuHT4xQGiWEU8o=w124">
+
+ <div style="list-style: none;height:100%;
+ float: right;
+ border-top: 1px solid #9C0;
+ width: 220px;
+ margin: 4px 20px;padding: .5em;">
+
+ <h5>About the app</h5>
+
+ <ul>
+ <li><a href="https://play.google.com/store/apps/details?id=com.unearby.sayhi">SayHi Chat,
+ Love, Meet, Dating</a></li>
+ <li>A social app to help you find people nearby</li>
+ </ul>
+
+ <h5>Localization Results</h5>
+
+ <ul>
+ <li>120% growth in language installs for new languages added</li>
+ <li>~20% increase in revenue and ~50% increase in User Reviews in the new
+ languages</li>
+ </ul>
+
+ <div style="padding:.5em 0 0 1em;">
+ <a href="https://play.google.com/store/apps/details?id=com.unearby.sayhi">
+ <img alt="Android app on Google Play"
+ src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+ </a>
+
+ </div>
+ </div>
+
+ <div style="line-height:1.4em;">
+
+<p>
+ The SayHi Chat app started out only in Japanese, Chinese and English. It soon
+ became one of the most popular apps in Japan, Hong Kong, and Taiwan. The
+ SayHi team realized it was time to launch in more languages, as the language
+ barrier was restricting how fast SayHi could grow globally. </p>
+
+ <p>Yan Shi, senior
+ developer at SayHi, says: "We checked Google Analytics for our DAU and user
+ growth numbers in each country, we also looked at total Android and iOS users
+ in those markets before finalizing our next set of languages.
+</p>
+
+ <div style="margin-top:8px;float:left;width:270px;">
+ <img src="{@docRoot}images/distribute/hichat-n5-port.jpg" style="width:240px;margin-right:48px;">
+ </div>
+
+<p>
+ SayHi used the App Translation Service to launch in 13 additional languages
+ in August 2013 and immediately saw 120% increase in install rates. In
+ addition, they are seeing their app ranked in Top 10 apps in countries like
+ Poland and Italy.
+</p>
+
+<p>Notably, they saw steady growth in Spain after replacing their previous
+ non-professional Spanish translation with a professional one produced through
+ the App Translation Service.</p>
+
+<p>
+ Yan Shi adds, “The App Translation Service is really easy to use and
+ the completion time for translation requests is very good.”
+</p>
+
+ <div style="width:600px;margin-top:98px;padding:0;">
+ <p class="img-caption"><strong>Arabic version of SayHi Chat</strong>:
+ User engagement increased significantly with
+ the localized version.</p>
+ </div>
+
+ </div>
+</div> <!-- END STORY -->
+
+
+<div style="margin-bottom:2em;clear:both;padding-top:18px;" id="g4a"><!-- START STORY -->
+
+<h3 style="line-spacing:1.25em;">G4A Indian Rummy: Benefitting from ease-of-use and<br /> fast turnaround time</h3>
+
+ <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 12px 20px 9px 20px;" src=
+ "https://lh4.ggpht.com/IxSyQgO0LWzPRoLfCrER06-0kr6aMAa2azF7eNYB30EBZAGOLYJUZulknPockbTlDYU=w124">
+
+ <div style="list-style: none;height:100%;
+ float: right;
+ border-top: 1px solid #9C0;
+ width: 220px;
+ margin: 4px 20px;padding: .5em;">
+
+ <h5>About the app</h5>
+
+ <ul>
+ <li><a href="https://play.google.com/store/apps/details?id=org.games4all.android.games.indianrummy.prod">G4A Indian Rummy</a></li>
+ <li>A card game in which the players try to form sets and sequences of cards</li>
+ </ul>
+
+ <h5>Localization Results</h5>
+
+ <ul>
+ <li>Double the number of users in French and German languages</li>
+ <li>300% increase in user engagement with localized version</li>
+ </ul>
+
+ <div style="padding:.5em 0 0 1em;">
+ <a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">
+ <img alt="Android app on Google Play"
+ src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+ </a>
+ </div>
+ </div>
+
+ <div style="line-height:1.4em;">
+
+<p>
+ Games4All (G4A) is the developer of Indian Rummy and a variety of games that
+ they distribute broadly to users around the world. After noticing that
+ certain apps had become especially popular in specific countries, they
+ decided to localize those apps. Initially they used a local agency to do
+ the translation and got great results — the number of users in
+ that language increased tremendously when they released the localized
+ version.
+</p>
+
+<p>
+ Building on that success, G4A expanded their localization goals but
+ found that translation quality varied across their vendors and costs limited the
+ language/game combinations they could try. That's when G4A decided to try the
+ App Translation Service.
+</p>
+
+<p>
+ Founder Pieter Olivier says, "When we heard that the App Translation
+ Service was available in the Developer Console, we jumped at the opportunity.
+ We've now been using the App Translation Service for several months and found
+ that the cost per translation is much lower than with local companies and the
+ process is much easier."
+</p>
+
+<p>So far, G4A has translated the game Indian Rummy into five languages through
+ the App Translation Service.</p>
+
+<p>
+ Olivier continues, "The first thing we did was convert all of our texts into
+ the strings.xml format. After that using the service was extremely easy and
+ straightforward. In contrast, our previous experiences with translation
+ agencies were much more difficult: files often required extensive conversion
+ operations to make them usable, and turnaround times varied wildly.
+</p>
+
+<p>
+ "With the App Translation Service, the turnaround time is usually measured in
+ days instead of weeks that we were used to with traditional translation
+ agencies."
+</p>
+
+ <div style="margin-top:14px;float:left;margin-right:24px;">
+ <img src="{@docRoot}images/distribute/indian-rummy-n4-land.jpg" style="width:470px;">
+ </div>
+
+ <div style="margin-top:158px;">
+ <p class="img-caption"><strong>Dutch
+ version of Indian Rummy</strong>: Making slight changes to games rules based on
+ local nuances was key to success of the game.</p>
+ </div>
+
+ </div>
+
+
+
+</div> <!-- END STORY -->
\ No newline at end of file
diff --git a/docs/html/distribute/stories/stories_toc.cs b/docs/html/distribute/stories/stories_toc.cs
new file mode 100644
index 0000000..944dabe
--- /dev/null
+++ b/docs/html/distribute/stories/stories_toc.cs
@@ -0,0 +1,34 @@
+<ul id="nav">
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/stories/index.html">
+ <span class="en">Videos</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/stories/localization.html">
+ <span class="en">Going Global</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/stories/games.html">
+ <span class="en">Games</span>
+ </a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/stories/tablets.html">
+ <span class="en">Tablets</span>
+ </a>
+ </div>
+ </li>
+
+</ul>
+
+
+<script type="text/javascript">
+<!--
+ buildToggleLists();
+ changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html/distribute/stories/tablets.jd b/docs/html/distribute/stories/tablets.jd
new file mode 100644
index 0000000..771fa52
--- /dev/null
+++ b/docs/html/distribute/stories/tablets.jd
@@ -0,0 +1,368 @@
+page.title=Developer Stories: The Opportunity of Android Tablets
+meta.tags="google play, developer story, journal, tablets, pure"
+pdage.metaDescription=Developers are investing in a full tablet experience for their apps and seeing those investments pay off big.
+page.image=/images/distribute/rememberthemilk.png
+
+@jd:body
+
+
+<p>"More" and more, developers are investing in a full tablet experience
+for their apps and are seeing those investments pay off big. The increased
+screen area on tablets opens up a world of possibilities, allowing for more
+engagement with the user — which can mean an increase in usage as well as
+more monetization opportunities. And with the growing wave of Android tablets that
+continue to hit the market, it’s an important piece of any developer’s mobile
+offering. </p>
+
+<p>Here are some stories from developers who are seeing real results as they
+expand their offering to include Android tablets.</p>
+
+
+<div style="margin-bottom:2em;" id="rememberthemilk"><!-- START STORY -->
+
+<h3>Remember The Milk: Lifting installs with tablet design</h3>
+
+ <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 12px 20px 9px 20px;" src=
+ "http://lh3.ggpht.com/xmnal18taauP2mjQFEhr1PhcItQ_W32IRuaD86IoL2U_4E-mfeKiliKtkISgOuA6Ln9n=w124">
+
+ <div style="list-style: none;height:100%;
+ float: right;
+ border-top: 1px solid #9C0;
+ width: 220px;
+ margin: 4px 20px;padding: .5em;">
+
+
+ <h5>About the app</h5>
+
+
+ <ul>
+ <li><a href="http://play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">Remember The Milk</a></li>
+ <li>A feature-packed to-do list app; never forget the milk (or anything else) again</li>
+ </ul>
+
+ <h5>Tablet Results</h5>
+
+ <ul>
+ <li>83% jump in tablet installs following update </li>
+ <li>Nexus 7 is most popular Android device for app </li>
+ <li>Single APK for phones and tablets</li>
+ </ul>
+
+ <div style="padding:.5em 0 0 1em;">
+ <a href="http://play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">
+ <img alt="Android app on Google Play"
+ src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+ </a>
+
+ </div>
+ </div>
+
+ <div style="line-height:1.4em;">
+ <p style="margin-top:0;margin-bottom:12px;">When the Android tablet guidelines
+ came out in 2012, the team at Remember The Milk had already been thinking about
+ a redesign for their <a href="http://play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">feature-packed
+ to-do list app</a>. Omar Kilani, Co-founder of Remember The Milk, explains how
+ <a href="http://blog.rememberthemilk.com/2013/04/the-all-new-remember-the-milk-for-android-and-tablets-too/">updating</a>
+ their app to meet the tablet guidelines lead to an 83% jump in tablet installs: </p>
+
+ <p>“We took this as an opportunity to think about how we were going to approach
+ Android tablets differently from a user experience perspective. The guidelines
+ were a helpful resource, and with the extra screen real estate tablets afford,
+ users have the opportunity to see all of their data in context and drill down
+ on more items. All of this is accomplished using a single APK on Play, even though
+ the phone and tablet versions each capture completely different use cases for us.”</p>
+
+ <p>“In the month after updating, we saw our tablet installs on Google Play jump 83%,
+ and the Nexus 7 is now the most popular Android device amongst our users. For us,
+ designing for tablets was an investment that has really paid off.”</p>
+
+ <p>The team also came out with a number of other goodies — including a new set of
+ widgets and richer notifications, and more ways to provide an immersive experience
+ for their users.</p>
+ </div>
+
+ <div style="clear:both;margin-top:30px;width:auto;">
+
+ <img src="{@docRoot}images/distribute/rememberthemilk.png">
+
+ <div style="width:600px;margin-top:0px;padding:0 90px;">
+ <p class="image-caption"><span style="font-weight:500;">Tablet redesign led to lift
+ in installs</span>: Following the redesign of the Android app, in part to meet the tablet
+ design criteria, Remember The Milk saw an 83% increase in tablet installs.</p>
+ </div>
+
+ </div>
+
+</div> <!-- END STORY -->
+
+
+<div style="margin-bottom:2em;" id="mint"><!-- START STORY -->
+
+<h3>Mint: More screen real estate = more engagement</h3>
+
+ <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 12px 20px 9px 20px;" src=
+ "https://lh5.ggpht.com/0xAIZJ1uE05b4RHNHgBBTIH6nRdPTY660T104xY7O2GbHXwab6YVmpU5yYg8yacfBg=w124">
+
+ <div style="list-style: none;height:100%;
+ float: right;
+ border-top: 1px solid #9C0;
+ width: 220px;
+ margin: 4px 20px;padding: .5em;">
+
+
+ <h5>About the app</h5>
+
+
+ <ul>
+ <li><a href="http://play.google.com/store/apps/details?id=com.mint">Mint.com Personal Finance</a> by Intuit Inc.</li>
+ <li>Financial management app targeting 7- to 10-inch tablets and phones</li>
+ </ul>
+
+ <h5>Tablet Results</h5>
+
+ <ul>
+ <li>Able to offer richer UI features</li>
+ <li>Much higher user engagement</li>
+ <li>Longer sessions — more Android tablet users have sessions longer than 5 minutes</li>
+ </ul>
+
+ <div style="padding:.5em 0 0 1em;">
+<a href="http://play.google.com/store/apps/details?id=com.mint">
+ <img alt="Android app on Google Play"
+ src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+</a>
+
+ </div>
+ </div>
+
+ <div style="line-height:1.4em;">
+ <p style="margin-top:0;margin-bottom:12px;">When Intuit was thinking about
+expanding their Mint mobile offering to include a version optimized for Android
+tablets, they knew that taking the layout that worked for phones and simply
+showing an enlarged version wouldn’t take full advantage of the opportunities
+that tablets afford.</p>
+
+ <p>“We knew we had a lot more real estate, and we wanted to provide a more
+immersive experience for our users” said Ken Sun, Intuit Group Product Manager
+at Mint.</p>
+
+<p>Intuit’s Mint app, which has a 4-star rating on Google Play, brings a number
+of features to Android tablets that aren’t available for phones, including a
+more visual presentation of personal financial data.</p>
+
+<p>“Whereas our app for phones is used throughout the day for quick sessions,
+we’ve seen a larger percentage of our tablet usage happen in the evening, for
+much longer sessions,” said Sun. “People are doing a lot more than just checking
+their spending. They’re looking at historical trends, re-categorizing
+transactions, analyzing the data and setting financial goals for the future
+— digging much deeper and being more thoughtful. One example is how much
+users are interacting with their own budgets in the tablet app. Customer budget
+operations (view, edit, drill-down, etc.) are 7x higher on Android tablets than
+they are on phones.”</p>
+
+<p>Fifty percent more Android tablet users have Mint sessions of 5 minutes or
+longer than they do on phones. “We’ve found that phone usage is indicative of a
+customer’s regular financial check-in, while tablet usage points towards more
+analysis and interaction with that customer’s personal financial data. This is
+the sort of immersive engagement experience we were looking for; the tablet and
+phone apps serve as great complements to each other."</p>
+ </div>
+
+ <div style="clear:both;margin-top:40px;width:auto;">
+
+ <img src="{@docRoot}images/distribute/mint.png">
+
+ <div style="width:600px;margin-top:0px;padding:0 90px;">
+ <p class="image-caption"><span style="font-weight:500;">Making the most of tablet screens</span>: Mint used the extra screen area on tablets to offer quick access to additional tools and information.</p>
+ </div>
+
+ </div>
+
+</div> <!-- END STORY -->
+
+
+<div style="margin:3em auto"><!-- START STORY -->
+
+
+<h3>TinyCo: Monetization opportunities abound on tablets</h3>
+
+ <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 12px 20px 30px 20px;" src=
+ "https://lh6.ggpht.com/QTy7lOGRTS58NW4XEeym2sxpWKDmRNod_n3kBrHlqTRIyzIv2gkw8DfwiR4GIAdxiHw=w124">
+
+
+ <div style="list-style: none;height:100%;
+ float: right;
+ border-top: 1px solid #9C0;
+ width: 220px;
+ margin: 4px 20px;padding: .5em;">
+
+ <h5>About the app</h5>
+
+ <ul>
+ <li><a href="http://play.google.com/store/apps/details?id=com.tinyco.village">Tiny Village</a> by TinyCo</li>
+ <li>Game targeting 7- to 10-inch tablets and phones</li>
+ </ul>
+
+ <h5>Tablet Results</h5>
+
+ <ul>
+ <li>35% higher average revenue per paying user (ARPPU)</li>
+ <li>Consistent increase in user retention</li>
+ <li>3x increase in downloads to Android tablets in the last 6 months</li>
+ </ul>
+
+ <div style="padding:.5em 0 0 1em;">
+<a href="http://play.google.com/store/apps/details?id=com.tinyco.village">
+ <img alt="Android app on Google Play"
+ src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+</a>
+
+ </div>
+ </div>
+
+ <div style="line-height:1.4em;">
+ <p style="margin-top:0;margin-bottom:12px;">
+
+<p>Over a year ago, app developer TinyCo, makers of a suite of games such as
+Tiny Monsters, decided to prioritize launching across multiple platforms
+effectively. They chose Android as one of their primary launch platforms because
+of its large installed base and global reach. They also knew that the growing
+base of Android tablet users represented a huge opportunity.</p>
+
+ <p>Tiny Village was their first title to take advantage of the strategy, and
+it proved to be a winning one — especially in terms of Android
+tablets.</p>
+
+ <p> “With continued optimization of the gameplay experience and a genuine
+commitment to our Android offering through our Griffin engine, all of our
+metrics started to rise,” said Rajeev Nagpal, Head of Product at TinyCo. In
+fact, they’ve seen Android tablet downloads more than triple in the last six
+months.</p>
+
+ <p>One of the first things they noticed about usage of Tiny Village on
+tablets was an increase in average revenue per paying user (ARPPU)—about 35%
+higher than on smaller-screen devices such as phones. Additionally, average
+revenue per user ARPU is now about 35% higher as well. “The game is just much
+more immersive on tablet.”</p>
+
+ <p>In addition to an increase in monetization metrics, they’ve also seen a
+consistent increase in retention over other platforms. “These are really
+important metrics for games — if you can get users to both stay around
+longer and spend more while they’re there, you have a recipe for success.”</p>
+ </div>
+
+ <div style="clear:both;margin-top:40px;width:auto;">
+
+ <img src="{@docRoot}images/distribute/tinyvillage.png">
+
+ <div style="width:600px;margin-top:0px;padding:0 90px;">
+ <p class="image-caption"><span style="font-weight:500;">More monetization
+on tablets</span>: On Android tablets TinyCo has seen higher ARPPU and user
+retention than on phones.</p>
+ </div>
+
+ </div>
+
+</div> <!-- END STORY -->
+
+
+<div style="margin-bottom:2em;"><!-- START STORY -->
+
+<h3>Instapaper: Riding the growing wave of Android tablets</h3>
+
+
+ <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px height:78px;
+ width: 78px;
+ float: left;
+ margin: 12px 20px 9px 20px;" src=
+ "https://lh3.ggpht.com/30KKcrIFO8V_wRfhnHaI9l0CLH_orIVFE7Xywtr9TBxAf0hi2BaZkKyBOs63Yfavpg=w124">
+
+
+ <div style="list-style: none;height:100%;
+ float: right;
+ border-top: 1px solid #9C0;
+ width: 220px;
+ margin: 4px 20px;padding: .5em;">
+
+
+
+
+ <h5>About the app</h5>
+ <ul>
+ <li><a href="http://play.google.com/store/apps/details?id=com.instapaper.android">Instapaper</a> by Mobelux</li>
+ <li>Content-browsing utility that targets 7- to 10-inch tablets and phones</li>
+ </ul>
+
+ <h5>Tablet Results</h5>
+
+ <ul>
+ <li>Tablets are now 50% of the app's installed base.</li>
+ </ul>
+
+ <div style="padding:.5em 0 0 1em;">
+<a href="http://play.google.com/store/apps/details?id=com.instapaper.android">
+ <img alt="Android app on Google Play"
+ src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
+</a>
+
+ </div>
+ </div>
+
+ <div style="line-height:1.4em;">
+ <p style="margin-top:0;margin-bottom:12px;">Instapaper for Android is an app
+for saving web content to read later. Developer Mobelux decided that creating a
+great UI for Android tablet users would be an essential part of their initial launch
+plan.</p>
+
+ <p>The app launched at the beginning of the summer of 2012, just in time to
+take advantage of a new tide of Android tablets, including the <span
+style="white-space:nowrap;">Nexus 7</span> tablet. The app has since seen huge
+popularity among tablet users, in particular, on Nexus 7. On the day that
+pre-orders of Nexus 7 began arriving, Mobelux saw a 600% jump in downloads of
+its app on Google Play.</p>
+
+ <p>“We saw a promising new set of Android tablets about to hit the market
+and wanted to position ourselves to be ready for them” said Jeff Rock of
+Mobelux. “It was a market that others were hesitant to explore, but the decision
+to prioritize tablets has paid off very well for us.”</p>
+
+ <p>Since that initial 600% jump in downloads, Instapaper for Android has
+continued to see a successful run on Android tablets. In fact, Android tablets
+now represent about 50% of their installed base. “With more and more Android
+tablets coming online, we’re excited to see how our investment in Android
+tablets continues to pay off.”</p>
+ </div>
+
+ <div style="clear:both;margin-top:40px;width:auto;">
+
+ <img src="{@docRoot}images/distribute/instapaper.png">
+
+ <div style="width:600px;margin-top:0px;padding:0 90px;">
+ <p class="image-caption"><span style="font-weight:500;">Popular with
+tablet users</span>: A great tablet UI and browsing convenience make Instapaper
+popular with Android tablet users.</p>
+ </div>
+
+ </div>
+
+</div> <!-- END STORY -->
+
+
+
diff --git a/docs/html/distribute/tools/disttools_toc.cs b/docs/html/distribute/tools/disttools_toc.cs
new file mode 100644
index 0000000..f4f39f0
--- /dev/null
+++ b/docs/html/distribute/tools/disttools_toc.cs
@@ -0,0 +1,46 @@
+<ul id="nav">
+
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/launch-checklist.html">
+ <span class="en">Launch Checklist</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/localization-checklist.html">
+ <span class="en">Localization Checklist</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/promote/device-art.html">
+ <span class="en">Device Art Generator</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/promote/badges.html">
+ <span class="en">Google Play Badges</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/promote/linking.html">
+ <span class="en">Linking to Your Products</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/promote/brand.html">
+ <span class="en">Brand Guidelines</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/open-distribution.html">
+ <span class="en">Alternative Distribution</span></a>
+ </div>
+ </li>
+</ul>
+
+<script type="text/javascript">
+<!--
+ buildToggleLists();
+ changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html/distribute/tools/index.jd b/docs/html/distribute/tools/index.jd
new file mode 100644
index 0000000..c8f0212
--- /dev/null
+++ b/docs/html/distribute/tools/index.jd
@@ -0,0 +1,57 @@
+page.title=Tools & Reference
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+<p>
+ Here you’ll find resources to help you publish your apps and games, acquire
+ users, and monetize your investment.
+</p>
+
+<div class="dynamic-grid">
+
+ <h3>Publishing and Launch</h3>
+ <div class="resource-widget resource-flow-layout landing col-16"
+ data-query="collection:distribute/tools/checklists"
+ data-cardSizes="9x6"
+ data-maxResults="2">
+ </div>
+
+<h3>Marketing Tools</h3>
+ <div class="resource-widget resource-flow-layout landing col-16"
+ data-query="collection:distribute/tools/promote"
+ data-cardSizes="6x6"
+ data-maxResults="3">
+ </div>
+
+ <h3>Developer Support</h3>
+ <div class="resource-widget resource-flow-layout landing col-16"
+ data-query="collection:distribute/tools/support"
+ data-cardSizes="6x6"
+ data-maxResults="3">
+ </div>
+
+ <h3>Developer News</h3>
+ <div class="resource-widget resource-flow-layout landing col-16"
+ data-query="collection:distribute/tools/news"
+ data-cardSizes="9x6"
+ data-maxResults="2">
+ </div>
+
+ <h3>More</h3>
+ <div class="resource-widget resource-flow-layout landing col-16"
+ data-query="collection:distribute/tools/more"
+ data-cardSizes="6x6"
+ data-maxResults="3">
+ </div>
+
+<!-- <h3>Related Resources</h3>
+ <div class="resource-widget resource-stack-layout col-16"
+ data-query="tag:developersupport"
+ data-sortOrder="-timestamp"
+ data-numStacks="3"
+ data-maxResults="6">
+ </div> -->
+
+</div>
diff --git a/docs/html/distribute/tools/launch-checklist.jd b/docs/html/distribute/tools/launch-checklist.jd
new file mode 100644
index 0000000..3b0dd55
--- /dev/null
+++ b/docs/html/distribute/tools/launch-checklist.jd
@@ -0,0 +1,1072 @@
+page.title=Launch Checklist
+page.metaDescription=Essential overview of the complete process of delivering your app to users. Read this checklist early in development to help you plan for a successful launch on Google Play.
+meta.tags="localizing, publishing, disttools"
+page.tags="launch, publishing, Google Play"
+page.image=/distribute/images/launch-checklist.jpg
+
+@jd:body
+
+<div id="qv-wrapper">
+ <div id="qv" style="width:280px">
+ <h2>Checklist</h2>
+ <ol>
+ <li><a href="#understand-publishing">1. Understand the Publishing Process</a></li>
+ <li><a href="#understand-policies">2. Understand Google Play Policies</a></li>
+ <li><a href="#test-quality">3. Test for Core App Quality</a></li>
+ <li><a href="#determine-rating">4. Determine Content Rating</a></li>
+ <li><a href="#determine-country">5. Determine Country Distribution</a></li>
+ <li><a href="#confirm-size">6. Confirm Overall Size</a></li>
+ <li><a href="#confirm-platform">7. Confirm Platform and Screen Ranges</a></li>
+ <li><a href="#decide-price">8. Decide Free or Priced</a></li>
+ <li><a href="#consider-billing">9. Use In-app Billing</a></li>
+ <li><a href="#set-prices">10. Set Prices for your Products</a></li>
+ <li><a href="#start-localization">11. Start Localization</a></li>
+ <li><a href="#prepare-graphics">12. Prepare Promotional Graphics, Screenshots, and Videos</a></li>
+ <li><a href="#build-upload">13. Build the Release-ready APK</a></li>
+ <li><a href="#plan-beta">14. Plan a Beta Release</a></li>
+ <li><a href="#complete-details">15. Complete the Store Listing</a></li>
+ <li><a href="#use-badges">16. Use Google Play Badges and Links</a></li>
+ <li><a href="#final-checks">17. Final Checks and Publishing</a></li>
+ <li><a href="#support-users">18. Support Users after Launch </a></li>
+ </ol>
+ </div>
+</div>
+
+<div class="top-right-float" style="width:194px"><img
+src="{@docRoot}distribute/images/launch-checklist.jpg"></div>
+
+<p>
+ Before you publish your apps on Google Play and distribute them to users, you
+ need to get the apps ready, test them, and prepare your promotional
+ materials.
+</p>
+
+<p>
+ This page helps you understand the publishing process and get ready for a
+ successful product launch on Google Play. It summarizes some of the tasks
+ you'll need to complete before publishing your app on Google Play, such as
+ creating a signed, release-ready application package (APK), understanding the
+ requirements of the app, and creating the product page and graphic assets for
+ each of your apps.
+</p>
+
+<p>
+ The preparation and publishing tasks are numbered to give you a rough idea of
+ sequence. However, you can handle the tasks in any sequence that works for
+ you or you can skip steps as appropriate.
+</p>
+
+<p>
+ As you move toward publishing, a variety of support resources are available
+ to you. Relevant links are provided in each step.
+</p>
+
+<div class="headerLine">
+ <h1 id="understand-publishing">
+ 1. Understand the Publishing Process
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Before you begin the steps in this checklist, you should take a moment to
+ read and understand the overall publishing workflow and become familiar with
+ how the process works. In particular, you or your development team will need
+ to prepare your apps for release using a process common to all Android apps.
+ The <a href="{@docRoot}tools/publishing/publishing_overview.html">Publishing
+ workflow documents</a> provide the details on how publishing works and how to
+ get an APK ready for release.
+</p>
+
+<p>
+ Once you are familiar with publishing in general, continue reading to
+ understand the issues that you should consider when publishing apps on Google
+ Play.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/understanding"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="understand-policies">
+ 2. Understand Google Play Policies and Agreements
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Make sure that you understand and follow the Google Play program policies
+ that you accepted when registering. Google Play actively enforces the
+ policies and any violations can lead to suspension of your apps or, for
+ repeated violations, termination of your developer account.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/policies" data-sortorder=
+"-timestamp" data-cardsizes="6x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="test-quality">
+ 3. Test for Quality
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Before you publish apps on Google Play, it's important to make sure that they
+ meet the basic quality expectations for all Android apps, on all of the
+ devices that you are targeting. You can check your app's quality by setting
+ up a test environment and testing the app against a short set of
+ <strong>quality criteria that applies to all apps</strong>. For complete
+ information, see the <a href=
+ "{@docRoot}distribute/essentials/quality/core.html">Core App Quality</a>
+ guidelines.
+</p>
+
+<p>
+ If your app is targeting tablet devices, make sure that it delivers a rich,
+ compelling experience to your tablet customers. See the <a href=
+ "{@docRoot}distribute/essentials/quality/tablets.html">Tablet App Quality</a>
+ guidelines for recommendations on ways to optimize your app for tablets.
+</p>
+
+<p>
+ If you plan to make your apps available to Google Play for Education, then
+ you need to make sure they are suitable for a K-12 classroom and offer
+ outstanding educational value. See the <a href=
+ "{@docRoot}distribute/essentials/gpfe-guidelines.html">Education
+ Guidelines</a> for information on the characteristics your education apps
+ should exhibit.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/quality" data-sortorder=
+"-timestamp" data-cardsizes="6x3,6x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="determine-rating">
+ 4. Determine your App’s Content Rating
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Google Play requires you to set a content rating for your app, which informs
+ Google Play users of its maturity level. Before you publish, you should
+ confirm what rating level you want to use. The available content rating
+ levels are:
+</p>
+
+<ul>
+ <li>
+ <p>
+ Everyone
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Low maturity
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Medium maturity
+ </p>
+ </li>
+
+ <li>
+ <p>
+ High maturity
+ </p>
+ </li>
+</ul>
+
+<p>
+ On their Android devices, Android users can set the desired maturity level
+ for browsing. Google Play then filters apps based on the setting, so the
+ content rating you select can affect the app's distribution to users. You can
+ assign (or change) the content rating for your apps in the Developer Console,
+ no changes are required in your app binary.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/rating" data-sortorder=
+"-timestamp" data-cardsizes="9x3,6x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="determine-country">
+ 5. Determine Country Distribution
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Google Play lets you control what countries and territories your apps are
+ distributed to. For the widest reach and the largest potential customer base,
+ you’d normally want to distribute to all available countries and territories.
+ However, because of business needs, app requirements, or launch dependencies,
+ you might want to exclude one or more countries from your distribution.
+</p>
+
+<p>
+ It's important to determine the exact country distribution early, because it
+ can affect:
+</p>
+
+<ul>
+ <li>
+ <p>
+ The need for localized resources in the app.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ The need for a localized app description in the Developer Console.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Legal requirements for the app that may be specific to certain countries.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Time zone support, local pricing, and so on.
+ </p>
+ </li>
+</ul>
+
+<p>
+ With your target countries in mind, you should assess your localization
+ needs, both in your apps and in their Google Play listings details, and start
+ the work of localization well in advance of your target launch date.
+</p>
+
+<p>
+ See <a href=
+ "{@docRoot}distribute/tools/localization-checklist.html">Localization
+ Checklist</a> for key steps and considerations in the localization process.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/country" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="confirm-size">
+ 6. Confirm the App's Overall Size
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ The overall size of your app can affect its design and how you publish it on
+ Google Play. Currently, the maximum size for an APK published on Google Play
+ is <strong>50 MB</strong>. If your app exceeds that size, or if you want to
+ offer a secondary download, you can use <a href=
+ "{@docRoot}google/play/expansion-files.html">APK Expansion Files</a>, which
+ Google Play will host for free on its server infrastructure and automatically
+ handle the download to devices.
+</p>
+
+<ul>
+ <li>
+ <p>
+ The maximum size for an APK published on Google Play is 50 MB.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ You can use up to two (2) APK Expansion Files, each up to 2GB in size,
+ for each APK.
+ </p>
+ </li>
+</ul>
+
+<p>
+ Using APK Expansion files is a convenient, cost-effective method of
+ distributing large apps. However, the use of APK Expansion Files requires
+ some changes in your app binary, so you will need to make those changes
+ before creating your release-ready APK.
+</p>
+
+<p>
+ To minimize the size of your app binary, make sure that you run the <a href=
+ "{@docRoot}tools/help/proguard.html">Proguard</a> tool or similar obfuscator
+ on your code when building your release-ready APK.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/size" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="confirm-platform">
+ 7. Confirm the App's Platform and Screen Compatibility Ranges
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Before publishing, it's important to make sure that your apps are designed to
+ run properly on the Android platform versions and device screen sizes that
+ you want to target.
+</p>
+
+<p>
+ From an app-compatibility perspective, Android platform versions are defined
+ by <a href=
+ "{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API
+ level</a>. You should confirm the minimum version that your app is compatible
+ with <a href=
+ "{@docRoot}guide/topics/manifest/uses-sdk-element.html"><minSdkVersion></a>,
+ as that will affect its distribution to Android devices once it is published.
+</p>
+
+<p>
+ For screen sizes, you should confirm that the app runs properly and looks
+ good on the range of screen sizes and pixel densities that you want to
+ support. You should follow the advice provided in <a href=
+ "{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+ Screens</a> to provide scalable support for multiple screen sizes. However,
+ if you have been unable to do so, declare the minimum screen-size supported
+ by your apps using <a href=
+ "{@docRoot}guide/topics/manifest/supports-screens-element.html"><supports-screens></a>.
+ Google Play will then restrict the availability of your apps accordingly,
+ making them available to devices with the declared screen size or large.
+</p>
+
+<p>
+ To get a better understanding of the current device penetration of Android
+ platform versions and screen sizes across all Android devices, see the
+ <a href="{@docRoot}about/dashboards/index.html">Device Dashboard</a> charts.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/platform" data-sortorder=
+"-timestamp" data-cardsizes="6x3,6x3,6x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="decide-price">
+ 8. Decide Whether your App will be Free or Priced
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-launch-checklist-1.png">
+</div>
+
+<p>
+ On Google Play, you can publish apps as free to download or priced. Free apps
+ can be downloaded by any Android user in Google Play. Paid apps can be
+ downloaded only by users who are in a country that supports paid downloads
+ and have registered a form of payment in Google Play, such as a credit card
+ or Direct Carrier Billing.
+</p>
+
+<p>
+ Deciding whether you apps will be free or paid is important because, on
+ Google Play, <strong>free apps must remain free</strong>.
+</p>
+
+<ul>
+ <li>
+ <p>
+ Once you publish an app as a free app, you cannot change it to being a
+ priced app. However, you can still sell <a href=
+ "{@docRoot}google/play/billing/billing_overview.html#products">in-app
+ products</a> and <a href=
+ "{@docRoot}google/play/billing/billing_subscriptions.html">subscriptions</a>
+ through Google Play's <a href=
+ "{@docRoot}google/play/billing/index.html">In-app Billing</a> service.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ If you publish your app as a priced app, you <em>can</em> change it at
+ any time to be a free app (<strong>but cannot then change it back to
+ priced</strong>). You can also sell in-app products and subscriptions.
+ </p>
+ </li>
+</ul>
+
+<p>
+ If your app is be priced, or if you'll be selling in-app products, you need
+ <a href=
+ "https://developers.google.com/wallet/digital/training/getting-started/merchant-setup">
+ set up a Google Wallet Merchant Account</a> before you can publish.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/price" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="consider-billing">
+ 9. Consider using In-app Billing
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Google Play <a href="{@docRoot}google/play/billing/index.html">In-app
+ Billing</a> lets you sell digital content in your applications. You can use
+ the service to sell a wide range of content, including downloadable content
+ such as media files or photos, and virtual content such as game levels or
+ potions. In-app Billing service lets you sell one-time purchases and
+ subscriptions from inside your app. This can help you to monetize the app
+ over its installed lifetime.
+</p>
+
+<p>
+ If your are looking for more ways to monetize your app and build engagement,
+ you should consider In-app Billing or Instant Buy. These services have become
+ very popular with both users and developers. To use In-app Billing or Instant
+ Buy, you need to make changes to your app binary, so you will need to
+ complete and test your implementation before creating your release-ready APK.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/purchasemethod"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="set-prices">
+ 10. Set Prices for your Products
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ If your apps is priced or you’ll sell in-app or physical products, Google
+ Play lets you set prices for your products in a variety of currencies, for
+ users in markets around the world. You can set prices individually in
+ different currencies, so you have the flexibility to adjust your price
+ according to market conditions and exchange rates.
+</p>
+
+<p>
+ Before you publish, consider how you’ll price your products and what your
+ prices will be in various currencies. Later, you can set prices in all
+ available currencies through the Developer Console.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/setprice" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,9x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="start-localization">
+ 11. Start Localization
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ With your country targeting in mind, it's a good idea to assess your
+ localization needs, ensure your apps are internationalized, and start the
+ work of localizing well in advance of your target launch date.
+</p>
+
+<p>
+ In addition to your application design, there are at least three aspects of
+ localization to consider:
+</p>
+
+<ul>
+ <li>
+ <p>
+ Localizing the strings, images, and other resources in your apps.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Localizing your apps’ store listing details on Google Play.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Localizing the apps’ graphic assets, screenshots, and videos that
+ accompany your store listing.
+ </p>
+ </li>
+</ul>
+
+<p>
+ See <a href=
+ "{@docRoot}distribute/tools/localization-checklist.html">Localization
+ Checklist</a> for key steps and considerations in the localization process.
+</p>
+
+<p>
+ To localize your store listing, first create and finalize your app title,
+ description, and promotional text. Collect and send all of these for
+ localization. You can optionally translate the "Recent Changes" text for app
+ updates as well. Later you can add your localized listing details in the
+ Developer Console, or you can choose to let Google Play auto-translate your
+ listing details into the languages you support.
+</p>
+
+<p>
+ A key part of making your app listing attractive to a global customer base is
+ creating localized versions of your promotional graphics, screenshots and
+ videos. For example, your app's feature graphic might include text that
+ should be translated, for maximum effectiveness. You can create different
+ versions of your promotional graphics for each language and upload them to
+ the Developer Console. If you offer a promotional video, you can create
+ localized versions of it and then add a link to the correct localized video
+ for each language you support.
+</p>
+
+<p>
+ When your translations are complete, move them into your app resources as
+ needed and test that they are loaded properly. Save your app's translated
+ listing details for later, when you upload assets and configure the store
+ listing.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/localization"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="prepare-graphics">
+ 12. Prepare Promotional Graphics, Screenshots, and Videos
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ When you publish on Google Play, you can supply a variety of high-quality
+ graphic assets to showcase your app or brand. After you publish, these appear
+ on your store listing page, search results, and elsewhere. These graphic
+ assets are key parts of a successful store listing page that attracts and
+ engages users, so you should consider having a professional produce them for
+ you. Screenshots and videos are also very important, because they show how
+ your apps look, how they’re used or played, and what makes them different.
+</p>
+
+<p>
+ All of your graphic assets should be designed so that they are easy to see
+ and highlight your apps or brand in a colorful, interesting way. The assets
+ should reference the same logo and icon as users will find in the All Apps
+ launcher once they have downloaded the app. Your graphic assets should also
+ fit in well with the graphic assets of all the apps you publish, which will
+ be also be displayed to users on your store listing page.
+</p>
+
+<p>
+ To help you market your apps more effectively to a global audience, Google
+ Play lets you create localized versions of your promotional graphics,
+ screenshots, and videos and upload them to the Developer Console. When a user
+ visits your app's store listing, Google Play displays the promotional
+ graphic, screenshots, and video that you've provided for the user's language.
+</p>
+
+<p>
+ To localize your promotional graphics, you can translate any embedded text,
+ use different imagery or presentation, or change your marketing approach to
+ best address the needs of users in specific languages. For example, if your
+ feature or promotional graphic includes an embedded product name or tag line,
+ you can translate that text and add it to a localized version of the
+ promotional graphic.
+</p>
+
+<p>
+ Because your localized graphic assets and videos are so important, you should
+ get started on creating and localizing them well in advance of your target
+ publishing date.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/graphics" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="build-upload">
+ 13. Build and Upload the Release-ready APK
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ When you are satisfied that your apps meet your UI, compatibility, and
+ quality requirements, you can build the release-ready versions of the apps.
+ You upload the release-ready APKs to your Developer Console and distribute to
+ users.
+</p>
+
+<p>
+ The process for preparing a release-ready APK is the same for all apps,
+ regardless of how they are distributed. Generally the process includes basic
+ code cleanup and optimization, building and signing with your release key,
+ and final testing.
+</p>
+
+<p>
+ For complete details on how to create a release-ready version of your app,
+ read <a href="{@docRoot}tools/publishing/preparing.html">Preparing for
+ Release</a>.
+</p>
+
+<p>
+ Once you have the release-ready APKs in hand, you can upload them to the
+ Developer Console. If necessary, you can replace an APK with a more recent
+ version before publishing.
+</p>
+<!--<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/toolsreference/launchchecklist/build"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3,9x3,6x3,9x3,9x3,9x3"
+ data-maxResults="6"></div>-->
+
+<div class="headerLine clearfloat">
+ <h1 id="plan-beta">
+ 14. Plan a Beta Release
+ </h1>
+
+ <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+ <div class="sidebox">
+ <h2>
+ Easy beta testing
+ </h2>
+
+ <p>
+ Google Play lets you set up groups of alpha and beta testers, anywhere
+ around the world. Check out this powerful feature next time you sign in
+ to the Developer Console.
+ </p>
+ </div>
+</div>
+
+<p>
+ Before launching your apps, it's always valuable to get real-world feedback
+ from users — even more so when you are launching new apps. It's highly
+ recommended that you distribute a pre-release version of your app to users
+ across your key markets and provide an easy means for them to provide
+ feedback and report bugs.
+</p>
+
+<p>
+ Google Play can help you set up a beta program for your app. After you sign
+ in to your Developer Console and have upload your APKs, you can set up groups
+ of users for alpha and beta testing the apps. You can start with a small
+ group of alpha testers, then move to a larger group of beta testers. Once
+ users are added, they access your app's store listing and install the app.
+ <strong>Users on alpha or beta versions cannot leave reviews or
+ ratings</strong>, so there is <strong>no risk to your rating</strong> on
+ Google Play. You need to arrange a mechanism for any testing feedback to be
+ delivered - such as a Google Forum or Google+.
+</p>
+
+<p>
+ The feedback you receive will help you adjust your UI, translations, and
+ store listing to ensure a great experience for users.
+</p>
+<!-- Related resources
+
+<table>
+ <tr>
+ <td>Beta-testing and Staged Rollouts
+See how you can facilitate testing with Google Play.</td>
+ </tr>
+</table> -->
+
+<div class="headerLine">
+ <h1 id="complete-details">
+ 15. Complete the Apps’ Store Listing
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ On Google Play, your apps’ product information is shown to users on their
+ store listing pages, the pages that users visit to learn more about your apps
+ and the pages from which they will decide to purchase or download your apps,
+ on their Android devices or on the web.
+</p>
+
+<p>
+ Google Play gives you a variety of ways to promote your apps and engage with
+ users on your store listing pages, from colorful graphics, screenshots, and
+ videos to localized descriptions, release details, and links to your other
+ apps. As you prepare to publish your apps, make sure that you take advantage
+ of all that your product detail pages can offer, making your apps as
+ compelling as possible to users.
+</p>
+
+<p>
+ You should begin planning your product pages in advance of your target launch
+ date, arranging for localized description, high-quality graphic assets,
+ screenshots and video, and so on.
+</p>
+
+<p>
+ As you get near your target publishing date, you should become familiar with
+ all the fields, options, and assets associated with the store listing
+ configuration page in the Developer Console. As you collect the information
+ and assets for the page, make sure that you can enter or upload it to the
+ Developer Console, until the page is complete and ready for publishing.
+</p>
+
+<p>
+ After you've set your apps’ geographic targeting in the Developer Console,
+ remember to add your localized store listing, promotional graphics, and so
+ on, for all of the languages that you support.
+</p>
+
+<p>
+ If your app is targeting tablet devices, make sure to include at least one
+ screenshot of the app running on a tablet, and highlight your apps’ support
+ for tablets in the app description, release notes, promotional campaigns, and
+ elsewhere.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/productdetails"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="use-badges">
+ 16. Use Google Play Badges and Links in your Promotional Campaigns
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Google Play badges give you an officially branded way of promoting your apps
+ to Android users. Use the <a href=
+ "{@docRoot}distribute/tools/promote/badges.html">Google Play Badge
+ generator</a> to quickly create badges to link users to your products from
+ web pages, ads, reviews, and more. You can also use special <a href=
+ "{@docRoot}distribute/tools/promote/linking.html">link formats</a> to link
+ directly to your store listing page, to a list of your products, or to search
+ results.
+</p>
+
+<p>
+ To help your apps get traction after launch, it's strongly recommended that
+ you support launch with a promotional campaign that announces your product
+ through many channels as possible, in as many countries as possible. For
+ example, you can promote a launch using ad placements, social network or blog
+ posts, video and other media, interviews and reviews, or any other channels
+ available.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/badges" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="final-checks">
+ 17. Final Checks and Publishing
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ When you think you’re ready to publish, sign in to the Developer Console and
+ take a few moments for a few final checks.
+</p>
+
+<p>
+ Make sure that:
+</p>
+
+<ul>
+ <li>
+ <p>
+ Your developer profile has the correct information and is linked to the
+ proper Google Wallet merchant account (if you’re selling products).
+ </p>
+ </li>
+
+ <li>
+ <p>
+ You have the right version of the apps uploaded.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ All parts of your store listing are ready, including all graphic assets,
+ screenshots, video, localized descriptions, and so on.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ You have set your app's pricing to free or priced.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ You have set country (and carrier) targeting and priced your products (if
+ appropriate) in buyer currencies
+ </p>
+ </li>
+
+ <li>
+ <p>
+ "Compatible devices" shows that your apps are reaching the devices that
+ you’re targeting. If not, you should check with your development team on
+ the apps’ requirements and filtering rules.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ You’ve provided the correct link to your website and the correct support
+ email address.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Your apps don’t violate content policy guidelines.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ You’ve acknowledged that your apps meets the guidelines for Android
+ content on Google Play and also US export laws.
+ </p>
+ </li>
+</ul>
+
+<p>
+ Your apps are now ready to publish!
+</p>
+
+<p>
+ If you’re releasing an update, make sure to read the <a href=
+ "http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113476&topic=2365760&ctx=topic">
+ requirements for publishing updates</a>.
+</p>
+
+<p>
+ When you’re ready, click the <strong>Publish</strong> button in the Developer
+ Console. Within a few hours, your apps will become available to users and
+ your product page will appear in Google Play for browsing, searching, or
+ linking from your promotional campaigns.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/finalchecks"
+data-sortorder="-timestamp" data-cardsizes="6x3,6x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="support-users">
+ 18. Support Users after Launch
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ After you publish apps or app updates, it's crucial for you to support your
+ customers. Prompt and courteous support can provide a better experience for
+ users that results in better ratings and more positive reviews for your
+ products. Users are likely to be more engaged with your app and recommend it
+ if you’re responsive to their needs and feedback. This is especially true
+ after publishing if you’re using a coordinated promotional campaign.
+</p>
+
+<p>
+ There are a number of ways that you can keep in touch with users and offer
+ them support. The most fundamental is to provide your <em>support email
+ address</em> on your store listing pages. Beyond that, you can provide
+ support in any way you choose, such as a forum, mailing list, or a Google+
+ page. The Google Play team provides user support for downloading, installing.
+ and payments issues, but issues that fall outside of these topics will be in
+ your domain. Examples of issues you can support include: feature requests,
+ questions about using the apps, and questions about compatibility settings.
+</p>
+
+<p>
+ After publishing, plan to:
+</p>
+
+<ul>
+ <li>
+ <p>
+ Check your ratings and reviews frequently on your apps’ store listing
+ pages. Watch for recurring themes that could signal bugs or other issues.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Be mindful of new Android platform version launches, as compatibility
+ settings for your apps might need to be updated.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Put a link to your support resources on your website and set up any other
+ support such as forums.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Provide an appropriate support email address on your store listing pages
+ and respond to users when they take the time to email you.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Beyond the automatic refund window offered by Google Play, be generous
+ with your own refund policy, as satisfied users will be more likely to
+ purchase in the future.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Acknowledge and fix issues in your apps. It helps to be transparent and
+ list known issues on your store listing pages proactively.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Publish updates as frequently as you’re able, without sacrificing quality
+ or annoying users with too-frequent updates.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ With each update, make sure to provide a summary of what's changed. You
+ can enter this information in the Developer Console. Users will read it
+ and appreciate that you are serious about improving the quality of your
+ apps.
+ </p>
+ </li>
+</ul>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/toolsreference/launchchecklist/afterlaunch"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3,9x3,9x3,9x3,9x3,9x3"
+ data-maxResults="6"></div>
diff --git a/docs/html/distribute/tools/localization-checklist.jd b/docs/html/distribute/tools/localization-checklist.jd
new file mode 100644
index 0000000..7a638ed
--- /dev/null
+++ b/docs/html/distribute/tools/localization-checklist.jd
@@ -0,0 +1,978 @@
+page.title=Localization Checklist
+page.metaDescription=Take advantage of the worldwide audience offered by Android and Google Play. Read this checklist to get an overview of how to deliver your product to markets around the world.
+meta.tags="localizing, publishing, disttools"
+page.tags="local, l10n, translation, language"
+page.image=/distribute/images/localization-checklist.jpg
+
+@jd:body
+
+<div id="qv-wrapper">
+ <div id="qv" style="width:280px">
+ <h2>Checklist</h2>
+ <ol>
+ <li><a href="#identify-languages">1. Identify target languages and locales</a></li>
+ <li><a href="#design">2. Design for localization</a></li>
+ <li><a href="#manage-strings">3. Manage strings for localization</a></li>
+ <li><a href="#translate-strings">4. Translate UI strings and other resources</a></li>
+ <li><a href="#test">5. Test your localized app</a></li>
+ <li><a href="#prepare-launch">6. Prepare for international launch</a></li>
+ <li><a href="#support-users">7. Support international users after launch</a></li>
+ </ol>
+ </div>
+</div>
+
+<div class="top-right-float" style="width:194px">
+ <img src="{@docRoot}distribute/images/localization-checklist.jpg">
+</div>
+
+<p>
+ Android and Google Play offer you a worldwide audience for your apps, with an
+ addressable user base that's growing very rapidly in countries such as Japan,
+ Korea, India, Brazil, and Russia. We strongly encourage you to localize as it
+ can maximize your apps’ distribution potential resulting in ratings from
+ users around the world.
+</p>
+
+<p>
+ Localization involves a variety of tasks throughout your app development
+ cycle, and advance planning is essential. This document helps you identify
+ key aspects of localization to get your app ready for a successful worldwide
+ launch on Google Play.
+</p>
+
+<div class="headerLine">
+ <h1 id="identify-languages">
+ 1. Identify target languages and locales
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ A basic but important step in preparing for localization is identifying the
+ countries where you’ll distribute your apps and the languages spoken there.
+ Localizing your apps is particularly important in countries where there is a
+ large market opportunity and English or another international language is not
+ widely used.
+</p>
+
+<p>
+ For international users, you can manage your apps in three main dimensions:
+ country, locale, and language. Of those, language is the key consideration
+ for localization (locale can also significant because of differences in
+ formats for dates, times, currencies, and similar information). Users control
+ both the language and locale used on their Android devices and in turn those
+ affect how your app is displayed.
+</p>
+
+<p>
+ Typically, you would decide which countries to target first, based on overall
+ market size and opportunity, app category, competitive landscape, local
+ pricing and financial factors, and so on. Then, based on your country
+ targeting, you would determine the languages you need to support in your
+ apps.
+</p>
+
+<p>
+ You may then decide to localize into some or all languages of the targeted
+ country. It might make sense to start with a major regional language and add
+ more languages as user base grows.
+</p>
+
+<p>
+ Once you have identified your target languages, you can focus your
+ development, translation, testing, and marketing efforts to these markets.
+</p>
+
+<h3 id="related-resources">
+ Related Resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/localizationchecklist/identifylocales"
+data-sortorder="-timestamp" data-cardsizes="9x3," data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="design">
+ 2. Design for localization
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ After you've determined your target languages for localization, assess what
+ you'll need to do to support them in your apps and plan the work early.
+ Consider the vocabulary expansion, script requirements, character spacing and
+ wrapping constraints, left-to-right and right-to-left support, and other
+ potential factors in each language.
+</p>
+
+<h4>
+ <strong>Design a single set of flexible layouts</strong>
+</h4>
+
+<p>
+ As you create your layouts, make sure that any UI elements that hold text are
+ designed generously. It’s good to allow more space than necessary for your
+ language (up to 30% more is normal) to accommodate other languages.
+</p>
+
+<p>
+ Also, elements should be able to expand horizontally or vertically to
+ accommodate variations in the width and height of UI strings or input text.
+ Your text strings shouldn’t overlap borders or the screen edge in any of your
+ target languages.
+</p>
+
+<p>
+ If you design your UI carefully, you can typically use a single set of
+ layouts for all of the languages you support. See <a href=
+ "{@docRoot}training/basics/fragments/fragment-ui.html">Building a Flexible
+ UI</a> for more information.
+</p>
+
+<h4>
+ <strong>Use alternative layouts where needed</strong>
+</h4>
+
+<p>
+ In cases where your UI can't accommodate text in one of your target
+ languages, you can create an <a href=
+ "{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">
+ alternative layout</a> for that language only. Android makes it easy to
+ declare sets of layouts and other resources to load for specific languages,
+ locales, screen sizes, and so on, simply by tagging them with the appropriate
+ resource qualifiers. While the flexibility of alternative layouts exists it
+ can also make your apps harder to maintain over time. In general, using a
+ single, more flexible layout is preferred.
+</p>
+
+<h4>
+ <strong>Support RTL layouts and text</strong>
+</h4>
+
+<p>
+ If you’re distributing to countries where right-to-left (RTL) scripts are
+ used, you should consider implementing support for RTL layouts and text
+ display and editing, to the extent possible.
+</p>
+
+<p>
+ Android 4.1 introduced limited support for bidirectional text, allowing apps
+ to display and edit text in both left-to-right (LTR) and right-to-left (RTL)
+ scripts. Android 4.2 added <a href=
+ "http://android-developers.blogspot.fr/2013/03/native-rtl-support-in-android-42.html">
+ full native support for RTL layouts</a>, including layout mirroring, so that
+ you can deliver the same great app experiences to all of your users.
+</p>
+
+<p>
+ At a minimum, for Android 4.2 users, it's simple to add basic RTL layout
+ mirroring, which goes a long way toward meeting the needs of RTL users.
+</p>
+
+<h4>
+ <strong>Use system-provided formats for dates, times, numbers, and
+ currencies</strong>
+</h4>
+
+<p>
+ Where your apps specify dates, times, numbers, currencies, and other entities
+ that can vary by locale, make sure to use the system-provided formats, rather
+ than app-specific formats. Keep in mind that not every locale uses the same
+ thousands separator, decimal separator, or percent sign.
+</p>
+
+<p>
+ Android provides a variety of utilities for formatting and converting
+ patterns across locales, such as <a href=
+ "{@docRoot}reference/android/text/format/DateUtils.html">DateUtils</a> and
+ <a href="{@docRoot}reference/java/text/DateFormat.html">DateFormat</a> for
+ dates; <a href=
+ "{@docRoot}reference/java/lang/String.html#format(java.lang.String,%20java.lang.Object...)">
+ String.format()</a> or <a href=
+ "{@docRoot}reference/java/text/DecimalFormat.html">DecimalFormat</a> for
+ numbers and currency; <a href=
+ "{@docRoot}reference/android/telephony/PhoneNumberUtils.html">PhoneNumberUtils</a>
+ for phone numbers; and others.
+</p>
+
+<p>
+ Hardcoding your formats based on assumptions about the user's locale can
+ result in problems when the user changes to another locale. Using
+ system-provided formats and utilities is strongly encouraged.
+</p>
+
+<h4>
+ <strong>Include a full set of default resources</strong>
+</h4>
+
+<p>
+ Make sure that your apps can run properly regardless of language or locale by
+ providing a complete set of default resources. The app's default resources
+ are those that are <em>not marked</em> with any language or locale
+ qualifiers, for example those stored in res/drawable/ and res/values/. If
+ your apps attempt to load a resource that isn't available in the current
+ language or in the default set, they will crash.
+</p>
+
+<p>
+ Whatever the default language you’re using in your apps, make sure that you
+ store the associated layouts, drawables, and strings in default resource
+ directories, without language or locale qualifiers.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/tools/loc/designforloc" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="manage-strings">
+ 3. Manage strings for localization
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ It's important to manage your apps’ UI strings properly, so that you deliver
+ a great experience for users and make localization straightforward.
+</p>
+
+<h4>
+ <strong>Move all strings into strings.xml</strong>
+</h4>
+
+<p>
+ As you build your apps, remember not to hard code any string. Instead declare
+ <em>all</em> of your strings as resources in a default strings.xml file which
+ makes it easy to update and localize. Strings in strings.xml file can be
+ extracted, translated and integrated back into your app (with appropriate
+ qualifiers) without any changes to compiled code.
+</p>
+
+<p>
+ If you generate images with text, put those strings in strings.xml as well,
+ and regenerate the images after translation.
+</p>
+
+<h4>
+ <strong>Follow Android guidelines for UI strings</strong>
+</h4>
+
+<p>
+ As you design and develop your UIs, make sure that you pay close attention to
+ <em>how</em> you talk to your user. In general, use a <a href=
+ "{@docRoot}design/style/writing.html">succinct and compressed style</a> that
+ is friendly but brief, and use a consistent style throughout your UIs.
+</p>
+
+<p>
+ Make sure that you read and follow the Android Design recommendations for
+ <a href="{@docRoot}design/style/writing.html">writing style and word
+ choice</a>. Doing so will make your apps appear more polished to the user and
+ will help users understand your UI more quickly.
+</p>
+
+<p>
+ Also, always use Android standard terminology wherever possible—such as
+ for UI elements such as "Action Bar," "Options Menu," "System Bar,"
+ "Notifications," and so on. Using Android terms correctly and consistently
+ makes translation easier and results in a better end-product for users.
+</p>
+
+<h4>
+ <strong>Provide sufficient context for declared strings</strong>
+</h4>
+
+<p>
+ As you declare strings in your strings.xml file, make sure to describe the
+ context in which the string is used. This information will be invaluable to
+ translators and result in better quality translation and will also help you
+ manage your strings more effectively over time.
+</p>
+
+<p>
+ Here's an example:
+</p>
+
+<pre class="prettyprint">
+<!-- The action for submitting a form. This text is on a button that can fit 30 chars -->
+<string name="login_submit_button">Sign in</string>
+</pre>
+<p>
+ Consider providing context information that may include:
+</p>
+
+<ul>
+ <li>
+ <p>
+ What is this string for? When/where is it presented to the user?
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Where is this in the layout? For example, if it’s a button, translations
+ are less flexible than if it were a text box.
+ </p>
+ </li>
+</ul>
+
+<h4>
+ <strong>Mark message parts that should not be translated</strong>
+</h4>
+
+<p>
+ Often strings contain contain text that shouldn’t be translated to other
+ languages. Common examples might be a piece of code, a placeholder for a
+ value, a special symbol, or a name. As you prepare you strings for
+ translation, look for and mark text that should remain as-is, without
+ translation, so that translators don’t change it.
+</p>
+
+<p>
+ To mark text that should not be translated, use an
+ <code><xliff:g></code> placeholder tag. Here's an example tag that
+ ensures the text "%1$s" will not be changed during translation (otherwise it
+ could break the message):
+</p>
+
+<pre class="prettyprint">
+<string name="countdown">
+ <xliff:g id="time" example="5 days>%1$s</xliff:g>until holiday
+</string>
+</pre>
+<p>
+ When you declare a placeholder tag, always add an id attribute that explains
+ what the placeholder is for. If your apps will later replace the placeholder
+ value, be sure to provide an example attribute to clarify the expected use.
+</p>
+
+<p>
+ Here are some more examples of placeholder tags:
+</p>
+
+<pre>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+<!-- Example placeholder for a special unicode symbol -->
+
+<string name="star_rating">Check out our 5
+
+ <xliff:g id="star">\u2605</xliff:g>
+
+</string>
+
+<!-- Example placeholder for a for a URL -->
+
+<string name="app_homeurl">
+
+ Visit us at <xliff:g id="application_homepage">http://my/app/home.html</xliff:g>
+
+</string>
+
+<!-- Example placeholder for a name -->
+
+<string name="prod_name">
+
+ Learn more at <xliff:g id="prod_gamegroup">Game Group</xliff:g>
+
+</string>
+
+<!-- Example placeholder for a literal -->
+
+<string name="promo_message">
+
+ Please use the "<xliff:g id="promotion_code">ABCDEFG</xliff:g>” to get a discount.
+
+</string>
+
+...
+
+</resources>
+</pre>
+<h3 class="clearfloat">
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/localizationchecklist/managestrings"
+data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="translate-strings">
+ 4. Translate UI strings and other resources
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Translating your apps’ UI strings and resources to your target languages is
+ the key phase of localization, and it's the one that requires the most care
+ and planning.
+</p>
+
+<p>
+ It is recommended to work with a professional translator (see <a href=
+ "#gp-trans">Purchase professional translations</a>) to ensure high quality
+ translations that enhance the value of your app. Machine translations,
+ although an option may not produce as good an experience for your users.
+</p>
+
+<h4>
+ <strong>Prepare for translation</strong>
+</h4>
+
+<p>
+ Translation output quality will depend in part on your input therefore make
+ sure that your strings.xml file is well organized, well commented, and
+ accurate.
+</p>
+
+<p>
+ Here are some ways to prepare your strings for translation:
+</p>
+
+<ul>
+ <li>
+ <p>
+ Make sure your strings are formatted correctly and consistently.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Follow the strings recommendations listed in <a href=
+ "#manage-strings">Manage strings for localization</a>, above.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Clean up the strings.xml file and remove unused strings.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Place comments in the file to identify the owner, origin, and the version
+ of the file, as well as any special instructions for translators.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Identify existing translations, if any, and include those in an outgoing
+ zip file or other package that you send to translators.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Identify drawables or other resources that require translation and
+ include them in the translators’ package.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Additionally, consider translating your apps’ store listing details
+ — app title and description, release notes, and so on — as
+ well as other international marketing materials.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Create a terminology list that explains the meaning and use of key terms
+ found in your product, your market, or the underlying technology. Add the
+ list to the translators’ package.
+ </p>
+ </li>
+</ul>
+
+<h4>
+ <strong>Send your strings for translation</strong>
+</h4>
+
+<p>
+ Early in the development cycle, contact professional translation vendors to
+ get an idea of cost and turnaround time. Make sure to include multiple
+ iterations in the cost. You can find translation vendors online or use
+ translation services available directly from Google Play Developer console
+ (see <a href="#gp-trans">Purchase professional translations</a>).
+</p>
+
+<p>
+ When your translations are complete, take a preliminary look at the
+ translations. Check that all files were translated, check for potential
+ encoding issues, and make sure that declaration formats are intact.
+</p>
+
+<p>
+ If everything looks good, carefully move the localized directories and files
+ back into your apps’ resources. Make sure to tag the directories with the
+ appropriate language and locale qualifiers so that they'll later be loaded
+ properly.
+</p>
+
+<p>
+ After the translations are merged back into your app, start <a href=
+ "#test">testing the localized app</a>.
+</p>
+
+<h4 id="gp-trans">
+ <strong>Purchase professional translations through Google Play</strong>
+</h4>
+
+<div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>
+ App Translations Service
+ </h2>
+
+ <p>
+ To make it easy to export your app's strings and import the finished
+ translations into your project, try the <a href=
+ "{@docRoot}sdk/installing/installing-adt.html#tmgr">ADT Translation
+ Manager Plugin</a>.
+ </p>
+ </div>
+</div>
+
+<p>
+ Google Play App Translation Service can help you quickly find and purchase
+ translations of your app. In the Developer Console, you can browse a list of
+ third-party vendors who are pre-qualified by Google to offer high-quality
+ translation at competitive prices. You can upload the strings you want
+ translated, select the languages you want to translate into, and select your
+ translation vendor based on time and price.
+</p>
+
+<p>
+ Once you've purchased translations, you'll receive an email from your vendor.
+ Your translations are a direct business agreement between you and your
+ vendor; you'll need to work directly with the vendor to manage the
+ translation process and deliverables and resolve any support issues.
+</p>
+
+<div>
+ <img src="{@docRoot}images/gp-localization-trans-0.png" class="border-img">
+</div>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/localizationchecklist/translatestrings"
+data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="test">
+ 5. Test your localized app
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Once you've received your translated strings and resources and moved them
+ back into your apps, you need to test the apps to make sure that they’re
+ ready for distribution to your international users.
+</p>
+
+<p>
+ Manual testing can help you discover localization issues in your layouts and
+ strings that can affect user satisfaction and, ultimately, your apps' user
+ rating.
+</p>
+
+<h4>
+ <strong>Set up a test environment</strong>
+</h4>
+
+<p>
+ To test your localized app, you'll need to set up an environment consisting
+ of multiple devices (or virtual devices) and screen sizes, based on the
+ markets and form factors you’re targeting. Note that the range of devices in
+ specific regions might be different. If possible, match your test devices to
+ the actual devices likely to be available to users.
+</p>
+
+<h4>
+ <strong>Look for common localization issues</strong>
+</h4>
+
+<p>
+ On each test device, set the language or locale in Settings. Install and
+ launch the app and then navigate through all of the UI flows, dialogs, and
+ user interactions. Enter text in inputs. Some things to look for include:
+</p>
+
+<ul>
+ <li>
+ <p>
+ Clipped text, or text that overlaps the edge of UI elements or the screen
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Poor line wrapping
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Incorrect word breaks or punctuation
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Incorrect alphabetical sorting
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Incorrect layout direction or text direction
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Untranslated text — if your default strings are displayed instead
+ of translated strings, then you may have overlooked those strings for
+ translation or marked the resources directory with an incorrect language
+ qualifier.
+ </p>
+ </li>
+</ul>
+
+<p>
+ For cases where your strings have expanded in translation and no longer fit
+ your layouts, it's suggested you try to simplify your default text, simplify
+ your translated text, or adjust your default layouts. If none of those
+ resolves the issue, you can create a custom layout for the language.
+</p>
+
+<h4>
+ <strong>Test for default resources</strong>
+</h4>
+
+<p>
+ After you've tested your apps in all of your supported languages and locales,
+ make sure to test it again in an <em>unsupported language</em> and locale.
+ This’ll help you make sure that your apps includes a full set of default
+ strings and resources, so that your apps are usable to all users, regardless
+ of their preferred language.
+</p>
+
+<h4>
+ <strong>Review with native-language speakers</strong>
+</h4>
+
+<p>
+ During or after testing, it's recommended that you let native speakers review
+ your localized apps. One way to do that is through beta testing with regional
+ users — Google Play can help you do this. <!-- </p>
+
+<h3 class="clearfloat">Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/toolsreference/localizationchecklist/test"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3,9x3,6x3,9x3,9x3,9x3"
+ data-maxResults="6"></div> -->
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="prepare-launch">
+ 6. Prepare for international launch
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Getting your apps translated is a key part of localization, but to help your
+ product attract users and gain visibility, you should prepare for launch in
+ your target countries and create a broader launch and marketing plan for
+ international users.
+</p>
+
+<h4>
+ <strong>Localize your Google Play listing</strong>
+</h4>
+
+<div class="sidebox-wrapper" style="float:right;">
+ <div class="sidebox">
+ <h2>
+ Localize your Google Play listing
+ </h2>
+
+ <p>
+ Google Play Store listing is the first impression international users
+ will have of your app. You should highlight what's great about your apps
+ to all of your users! Localize your listing in the Developer Console,
+ including:
+ </p>
+
+ <ul>
+ <li>App title and description
+ </li>
+
+ <li>App screenshots on phones and tablets
+ </li>
+
+ <li>Promotional graphics and videos.
+ </li>
+ </ul>
+ </div>
+</div>
+
+<p>
+ If you want your apps to be successful in international markets, it's
+ essential to localize your Google Play store listing. You can manage your
+ localized listing in the Developer Console.
+</p>
+
+<p>
+ Well before launch, decide on your app title, description, promotional text,
+ marketing names and programs, and other text and images. Send your listing
+ text and images for translation early, so that you’ve them ready when beta
+ testing begins. When your translated text is available, you can add it
+ through the Developer Console.
+</p>
+
+<div class="sidebox-wrapper" style="float:right;">
+ <div class="sidebox">
+ <h2>
+ Store listing translation in Google Play
+ </h2>
+
+ <p>
+ You can use the App Translation service on Google Play to translate your
+ store listing. Prepare an XML file with your store listing information
+ and upload just as you would upload the strings.xml file (see <a href=
+ "#gp-trans">Purchase professional translations</a>)
+ </p>
+ </div>
+</div>
+
+<p>
+ Also, since you've made the effort to create a great localized app, let users
+ know about it! Take screenshots of your UI in each language, for phones and
+ 7- and 10- inch tablets. You can upload screenshots to the Developer Console
+ for each language you support. These will be of great value to users browsing
+ your app listings in other languages.
+</p>
+
+<p>
+ It's also essential to create localized versions of your promotional graphics
+ and videos. For example, your apps’ feature graphics might include text that
+ should be translated, for maximum effectiveness, or you might want to take a
+ different visual approach in one country than you do in another. You can
+ create different versions of your promotional graphics for each language and
+ upload them to the Developer Console. If you offer a promotional video, you
+ can create localized versions of it and then add a link to the correct
+ localized video for each language you support.
+</p>
+
+<h4>
+ <strong>Plan a beta release in key countries</strong>
+</h4>
+
+<div class="sidebox-wrapper" style="float:right;">
+ <div class="sidebox">
+ <h2>
+ Easy beta testing
+ </h2>
+
+ <p>
+ Google Play now lets you set up groups of alpha and beta testers,
+ anywhere around the world. Check out this powerful feature next time you
+ sign in to the Developer Console.
+ </p>
+ </div>
+</div>
+
+<p>
+ Before launching your apps, it's always valuable to get real-world feedback
+ from users — even more so when you are launching an app in a new
+ language, country, or region. In those cases, it's highly recommended that
+ you distribute a pre-release version of your apps to users across your key
+ markets and provide an easy means for them to provide feedback and report
+ bugs.
+</p>
+
+<p>
+ Google Play can help you set up a beta program for your apps. After you sign
+ in to the Developer Console and upload your APK, you can set up groups of
+ users for alpha testing and beta testing the app. You can start with a small
+ group of alpha testers, then move to a larger group of beta testers.
+</p>
+
+<p>
+ Once users are added, they access your app's store listing and install the
+ app. <strong>Users on alpha or beta versions cannot leave reviews or
+ ratings</strong>, so there is <strong>no risk to your rating</strong> on
+ Google Play, however it does mean you need to setup a mechanism for your
+ testers to provide you with feedback: consider creating a <a href=
+ "http://www.google.com/+/business/">Google+</a> page or <a href=
+ "https://groups.google.com/forum/#!overview">Google Groups</a>.
+</p>
+
+<p>
+ The feedback you receive will help you adjust your UI, translations, and
+ store listing to ensure a great experience for users.
+</p>
+
+<h4>
+ <strong>Plan for international marketing</strong>
+</h4>
+
+<p>
+ For highest visibility across countries, consider an international marketing
+ or advertising campaign. The scope of the campaign will vary based on the
+ budget you can support, but in general it's cost-effective and productive to
+ do regional or country-specific marketing at launch and after.
+</p>
+
+<h4>
+ <strong>Create localized Google Play badges</strong>
+</h4>
+
+<p>
+ If you’re preparing international marketing, make sure to include a <a href=
+ "{@docRoot}distribute/tools/promote/badges.html">localized Google Play
+ badge</a> to tell users you're on Google Play. You can use the badge
+ generator to quickly build localized badges that you can use on websites or
+ marketing materials. High-resolution assets are also available.
+</p>
+
+<h4>
+ <strong>Create Localized Device Art</strong>
+</h4>
+
+<p>
+ If you feature product shots of your apps running on Android devices, make
+ sure that those shots look great and reflect the latest in Android devices.
+ To help you create high-quality marketing materials, use the drag-and-drop
+ <a href="{@docRoot}distribute/tools/promote/device-art.html">Device Art
+ Generator</a> to quickly frame your screenshot on a Nexus device.
+</p>
+
+<h4>
+ <strong>Check your Optimization Tips</strong>
+</h4>
+
+<p>
+ As you prepare for launch, make sure to sign into the Developer Console and
+ check your apps’ Optimization Tips. The Optimization Tips let you know when
+ you’re missing parts of your localized store listing and provide other
+ helpful reminders for a successful localized launch.
+</p>
+
+<h3>
+ Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/localizationchecklist/preplaunch"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="support-users">
+ 7. Support international users after launch
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ After you launch your apps internationally, you should be prepared to support
+ users in a variety of languages and time zones. The extent of your
+ international user support depends on your budget, but at a minimum you
+ should watch your ratings, reviews, and download stats carefully after
+ launch.
+</p>
+
+<p>
+ Here are some suggestions:
+</p>
+
+<ul>
+ <li>
+ <p>
+ Use the app stats in the Developer Console to compare your downloads,
+ installs, and uninstalls, and ratings across languages and
+ countries—If your downloads or ratings aren’t keeping up in
+ specific languages or countries, consider options for improving your
+ product or changing your marketing approach.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Check reviews regularly—Google Play translates all user reviews for
+ you, so you can stay in touch with how international users feel about
+ your apps, what features they like and what issues are affecting them. By
+ watching reviews, you can spot technical issues that may affect users in
+ a particular country, then fix and update your apps.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Respond to reviews if possible—It's good to engage with
+ international users in their language or a common language if possible.
+ If not, you can try using translation tools, although results may not be
+ predictable. If your apps gets very popular in a language, consider
+ getting support help from native-language speakers.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Make sure there's a link to any support resources on your website.
+ Consider setting up language-specific user groups, Google+ communities,
+ or other support forums.
+ </p>
+ </li>
+</ul>
+
+<p>
+ By following these practices for localizing your apps, promoting and
+ marketing to international users, and providing ongoing support, you can
+ attract many new users to your apps and maintain their loyalty.
+</p>
+
+<p>
+ Make sure to read the <a href=
+ "{@docRoot}distribute/tools/launch-checklist.html">Launch Checklist</a> to
+ learn more about how to plan, build, and launch your app on Google Play.
+</p>
+<h3 class="clearfloat">Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/toolsreference/localizationchecklist/supportlaunch"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3,9x3,6x3,9x3,9x3,9x3"
+ data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/tools/open-distribution.jd b/docs/html/distribute/tools/open-distribution.jd
new file mode 100644
index 0000000..f804af2
--- /dev/null
+++ b/docs/html/distribute/tools/open-distribution.jd
@@ -0,0 +1,150 @@
+page.title=Alternative Distribution Options
+page.metaDescription=With Android you can distribute apps to users in any way you want, using any store or distribution approach.
+page.image=/distribute/images/alt-distribution.jpg
+
+@jd:body
+
+<p>
+ As an open platform, Android offers choice. You can distribute your Android
+ apps to users in any way you want, using any distribution approach or
+ combination of approaches that meets your needs. From publishing in an app
+ marketplace to serving your apps from a web site or emailing them directly
+ users, you’re never locked into any particular distribution platform.
+</p>
+
+<p>
+ The process for building and packaging your apps for distribution is the
+ same, regardless of how you distribute them. This saves you time and lets you
+ automate parts of the process as needed. You can read <a href=
+ "{@docRoot}tools/publishing/preparing.html">Preparing for Release</a> for
+ more information.
+</p>
+
+<p>
+ The sections below highlight some of the alternatives for distributing your
+ apps.
+</p>
+
+<div class="headerLine">
+ <h1>
+ Distributing Through an App Marketplace
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Usually, to reach the broadest possible audience, you’d distribute your apps
+ through a marketplace, such as Google Play.
+</p>
+
+<p>
+ Google Play is the premier marketplace for Android apps and is particularly
+ useful if you want to distribute your apps to a large global audience.
+ However, you can distribute your apps through any app marketplace you want or
+ use multiple marketplaces.
+</p>
+
+<p>
+ Unlike other forms of distribution, Google Play allows you to use the In-app
+ Billing service and Licensing service. The <a href=
+ "{@docRoot}google/play/billing/index.html">In-app Billing service</a> makes
+ it easy to sell in-app products like game jewels or app feature upgrades. The
+ <a href="{@docRoot}google/play/licensing/index.html">Licensing service</a>
+ helps prevent unauthorized installation and use of your apps.
+</p>
+
+<div class="headerLine">
+ <h1>
+ Distributing Your Apps by Email
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure" style="width:300px;">
+ <img src="{@docRoot}images/publishing/publishing_via_email.png">
+ <p class="img-caption">
+ <b>Figure 1.</b> Users can simply click <b>Install</b> when you send them
+ an application via email.
+ </p>
+</div>
+
+<p>
+ An easy and quick way to release your apps is to send them to users by email.
+ To do this, you prepare the app for release, attach it to an email, and send
+ it to a user. When the user open your email on their Android-powered device,
+ the Android system recognizes the APK and displays an <strong>Install
+ Now</strong> button in the email message (see Figure 1). Users can install
+ your app by touching the button.
+</p>
+
+<p>
+ <strong>Note:</strong> The <strong>Install Now</strong> button, shown in
+ Figure 1, appears only if the user has configured their device to allow
+ installation from <a href=
+ "{@docRoot}distribute/open.html#unknown-sources">unknown sources</a> and
+ opened your email in the native Gmail app.
+</p>
+
+<p>
+ Distributing apps through email is convenient if you’re sending them to a few
+ trusted users, as it provides few protections from piracy and unauthorized
+ distribution; that is, anyone you send your apps to can simply forward them
+ to others.
+</p>
+
+<div class="headerLine">
+ <h1>
+ Distributing Through a Website
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ If you don’t want to release your apps on a marketplace such as Google Play,
+ you can make them available for download on your own website or server,
+ including on a private or enterprise server. To do this, you first prepare
+ your apps for release in the normal way. Then all you need to do is host the
+ release-ready APK file on your website and provide a download link to users.
+</p>
+
+<p>
+ When users browse to the download link from their Android-powered devices,
+ the file is downloaded and Android system automatically starts installing it
+ on the device. However, the installation process will start automatically
+ only if users have configured their Settings to allow the installation of
+ apps from <a href="{@docRoot}distribute/open.html#unknown-sources">unknown
+ sources</a>.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1>
+ User Opt-In for Apps from Unknown Sources
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure" style="width:325px;">
+ <img src="{@docRoot}images/publishing/publishing_unknown_sources_sm.png">
+ <p class="img-caption">
+ <b>Figure 2.</b> Users must enable the <b>Unknown sources</b> setting
+ before they can install apps not downloaded from Google Play.
+ </p>
+</div>
+
+<p>
+ Android protects users from inadvertent download and install of apps from
+ locations other than Google Play (which is trusted). It blocks such installs
+ until the user opts-in <strong>Unknown sources</strong> in Settings
+ <strong>></strong> Security, shown in Figure 2. Users need to make this
+ configuration change <em>before</em> they download your apps to their
+ devices.
+</p>
+
+<p>
+ Note that some network providers don’t allow users to install applications
+ from unknown sources.
+</p>
diff --git a/docs/html/distribute/tools/promote/badge-files.jd b/docs/html/distribute/tools/promote/badge-files.jd
new file mode 100644
index 0000000..cce3632
--- /dev/null
+++ b/docs/html/distribute/tools/promote/badge-files.jd
@@ -0,0 +1,291 @@
+page.title=Google Play Badge Files
+page.image=/images/gp-badges-set.png
+page.metaDescription=Download hi-res assets for localized Google Play badges.
+page.tags="badge, google play"
+
+@jd:body
+
+<style>
+table tr td {border:0}
+</style>
+
+<p>The following links provide the Adobe® Illustrator® (.ai) file for the
+two Google Play badges.</p>
+
+<hr>
+<img src="{@docRoot}images/brand/en_generic_rgb_wo_60.png" alt="Get It On Google Play">
+
+<div style="clear:left"> </div>
+
+<div class="col-4" style="margin-left:0">
+
+ <a href="{@docRoot}downloads/brand/v2/english_get.ai">English (English)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/amharic_get.ai">ኣማርኛ (Amharic)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/af_generic_rgb_wo.ai">Afrikaans (Afrikaans)</a><br/>
+<!--
+ <a href="{@docRoot}downloads/brand/ar_generic_rgb_wo.ai">العربية (Arabic)</a><br/>
+-->
+ <a href="{@docRoot}downloads/brand/v2/belarusian_get.ai">Беларуская (Belarusian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/bulgarian_get.ai">български (Bulgarian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/catalan_get.ai">Català (Catalan)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/traditional_chinese_get.ai">中文 (中国) (Chinese)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/hongkong_chinese_get.ai">中文(香港) (Chinese Hong Kong)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/taiwan_chinese_get.ai">中文 (台灣) (Chinese Taiwan)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/croatian_get.ai">Hrvatski (Croatian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/czech_get.ai">Česky (Czech)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/danish_get.ai">Dansk (Danish)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/dutch_get.ai">Nederlands (Dutch)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/estonian_get.ai">Eesti keel (Estonian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/farsi_get.ai">فارسی (Farsi Persian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/filipino_get.ai">Tagalog (Filipino)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/finnish_get.ai">Suomi (Finnish)</a><br/>
+
+</div>
+
+<div class="col-4">
+
+ <a href="{@docRoot}downloads/brand/v2/french_get.ai">Français (French)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/german_get.ai">Deutsch (German)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/greek_get.ai">Ελληνικά (Greek)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/hebrew_get.ai">עברית (Hebrew)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/hindi_get.ai">हिन्दी (Hindi)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/hungarian_get.ai">Magyar (Hungarian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/indonesian_get.ai">Bahasa Indonesia (Indonesian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/italian_get.ai">Italiano (Italian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/japanese_get.ai">日本語 (Japanese)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/kazakh_get.ai">Қазақ тілі (Kazakh)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/korean_get.ai">한국어 (Korean)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/latvian_get.ai">Latviski (Latvian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/lithuanian_get.ai">Lietuviškai (Lithuanian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/malay_get.ai">Bahasa Melayu (Malay)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/norwegian_get.ai">Norsk (Norwegian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/polish_get.ai">Polski (Polish)</a><br/>
+
+</div>
+
+<div class="col-4" style="margin-right:0">
+
+ <a href="{@docRoot}downloads/brand/v2/portugal_portuguese_get.ai">Português (Portuguese)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/brazilian_portuguese_get.ai">Português Brasil (Portuguese Brazil)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/romanian_get.ai">Românã (Romanian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/russian_get.ai">Pусский (Russian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/serbian_get.ai">Српски / srpski (Serbian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/slovak_get.ai">Slovenčina (Slovak)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/slovenian_get.ai">Slovenščina (Slovenian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/spanish_get.ai">Español (Spanish)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/spanish_latam_get.ai">Español Latinoamérica (Spanish Latin America)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/swahili_get.ai">Kiswahili (Swahili)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/swedish_get.ai">Svenska (Swedish)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/thai_get.ai">ภาษาไทย (Thai)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/turkish_get.ai">Türkçe (Turkish)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/uk_generic_rgb_wo.ai">Українська (Ukrainian)</a><br/>
+ <a href="{@docRoot}downloads/brand/vi_generic_rgb_wo.ai">Tiếng Việt (Vietnamese)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/zulu_get.ai">isiZulu (Zulu)</a><br/>
+
+</div>
+<div style="clear:left"> </div>
+
+
+
+
+
+
+
+
+
+<hr>
+<img src="{@docRoot}images/brand/en_app_rgb_wo_60.png" alt="Android App On Google Play">
+
+<div style="clear:left"> </div>
+
+<div class="col-4" style="margin-left:0">
+
+ <a href="{@docRoot}downloads/brand/v2/english_app.ai">English (English)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/afrikaans_app.ai">Afrikaans (Afrikaans)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/amharic_app.ai">ኣማርኛ (Amharic)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/arabic_app.ai">العربية (Arabic)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/belarusian_app.ai">Беларуская (Belarusian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/bulgarian_app.ai">български (Bulgarian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/catalan_app.ai">Català (Catalan)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/traditional_chinese_app.ai">中文 (中国) (Chinese)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/hongkong_chinese_app.ai">中文(香港) (Chinese Hong Kong)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/taiwan_chinese_app.ai">中文 (台灣) (Chinese Taiwan)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/croatian_app.ai">Hrvatski (Croatian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/czech_app.ai">Česky (Czech)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/danish_app.ai">Dansk (Danish)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/dutch_app.ai">Nederlands (Dutch)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/estonian_app.ai">Eesti keel (Estonian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/farsi_app.ai">فارسی (Farsi Persian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/filipino_app.ai">Tagalog (Filipino)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/finnish_app.ai">Suomi (Finnish)</a><br/>
+
+</div>
+
+<div class="col-4">
+
+ <a href="{@docRoot}downloads/brand/v2/french_app.ai">Français (French)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/german_app.ai">Deutsch (German)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/greek_app.ai">Ελληνικά (Greek)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/hebrew_app.ai">עברית (Hebrew)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/hindi_app.ai">हिन्दी (Hindi)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/hungarian_app.ai">Magyar (Hungarian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/indonesian_app.ai">Bahasa Indonesia (Indonesian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/italian_app.ai">Italiano (Italian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/japanese_app.ai">日本語 (Japanese)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/korean_app.ai">한국어 (Korean)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/latvian_app.ai">Latviski (Latvian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/lithuanian_app.ai">Lietuviškai (Lithuanian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/malay_app.ai">Bahasa Melayu (Malay)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/norwegian_app.ai">Norsk (Norwegian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/polish_app.ai">Polski (Polish)</a><br/>
+
+
+</div>
+
+<div class="col-4" style="margin-right:0">
+
+ <a href="{@docRoot}downloads/brand/v2/portugal_portuguese_app.ai">Português (Portuguese)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/brazilian_portuguese_app.ai">Português Brasil (Portuguese Brazil)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/romanian_app.ai">Românã (Romanian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/russian_app.ai">Pусский (Russian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/serbian_app.ai">Српски / srpski (Serbian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/slovak_app.ai">Slovenčina (Slovak)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/slovenian_app.ai">Slovenščina (Slovenian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/spanish_app.ai">Español (Spanish)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/spanish_latam_app.ai">Español Latinoamérica (Spanish Latin America)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/swahili_app.ai">Kiswahili (Swahili)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/swedish_app.ai">Svenska (Swedish)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/thai_app.ai">ภาษาไทย (Thai)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/turkish_app.ai">Türkçe (Turkish)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/ukranian_app.ai">Українська (Ukrainian)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/vietnamese_app.ai">Tiếng Việt (Vietnamese)</a><br/>
+
+ <a href="{@docRoot}downloads/brand/v2/zulu_app.ai">isiZulu (Zulu)</a><br/>
+
+</div>
+<div style="clear:left"> </div>
+
+
+
+
+
+
+<h2>Guidelines</h2>
+
+ <ul>
+ <li>Do not modify the color, proportions, spacing or any other aspect of the badge image.
+ </li>
+ <li>When used alongside logos for other application marketplaces, the Google Play logo
+ should be of equal or greater size.</li>
+ <li>When used online, the badge should link to either:
+ <ul>
+ <li>A list of products published by you, for example:<br />
+ <span style="margin-left:1em;">http://play.google.com/store/search?q=<em>publisherName</em></span>
+ </li>
+ <li>A specific app product details page within Google Play, for example:<br />
+ <span style="margin-left:1em;">http://play.google.com/store/apps/details?id=<em>packageName</em></span>
+ </li>
+ </ul>
+ </li>
+ </ul>
+
+<p>For more information, see the
+<a href="{@docRoot}distribute/tools/promote/brand.html#brand-google_play">Brand
+Guidelines</a>.
+
+
+<p>To quickly create a badge that links to your apps on Google Play,
+use the <a
+href="{@docRoot}distribute/tools/promote/badges.html">Googe Play badge generator</a>.</p>
+
+
+
\ No newline at end of file
diff --git a/docs/html/distribute/tools/promote/badges.jd b/docs/html/distribute/tools/promote/badges.jd
new file mode 100644
index 0000000..e91a804
--- /dev/null
+++ b/docs/html/distribute/tools/promote/badges.jd
@@ -0,0 +1,362 @@
+page.title=Google Play Badge Generator
+page.image=/images/gp-badges-set.png
+page.metaDescription=Build badges for your app in just a few clicks, or download hi-res badge assets localized for a variety of languages.
+meta.tags="disttools, promoting, deviceart, marketing, googleplay"
+page.tags="badge, google play"
+
+@jd:body
+
+<p itemprop="description">Google Play badges enable you to promote your apps with
+official branding in your online ads, promotional materials, or anywhere you want
+a link to your apps</p>
+
+<p>In the form below,
+input your app's package name or publisher name, choose the badge style,
+click <em>Build my badge</em>, then paste the HTML into your web content.</p>
+
+<p>If you're creating a promotional web page for your app, you should also use the
+<a href="{@docRoot}distribute/tools/promote/device-art.html">Device Art Generator</a>, which quickly
+wraps your screenshots in real device artwork.</p>
+
+<p>For guidelines when using the Google Play badge and other brand assets,
+see the <a href="{@docRoot}distribute/tools/promote/brand.html#brand-google_play">Brand
+Guidelines</a>.</p>
+
+<style type="text/css">
+
+form.button-form {
+ margin-top:2em;
+}
+
+/* the label and input elements are blocks that float left in order to
+ keep the left edgets of the input aligned, and IE 6/7 do not fully support "inline-block" */
+label.block {
+ display: block;
+ float: left;
+ width: 100px;
+ padding-right: 10px;
+}
+
+input.text {
+ display: block;
+ float: left;
+ width: 250px;
+}
+
+div.button-row {
+ white-space:nowrap;
+ min-height:80px;
+}
+
+div.button-row input {
+ vertical-align:middle;
+ margin:0 5px 0 0;
+}
+
+#jd-content div.button-row img {
+ margin: 0;
+ vertical-align:middle;
+}
+
+</style>
+
+<script type="text/javascript">
+
+// locales for which we have the 'app' badge
+var APP_LANGS = ['it','pt-br','pt-pt','nl','ko','ja','fr','es','es-419','en','de'];
+
+// variables for creating 'try it out' demo button
+var imagePath = "{@docRoot}images/brand/"
+var linkStart = "<a href=\"https://play.google.com/store/";
+var imageStart = "\">\n"
+ + " <img alt=\"";
+ // leaves opening for the alt text value
+var imageSrc = "\"\n src=\"" + imagePath;
+ // leaves opening for the image file name
+var imageEnd = ".png\" />\n</a>";
+
+// variables for creating code snippet
+var linkStartCode = "<a href=\"https://play.google.com/store/";
+var imageStartCode = "\">\n"
+ + " <img alt=\"";
+ // leaves opening for the alt text value
+var imageSrcCode = "\"\n src=\"" + imagePath;
+ // leaves opening for the image file name
+var imageEndCode = ".png\" />\n</a>";
+
+/** Generate the HTML snippet and demo based on form values */
+function buildButton(form) {
+ var lang = $('#locale option:selected').val();
+ var selectedValue = lang + $('form input[type=radio]:checked').val();
+ var altText = selectedValue.indexOf("generic") != -1 ? "Get it on Google Play" : "Android app on Google Play";
+
+ if (form["package"].value != "com.example.android") {
+ $("#preview").show();
+ var packageName = escapeHTML(form["package"].value);
+ $("#snippet").show().html(linkStartCode + "apps/details?id=" + packageName
+ + imageStartCode + altText + imageSrcCode
+ + selectedValue + imageEndCode);
+ $("#button-preview").html(linkStart + "apps/details?id=" + packageName
+ + imageStart + altText + imageSrc
+ + selectedValue + imageEnd);
+
+ // Send the event to Analytics
+ _gaq.push(['_trackEvent', 'Distribute', 'Create Google Play Badge', 'Package ' + selectedValue]);
+ } else if (form["publisher"].value != "Example, Inc.") {
+ $("#preview").show();
+ var publisherName = escapeHTML(form["publisher"].value);
+ $("#snippet").show().html(linkStartCode + "search?q=pub:" + publisherName
+ + imageStartCode + altText + imageSrcCode
+ + selectedValue + imageEndCode);
+ $("#button-preview").html(linkStart + "search?q=pub:" + publisherName
+ + imageStart + altText + imageSrc
+ + selectedValue + imageEnd);
+
+ // Send the event to Analytics
+ _gaq.push(['_trackEvent', 'Distribute', 'Create Google Play Badge', 'Publisher ' + selectedValue]);
+ } else {
+ alert("Please enter your package name or publisher name");
+ }
+ return false;
+}
+
+/** Listen for Enter key */
+function onTextEntered(event, form, me) {
+ // 13 = enter
+ if (event.keyCode == 13) {
+ buildButton(form);
+ }
+}
+
+/** When input is focused, remove example text and disable other input */
+function onInputFocus(object, example) {
+ if (object.value == example) {
+ $(object).val('').css({'color' : '#000'});
+ }
+ $('input[type="text"]:not(input[name='+object.name+'])',
+ object.parentNode).attr('disabled','true');
+ $('#'+object.name+'-clear').show();
+}
+
+/** When input is blured, restore example text if appropriate and enable other input */
+function onInputBlur(object, example) {
+ if (object.value.length < 1) {
+ $(object).attr('value',example).css({'color':'#ccc'});
+ $('input[type="text"]', object.parentNode).removeAttr('disabled');
+ $('#'+object.name+'-clear').hide();
+ }
+}
+
+/** Clear the form to start over */
+function clearLabel(id, example) {
+ $("#preview").hide();
+ $('#'+id+'').html('').attr('value',example).css({'color':'#ccc'});
+ $('input[type="text"]', $('#'+id+'').parent()).removeAttr('disabled');
+ $('#'+id+'-clear').hide();
+ return false;
+}
+
+/** Switch the badge urls for selected language */
+function changeBadgeLang() {
+ var lang = $('#locale option:selected').val();
+
+ // check if we have the 'app' badge for this lang and show notice if not
+ $("div.button-row.error").remove(); // remove any existing instance of error message
+ if ($.inArray(lang,APP_LANGS) == -1) {
+ $("div.button-row.app").hide();
+ $("div.button-row.app").after('<div class="button-row error"><p class="note" style="margin:1em 0 -1em">'
+ + 'Sorry, we currently don\'t have the '
+ + '<em>Android app on Google Play</em> badge translated for '
+ + $("select#locale option[value="+lang+"]").attr("title")
+ + '.<br>Please check back later or instead use the <em>Get it on Google Play</em> badge below.'
+ + '</p></div>');
+ } else {
+ $("div.button-row.app").show(); // show the 'app' badge row
+ }
+
+ $('.button-row img').each(function() {
+ var id = $(this).parent().attr('for');
+ var imgName = lang + $('input#'+id).attr('value') + '.png';
+ var lastSlash = $(this).attr('src').lastIndexOf('/');
+ var imgPath = $(this).attr('src').substring(0, lastSlash+1);
+ $(this).attr('src', imgPath + imgName);
+ });
+}
+
+/** When the doc is ready, find the inputs and color the input grey if the value is the example
+ text. This is necessary to handle back-navigation, which can auto-fill the form with previous
+ values (and text should not be grey) */
+$(document).ready(function() {
+ $(".button-form input.text").each(function(index) {
+ if ($(this).val() == $(this).attr("default")) {
+ $(this).css("color","#ccc");
+ } else {
+ /* This is necessary to handle back-navigation to the page after form was filled */
+ $('input[type="text"]:not(input[name='+this.name+'])',
+ this.parentNode).attr('disabled','true');
+ $('#'+this.name+'-clear').show();
+ }
+ });
+});
+
+</script>
+
+<form class="button-form">
+ <label class="block" for="locale">Language:</label>
+ <select id="locale" style="display:block;float:left;margin:0"
+ onchange="changeBadgeLang()">
+ <option title="Afrikaans"
+ value="af">Afrikaans</option>
+ <option title="Arabic"
+ value="ar">العربية</option>
+ <option title="Belarusian"
+ value="be">Беларуская</option>
+ <option title="Bulgarian"
+ value="bg">Български</option>
+ <option title="Catalan"
+ value="ca">Català</option>
+ <option title="Chinese (China)"
+ value="zh-cn">中文 (中国)</option>
+ <option title="Chinese (Hong Kong)"
+ value="zh-hk">中文(香港)</option>
+ <option title="Chinese (Taiwan)"
+ value="zh-tw">中文 (台灣)</option>
+ <option title="Croatian"
+ value="hr">Hrvatski</option>
+ <option title="Czech"
+ value="cs">Česky</option>
+ <option title="Danish"
+ value="da">Dansk</option>
+ <option title="Dutch"
+ value="nl">Nederlands</option>
+ <option title="Estonian"
+ value="et">Eesti</option>
+ <option title="Farsi - Persian"
+ value="fa">فارسی</option>
+ <option title="Filipino"
+ value="fil">Tagalog</option>
+ <option title="Finnish"
+ value="fi">Suomi</option>
+ <option title="French"
+ value="fr">Français</option>
+ <option title="German"
+ value="de">Deutsch</option>
+ <option title="Greek"
+ value="el">Ελληνικά</option>
+ <option title="English"
+ value="en" selected="true">English</option>
+<!--
+ <option title="Hebrew"
+ value="iw-he">עברית</option>
+-->
+ <option title="Hungarian"
+ value="hu">Magyar</option>
+ <option title="Indonesian"
+ value="id-in">Bahasa Indonesia</option>
+ <option title="Italian"
+ value="it">Italiano</option>
+ <option title="Japanese"
+ value="ja">日本語</option>
+ <option title="Korean"
+ value="ko">한국어</option>
+ <option title="Latvian"
+ value="lv">Latviešu</option>
+ <option title="Lithuanian"
+ value="lt">Lietuviškai</option>
+ <option title="Malay"
+ value="ms">Bahasa Melayu</option>
+ <option title="Norwegian"
+ value="no">Norsk (bokmål)</option>
+ <option title="Polish"
+ value="pl">Polski</option>
+ <option title="Portuguese (Brazil)"
+ value="pt-br">Português (Brasil)</option>
+ <option title="Portuguese (Portugal)"
+ value="pt-pt">Português (Portugal)</option>
+ <option title="Romanian"
+ value="ro">Română</option>
+ <option title="Russian"
+ value="ru">Русский</option>
+ <option title="Serbian"
+ value="sr">Српски / srpski</option>
+ <option title="Slovak"
+ value="sk">Slovenčina</option>
+ <option title="Slovenian"
+ value="sl">Slovenščina</option>
+ <option title="Spanish (Spain)"
+ value="es">Español (España)</option>
+ <option title="Spanish (Latin America)"
+ value="es-419">Español (Latinoamérica)</option>
+ <option title="Swedish"
+ value="sv">Svenska</option>
+ <option title="Swahili"
+ value="sw">Kiswahili</option>
+ <option title="Thai"
+ value="th">ไทย</option>
+ <option title="Turkish"
+ value="tr">Türkçe</option>
+ <option title="Ukrainian"
+ value="uk">Українська</option>
+ <option title="Vietnamese"
+ value="vi">Tiếng Việt</option>
+ <option title="Zulu"
+ value="zu">isiZulu</option>
+ </select>
+ <p style="clear:both;margin:0"> </p>
+ <label class="block" for="package" style="clear:left">Package name:</label>
+ <input class="text" type="text" id="package" name="package"
+ value="com.example.android"
+ default="com.example.android"
+ onfocus="onInputFocus(this, 'com.example.android')"
+ onblur="onInputBlur(this, 'com.example.android')"
+ onkeyup="return onTextEntered(event, this.parentNode, this)"/>
+ <a id="package-clear" style="display:none" href="#"
+ onclick="return clearLabel('package','com.example.android');">clear</a>
+ <p style="clear:both;margin:0"> <em>or</em></p>
+ <label class="block" style="margin-top:5px" for="publisher">Publisher name:</label>
+ <input class="text" type="text" id="publisher" name="publisher"
+ value="Example, Inc."
+ default="Example, Inc."
+ onfocus="onInputFocus(this, 'Example, Inc.')"
+ onblur="onInputBlur(this, 'Example, Inc.')"
+ onkeyup="return onTextEntered(event, this.parentNode, this)"/>
+ <a id="publisher-clear" style="display:none" href="#"
+ onclick="return clearLabel('publisher','Example, Inc.');">clear</a>
+ <br/><br/>
+
+
+<div class="button-row app">
+ <input type="radio" name="buttonStyle" value="_app_rgb_wo_45" id="ws" />
+ <label for="ws"><img src="{@docRoot}images/brand/en_app_rgb_wo_45.png"
+alt="Android app on Google Play (small)" /></label>
+
+ <input type="radio" name="buttonStyle" value="_app_rgb_wo_60" id="wm" />
+ <label for="wm"><img src="{@docRoot}images/brand/en_app_rgb_wo_60.png"
+alt="Android app on Google Play (large)" /></label>
+</div>
+
+<div class="button-row">
+ <input type="radio" name="buttonStyle" value="_generic_rgb_wo_45" id="ns" checked="checked" />
+ <label for="ns"><img src="{@docRoot}images/brand/en_generic_rgb_wo_45.png"
+alt="Get it on Google Play (small)" /></label>
+
+ <input type="radio" name="buttonStyle" value="_generic_rgb_wo_60" id="nm" />
+ <label for="nm"><img src="{@docRoot}images/brand/en_generic_rgb_wo_60.png"
+alt="Get it on Google Play (large)" /></label>
+</div>
+
+ <input class="button" onclick="return buildButton(this.parentNode);"
+ type="button" value="Build my badge" style="padding:10px" />
+ <br/>
+</form>
+
+<div id="preview" style="display:none">
+ <p>Copy and paste this HTML into your web site:</p>
+ <textarea id="snippet" cols="100" rows="5" onclick="this.select()"
+style="font-family:monospace;background-color:#efefef;padding:5px;display:none;margin-bottom:1em">
+ </textarea >
+
+<p>Try it out:</p>
+<div id="button-preview" style="margin-top:1em"></div>
+</div>
+
diff --git a/docs/html/distribute/tools/promote/brand.jd b/docs/html/distribute/tools/promote/brand.jd
new file mode 100644
index 0000000..2116c0f1
--- /dev/null
+++ b/docs/html/distribute/tools/promote/brand.jd
@@ -0,0 +1,195 @@
+page.title=Brand Guidelines
+page.image=/assets/images/resource-card-default-android.jpg
+page.metaDescription=Guidelines and downloads for the Android and Google Play brands.
+page.tags="brand, bugdroid, assets"
+
+@jd:body
+
+<p>We encourage you to use the Android and Google Play brands with your Android app
+promotional materials. You can use the icons and other assets on this page
+provided that you follow the guidelines.</p>
+
+<h2 id="brand-android">Android</h2>
+
+ <p>The following are guidelines for the Android brand
+ and related assets.</p>
+
+
+ <h4 style="clear:right">Android in text</h4>
+
+ <div style="float:right;clear:right;width:200px;margin:0 0 20px 30px">
+ <img alt="" src="{@docRoot}images/brand/mediaplayer.png">
+ </div>
+ <ul>
+ <li>Android™ should have a trademark symbol the first time it appears in a creative.</li>
+ <li>Android should always be capitalized and is never plural or possessive.</li>
+ <li>"Android" cannot be used in names of applications or accessory products,
+ including phones, tablets, TVs, speakers, headphones, watches, and other devices. Instead use "for Android".
+ <ul>
+ <li><span style="color:red">Incorrect</span>: "Android MediaPlayer"</li>
+ <li><span style="color:green">Correct</span>: "MediaPlayer for Android"</li>
+ </ul>
+ <p>If used with your logo, "for Android" needs to be smaller in size than your logo.
+ First instance of this use should be followed by a TM symbol, "for Android™".</p>
+ </li>
+ <li>Android may be used as a descriptor, as long as it is followed by a proper generic term.
+ <ul>
+ <li><span style="color:red">Incorrect</span>: "Android MediaPlayer" or "Android XYZ app"</li>
+ <li><span style="color:green">Correct</span>: "Android features" or "Android applications"</li>
+ </ul>
+ </li>
+ </ul>
+
+ <p>Any use of the Android name needs to include this
+ attribution in your communication:</p>
+ <blockquote><em>Android is a trademark of Google Inc.</em></blockquote></p>
+
+
+ <h4>Android robot</h4>
+
+ <div style="float:right;width:200px;margin-left:30px">
+ <img alt="" src="{@docRoot}images/brand/Android_Robot_100.png"
+ style="margin-left:50px">
+ <p style="text-align:center">
+ <a href="{@docRoot}images/brand/Android_Robot_100.png">100x118</a> |
+ <a href="{@docRoot}images/brand/Android_Robot_200.png">200x237</a><br>
+ <a href="{@docRoot}downloads/brand/Android_Robot_outlined.ai">Illustrator (.ai)</a></p>
+ </div>
+
+ <p>The Android robot can be used, reproduced, and modified freely in marketing
+ communications. The color value for print is PMS 376C and the online hex
+ color is <span style="color:#A4C639">#A4C639</span>.</p>
+
+ <p>When using the Android Robot or any modification of it, proper attribution is
+ required under the terms of the <a href="http://creativecommons.org/licenses/by/3.0/">Creative
+Commons Attribution</a> license:</p>
+
+ <blockquote><em>The Android robot is reproduced or modified from work created and shared by Google and
+used according to terms described in the Creative Commons 3.0 Attribution License.</em></blockquote>
+
+ <p>You may not file trademark applications incorporating the Android robot logo or
+derivatives thereof. We want to ensure that the Android robot remains available
+for all to use.</p>
+
+
+<h4 style="clear:right">Android logo</h4>
+
+<div style="float:right;width:210px;margin-left:30px;margin-top:-10px">
+ <img alt="" src="{@docRoot}images/brand/android_logo_no.png">
+</div>
+
+<p>The Android logo may not be used. Nor can this be used with the Android robot.</p>
+<p>The custom typeface may not be used.</p>
+
+
+
+
+<h2 id="brand-google_play">Google Play</h2>
+
+
+ <p>The following are guidelines for the Google Play brand
+ and related assets.</p>
+
+<h4>Google Play in text</h4>
+
+<p>Always include a TM symbol on the first or most prominent instance of Google Play™
+in text.</p>
+
+<p>When referring to the mobile experience, use "Google Play" unless the text is clearly
+instructional for the user. For example, a marketing headline might read "Download our
+games on Google Play™," but instructional text would read "Download our games using the Google
+Play™ Store app."
+
+ <p>Any use of the Google Play name or icon needs to include this
+ attribution in your communication:</p>
+
+<blockquote><em>Google Play is a trademark of Google Inc.</em></blockquote>
+
+
+ <div style="float:right;width:96px;margin-left:30px;margin-top:-20px">
+ <img src="{@docRoot}images/brand/Google_Play_Store_96.png" alt="">
+ <p style="text-align:center">
+ <a href="{@docRoot}images/brand/Google_Play_Store_48.png">48x48</a> |
+ <a href="{@docRoot}images/brand/Google_Play_Store_96.png">96x96</a><br>
+ <a href="{@docRoot}downloads/brand/Google_Play_Store.ai">Illustrator (.ai)</a>
+ </p>
+ </div>
+
+<h4>Google Play Store icon</h4>
+
+<p>You may use the Google Play Store icon, but you may not modify it.</p>
+
+<p>As mentioned above, when referring to the Google Play Store app in copy, use the full name:
+"Google Play Store." However, when labeling the Google Play Store icon directly, it's OK to use
+"Play Store" alone to accurately reflect the icon label as it appears on a device.</p>
+
+
+<h4>Google Play badge</h4>
+
+ <div style="float:right;clear:right;width:172px;margin-left:30px">
+ <img src="{@docRoot}images/brand/en_app_rgb_wo_60.png" alt="">
+ <p style="text-align:center">
+ <a href="{@docRoot}images/brand/en_app_rgb_wo_45.png">129x45</a> |
+ <a href="{@docRoot}images/brand/en_app_rgb_wo_60.png">172x60</a></p>
+ </div>
+
+ <div style="float:right;clear:right;width:172px;margin-left:30px">
+ <img src="{@docRoot}images/brand/en_generic_rgb_wo_60.png" alt="">
+ <p style="text-align:center">
+ <a href="{@docRoot}images/brand/en_generic_rgb_wo_45.png">129x45</a> |
+ <a href="{@docRoot}images/brand/en_generic_rgb_wo_60.png">172x60</a></p>
+ </div>
+
+ <p>The "Get it on Google Play" and "Android App on Google Play" logos are badges that you
+ can use on your website and promotional materials, to point to your products on Google
+ Play.</p>
+
+ <ul>
+ <li>Don't modify the color, proportions, spacing, or any other aspect of the badge image.
+ </li>
+ <li>When used alongside logos for other application marketplaces, the Google Play logo
+ should be of equal or greater size.</li>
+ <li>When used online, the badge should link to either:
+ <ul>
+ <li>A list of products published by you, for example:<br />
+ <span style="margin-left:1em;">http://play.google.com/store/search?q=<em>publisherName</em></span>
+ </li>
+ <li>A specific app product details page within Google Play, for example:<br />
+ <span style="margin-left:1em;">http://play.google.com/store/apps/details?id=<em>packageName</em></span>
+ </li>
+ </ul>
+ </li>
+ </ul>
+
+ <p>To quickly create a badge that links to your apps on Google Play,
+ use the <a
+ href="{@docRoot}distribute/tools/promote/badges.html">Googe Play badge generator</a>
+ (provides the badge in over 40 languages).</p>
+
+ <p>To create your own size, download an Adobe® Illustrator® (.ai) file for the
+ <a href="{@docRoot}distribute/tools/promote/badge-files.html">Google Play
+ badge in over 40 languages</a>.</p>
+
+ <p>For details on all the ways that you can link to your product details page in Google Play,
+ see <a href="{@docRoot}distribute/tools/promote/linking.html">Linking to your products</a></p>
+
+
+
+<h2 id="Questions">Questions</h2>
+
+<p>To view our full guidelines or for any further brand usage questions, please contact our
+Android Partner Marketing team:</p>
+<ul>
+ <li>For North and South America, please contact <a
+ href="mailto:android-brand-approvals@google.com?Subject=Brand%20Approval%20Questions"
+ >android-brand-approvals@google.com</a></li>
+
+ <li>For Europe and Emerging Markets, please contact <a
+ href="mailto:emea-android-brand@google.com?Subject=Brand%20Approval%20Questions"
+ >emea-android-brand@google.com</a></li>
+
+ <li>For Asia and Pacific-America, please contact <a
+ href="mailto:apac-android-brand-approvals@google.com?Subject=Brand%20Approval%20Questions"
+ >apac-android-brand-approvals@google.com</a></li>
+</ul>
+
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/thumb.png
Binary files differ
diff --git a/docs/html/distribute/tools/promote/device-art.jd b/docs/html/distribute/tools/promote/device-art.jd
new file mode 100644
index 0000000..b0b5f84
--- /dev/null
+++ b/docs/html/distribute/tools/promote/device-art.jd
@@ -0,0 +1,697 @@
+page.title=Device Art Generator
+page.image=/images/device-art-ex-crop.jpg
+page.metaDescription=Drag and drop screenshots of your app into real device artwork, for better looking promotional images and improved visual context.
+meta.tags="disttools, promoting, deviceart, marketing"
+page.tags="device, deviceart, nexus, assets"
+Xnonavpage=true
+
+@jd:body
+
+<p>The device art generator enables you to quickly wrap app screenshots in real device artwork. This provides better visual context for your app screenshots on your website or in other promotional materials</p>
+
+<p class="note"><strong>Note</strong>: Do <em>not</em> use graphics created here in your 1024x500
+feature image or screenshots for your Google Play app listing.</p>
+
+<hr>
+
+<div class="supported-browser">
+
+<div class="layout-content-row">
+ <div class="layout-content-col span-3">
+ <h4>Step 1</h4>
+ <p>Drag a screenshot from your desktop onto a device to the right.</p>
+ </div>
+ <div class="layout-content-col span-10">
+ <ul class="device-list primary"></ul>
+ <a href="#" id="archive-expando">Older devices</a>
+ <ul class="device-list archive"></ul>
+ </div>
+</div>
+
+<hr>
+
+<div class="layout-content-row">
+ <div class="layout-content-col span-3">
+ <h4>Step 2</h4>
+ <p>Customize the generated image and drag it to your desktop to save.</p>
+ <p id="frame-customizations">
+ <input type="checkbox" id="output-shadow" checked="checked" class="form-field-checkbutton">
+ <label for="output-shadow">Shadow</label><br>
+ <input type="checkbox" id="output-glare" checked="checked" class="form-field-checkbutton">
+ <label for="output-glare">Screen Glare</label><br><br>
+ <a class="button" id="rotate-button">Rotate</a>
+ </p>
+ </div>
+ <div class="layout-content-col span-10">
+ <!-- position:relative fixes an issue where dragging an image out of a inline-block container
+ produced no drag feedback image in Chrome 28. -->
+ <div id="output" style="position:relative">No input image.</div>
+ </div>
+</div>
+
+</div>
+
+<div class="unsupported-browser" style="display: none">
+ <p class="warning"><strong>Error:</strong> This page requires
+ <span id="unsupported-browser-reason">certain features</span>, which your web browser
+ doesn't support. To continue, navigate to this page on a supported web browser, such as
+ <strong>Google Chrome</strong>.</p>
+ <a href="https://www.google.com/chrome/" class="button">Get Google Chrome</a>
+ <br><br>
+</div>
+
+<style>
+ h4 {
+ text-transform: uppercase;
+ }
+
+ .device-list {
+ padding: 0;
+ margin: 0;
+ }
+
+ .device-list li {
+ display: inline-block;
+ vertical-align: bottom;
+ margin: 0;
+ margin-right: 20px;
+ text-align: center;
+ }
+
+ .device-list li .thumb-container {
+ display: inline-block;
+ }
+
+ .device-list li .thumb-container img {
+ margin-bottom: 8px;
+ opacity: 0.6;
+
+ -webkit-transition: -webkit-transform 0.2s, opacity 0.2s;
+ -moz-transition: -moz-transform 0.2s, opacity 0.2s;
+ transition: transform 0.2s, opacity 0.2s;
+ }
+
+ .device-list li.drag-hover .thumb-container img {
+ opacity: 1;
+
+ -webkit-transform: scale(1.1);
+ -moz-transform: scale(1.1);
+ transform: scale(1.1);
+ }
+
+ .device-list li .device-details {
+ font-size: 13px;
+ line-height: 16px;
+ color: #888;
+ }
+
+ .device-list li .device-url {
+ font-weight: bold;
+ }
+
+ #archive-expando {
+ display: block;
+ font-size: 13px;
+ font-weight: bold;
+ color: #333;
+ text-transform: uppercase;
+ margin-top: 16px;
+ padding-top: 16px;
+ padding-left: 28px;
+ border-top: 1px solid transparent;
+ background: transparent url({@docRoot}assets/images/styles/disclosure_down.png)
+ no-repeat scroll 0 8px;
+ -webkit-transition: border 0.2s;
+ -moz-transition: border 0.2s;
+ transition: border 0.2s;
+ }
+
+ #archive-expando.expanded {
+ background-image: url({@docRoot}assets/images/styles/disclosure_up.png);
+ border-top: 1px solid #ccc;
+ }
+
+ .device-list.archive {
+ max-height: 0;
+ overflow: hidden;
+ opacity: 0;
+
+ -webkit-transition: max-height 0.2s, opacity 0.2s;
+ -moz-transition: max-height 0.2s, opacity 0.2s;
+ transition: max-height 0.2s, opacity 0.2s;
+ }
+
+ .device-list.archive.expanded {
+ opacity: 1;
+ max-height: 300px;
+ }
+
+ #output {
+ color: #f44;
+ font-style: italic;
+ }
+
+ #output img {
+ max-height: 500px;
+ }
+</style>
+<script>
+ // Global variables
+ var g_currentImage;
+ var g_currentDevice;
+ var g_currentObjectURL;
+ var g_currentBlob;
+
+ // Global constants
+ var MSG_INVALID_INPUT_IMAGE = 'Invalid screenshot provided. Screenshots must be PNG files '
+ + 'matching the target device\'s screen aspect ratio in either portrait or landscape.';
+ var MSG_NO_INPUT_IMAGE = 'Drag a screenshot (in PNG format) from your desktop onto a '
+ + 'target device above.'
+ var MSG_GENERATING_IMAGE = 'Generating device art…';
+
+ var MAX_DISPLAY_HEIGHT = 126; // XOOM, to fit into 200px wide
+
+ // Device manifest.
+ var DEVICES = [
+ {
+ id: 'nexus_5',
+ title: 'Nexus 5',
+ url: 'http://www.google.com/nexus/5/',
+ physicalSize: 5,
+ physicalHeight: 5.43,
+ density: 'XXHDPI',
+ landRes: ['shadow', 'back', 'fore'],
+ landOffset: [436,306],
+ portRes: ['shadow', 'back', 'fore'],
+ portOffset: [304,436],
+ portSize: [1080,1920],
+ },
+ {
+ id: 'nexus_7',
+ title: 'Nexus 7',
+ url: 'http://www.google.com/nexus/7/',
+ physicalSize: 7,
+ physicalHeight: 8,
+ actualResolution: [1200,1920],
+ density: 'XHDPI',
+ landRes: ['shadow', 'back', 'fore'],
+ landOffset: [326,245],
+ portRes: ['shadow', 'back', 'fore'],
+ portOffset: [244,326],
+ portSize: [800,1280]
+ },
+ {
+ id: 'nexus_10',
+ title: 'Nexus 10',
+ url: 'http://www.google.com/nexus/10/',
+ physicalSize: 10,
+ physicalHeight: 7,
+ actualResolution: [1600,2560],
+ density: 'XHDPI',
+ landRes: ['shadow', 'back', 'fore'],
+ landOffset: [227,217],
+ portRes: ['shadow', 'back', 'fore'],
+ portOffset: [217,223],
+ portSize: [800,1280]
+ },
+ {
+ id: 'xoom',
+ title: 'Motorola XOOM',
+ url: 'http://www.google.com/phone/detail/motorola-xoom',
+ physicalSize: 10,
+ physicalHeight: 6.61,
+ density: 'MDPI',
+ landRes: ['shadow', 'back', 'fore'],
+ landOffset: [218,191],
+ portRes: ['shadow', 'back', 'fore'],
+ portOffset: [199,200],
+ portSize: [800,1280],
+ archived: true
+ },
+ {
+ id: 'nexus_7_2012',
+ title: 'Nexus 7 (2012)',
+ url: 'http://www.google.com/nexus/7/',
+ physicalSize: 7,
+ physicalHeight: 7.81,
+ density: '213dpi',
+ landRes: ['shadow', 'back', 'fore'],
+ landOffset: [315,270],
+ portRes: ['shadow', 'back', 'fore'],
+ portOffset: [264,311],
+ portSize: [800,1280],
+ archived: true
+ },
+ {
+ id: 'nexus_4',
+ title: 'Nexus 4',
+ url: 'http://www.google.com/nexus/4/',
+ physicalSize: 4.7,
+ physicalHeight: 5.27,
+ density: 'XHDPI',
+ landRes: ['shadow', 'back', 'fore'],
+ landOffset: [349,214],
+ portRes: ['shadow', 'back', 'fore'],
+ portOffset: [213,350],
+ portSize: [768,1280],
+ archived: true
+ },
+ {
+ id: 'galaxy_nexus',
+ title: 'Galaxy Nexus',
+ url: 'http://www.android.com/devices/detail/galaxy-nexus',
+ physicalSize: 4.65,
+ physicalHeight: 5.33,
+ density: 'XHDPI',
+ landRes: ['shadow', 'back', 'fore'],
+ landOffset: [371,199],
+ portRes: ['shadow', 'back', 'fore'],
+ portOffset: [216,353],
+ portSize: [720,1280],
+ archived: true
+ },
+ {
+ id: 'nexus_s',
+ title: 'Nexus S',
+ url: 'http://www.google.com/phone/detail/nexus-s',
+ physicalSize: 4.0,
+ physicalHeight: 4.88,
+ density: 'HDPI',
+ landRes: ['shadow', 'back', 'fore'],
+ landOffset: [247,135],
+ portRes: ['shadow', 'back', 'fore'],
+ portOffset: [134,247],
+ portSize: [480,800],
+ archived: true
+ }
+ ];
+
+ DEVICES = DEVICES.sort(function(x, y) { return x.physicalSize - y.physicalSize; });
+
+ var MAX_HEIGHT = 0;
+ for (var i = 0; i < DEVICES.length; i++) {
+ MAX_HEIGHT = Math.max(MAX_HEIGHT, DEVICES[i].physicalHeight);
+ }
+
+ // Setup performed once the DOM is ready.
+ $(document).ready(function() {
+ if (!checkBrowser()) {
+ return;
+ }
+
+ polyfillCanvasToBlob();
+ setupUI();
+
+ // Set up Chrome drag-out
+ $.event.props.push("dataTransfer");
+ document.body.addEventListener('dragstart', function(e) {
+ var target = e.target;
+ if (target.classList.contains('dragout')) {
+ e.dataTransfer.setData('DownloadURL', target.dataset.downloadurl);
+ }
+ }, false);
+ });
+
+ /**
+ * Returns the device from DEVICES with the given id.
+ */
+ function getDeviceById(id) {
+ for (var i = 0; i < DEVICES.length; i++) {
+ if (DEVICES[i].id == id)
+ return DEVICES[i];
+ }
+ return;
+ }
+
+ /**
+ * Checks to make sure the browser supports this page. If not,
+ * updates the UI accordingly and returns false.
+ */
+ function checkBrowser() {
+ // Check for browser support
+ var browserSupportError = null;
+
+ // Must have <canvas>
+ var elem = document.createElement('canvas');
+ if (!elem.getContext || !elem.getContext('2d')) {
+ browserSupportError = 'HTML5 canvas.';
+ }
+
+ // Must have FileReader
+ if (!window.FileReader) {
+ browserSupportError = 'desktop file access';
+ }
+
+ if (browserSupportError) {
+ $('.supported-browser').hide();
+
+ $('#unsupported-browser-reason').html(browserSupportError);
+ $('.unsupported-browser').show();
+ return false;
+ }
+
+ return true;
+ }
+
+ function setupUI() {
+ $('#output').html(MSG_NO_INPUT_IMAGE);
+
+ $('#frame-customizations').hide();
+
+ $('#output-shadow, #output-glare').click(function() {
+ createFrame();
+ });
+
+ // Build device list.
+ $.each(DEVICES, function() {
+ var resolution = this.actualResolution || this.portSize;
+ var scaleFactorText = '';
+ if (resolution[0] != this.portSize[0]) {
+ scaleFactorText = '<br>' + (100 * (this.portSize[0] / resolution[0])).toFixed(0) +
+ '% size output';
+ } else {
+ scaleFactorText = '<br> ';
+ }
+
+ $('<li>')
+ .append($('<div>')
+ .addClass('thumb-container')
+ .append($('<img>')
+ .attr('src', 'device-art-resources/' + this.id + '/thumb.png')
+ .attr('height',
+ Math.floor(MAX_DISPLAY_HEIGHT * this.physicalHeight / MAX_HEIGHT))))
+ .append($('<div>')
+ .addClass('device-details')
+ .html((this.url
+ ? ('<a class="device-url" href="' + this.url + '">' + this.title + '</a>')
+ : this.title) +
+ '<br>' + this.physicalSize + '" @ ' + this.density +
+ '<br>' + (resolution[0] + 'x' + resolution[1]) + scaleFactorText))
+ .data('deviceId', this.id)
+ .appendTo(this.archived ? '.device-list.archive' : '.device-list.primary');
+ });
+
+ // Set up "older devices" expando.
+ $('#archive-expando').click(function() {
+ if ($(this).hasClass('expanded')) {
+ $(this).removeClass('expanded');
+ $('.device-list.archive').removeClass('expanded');
+ } else {
+ $(this).addClass('expanded');
+ $('.device-list.archive').addClass('expanded');
+ }
+ return false;
+ });
+
+ // Set up drag and drop.
+ $('.device-list li')
+ .live('dragover', function(evt) {
+ $(this).addClass('drag-hover');
+ evt.dataTransfer.dropEffect = 'link';
+ evt.preventDefault();
+ })
+ .live('dragleave', function(evt) {
+ $(this).removeClass('drag-hover');
+ })
+ .live('drop', function(evt) {
+ $('#output').empty().html(MSG_GENERATING_IMAGE);
+ $(this).removeClass('drag-hover');
+ g_currentDevice = getDeviceById($(this).closest('li').data('deviceId'));
+ evt.preventDefault();
+ loadImageFromFileList(evt.dataTransfer.files, function(data) {
+ if (data == null) {
+ $('#output').html(MSG_INVALID_INPUT_IMAGE);
+ return;
+ }
+ loadImageFromUri(data.uri, function(img) {
+ g_currentFilename = data.name;
+ g_currentImage = img;
+ createFrame();
+ // Send the event to Analytics
+ _gaq.push(['_trackEvent', 'Distribute', 'Create Device Art', g_currentDevice.title]);
+ });
+ });
+ });
+
+ // Set up rotate button.
+ $('#rotate-button').click(function() {
+ if (!g_currentImage) {
+ return;
+ }
+
+ var w = g_currentImage.naturalHeight;
+ var h = g_currentImage.naturalWidth;
+ var canvas = $('<canvas>')
+ .attr('width', w)
+ .attr('height', h)
+ .get(0);
+
+ var ctx = canvas.getContext('2d');
+ ctx.rotate(-Math.PI / 2);
+ ctx.translate(-h, 0);
+ ctx.drawImage(g_currentImage, 0, 0);
+
+ loadImageFromUri(canvas.toDataURL('image/png'), function(img) {
+ g_currentImage = img;
+ createFrame();
+ });
+ });
+ }
+
+ /**
+ * Generates the frame from the current selections (g_currentImage and g_currentDevice).
+ */
+ function createFrame() {
+ var port;
+
+ var aspect1 = g_currentImage.naturalWidth / g_currentImage.naturalHeight;
+ var aspect2 = g_currentDevice.portSize[0] / g_currentDevice.portSize[1];
+
+ if (aspect1 == aspect2) {
+ port = true;
+ } else if (aspect1 == 1 / aspect2) {
+ port = false;
+ } else {
+ alert('The screenshot must have an aspect ratio of ' +
+ aspect2.toFixed(3) + ' or ' + (1 / aspect2).toFixed(3) +
+ ' (ideally ' + g_currentDevice.portSize[0] + 'x' + g_currentDevice.portSize[1] +
+ ' or ' + g_currentDevice.portSize[1] + 'x' + g_currentDevice.portSize[0] + ').');
+ $('#output').html(MSG_INVALID_INPUT_IMAGE);
+ return;
+ }
+
+ // Load image resources
+ var res = port ? g_currentDevice.portRes : g_currentDevice.landRes;
+ var resList = {};
+ for (var i = 0; i < res.length; i++) {
+ resList[res[i]] = 'device-art-resources/' + g_currentDevice.id + '/' +
+ (port ? 'port_' : 'land_') + res[i] + '.png'
+ }
+
+ var resourceImages = {};
+ loadImageResources(resList, function(r) {
+ resourceImages = r;
+ continueWithResources_();
+ });
+
+ function continueWithResources_() {
+ var width = resourceImages['back'].naturalWidth;
+ var height = resourceImages['back'].naturalHeight;
+ var offset = port ? g_currentDevice.portOffset : g_currentDevice.landOffset;
+ var size = port
+ ? g_currentDevice.portSize
+ : [g_currentDevice.portSize[1], g_currentDevice.portSize[0]];
+
+ var canvas = document.createElement('canvas');
+ canvas.width = width;
+ canvas.height = height;
+
+ var ctx = canvas.getContext('2d');
+ if (resourceImages['shadow'] && $('#output-shadow').is(':checked')) {
+ ctx.drawImage(resourceImages['shadow'], 0, 0);
+ }
+ ctx.drawImage(resourceImages['back'], 0, 0);
+ ctx.fillStyle = '#000';
+ ctx.fillRect(offset[0], offset[1], size[0], size[1]);
+ ctx.drawImage(g_currentImage, offset[0], offset[1], size[0], size[1]);
+ if (resourceImages['fore'] && $('#output-glare').is(':checked')) {
+ ctx.drawImage(resourceImages['fore'], 0, 0);
+ }
+
+ window.URL = window.URL || window.webkitURL;
+ if (canvas.toBlob && window.URL.createObjectURL) {
+ if (g_currentObjectURL) {
+ window.URL.revokeObjectURL(g_currentObjectURL);
+ g_currentObjectURL = null;
+ }
+ if (g_currentBlob) {
+ if (g_currentBlob.close) {
+ g_currentBlob.close();
+ }
+ g_currentBlob = null;
+ }
+
+ canvas.toBlob(function(blob) {
+ if (!blob) {
+ continueWithFinalUrl_(canvas.toDataURL('image/png'));
+ return;
+ }
+ g_currentBlob = blob;
+ g_currentObjectURL = window.URL.createObjectURL(blob);
+ continueWithFinalUrl_(g_currentObjectURL);
+ }, 'image/png');
+ } else {
+ continueWithFinalUrl_(canvas.toDataURL('image/png'));
+ }
+ }
+
+ function continueWithFinalUrl_(imageUrl) {
+ var filename = g_currentFilename
+ ? g_currentFilename.replace(/^(.+?)(\.\w+)?$/, '$1_framed.png')
+ : 'framed_screenshot.png';
+
+ var $link = $('<a>')
+ .attr('download', filename)
+ .attr('href', imageUrl)
+ .append($('<img>')
+ .addClass('dragout')
+ .attr('src', imageUrl)
+ .attr('draggable', true)
+ .attr('data-downloadurl', ['image/png', filename, imageUrl].join(':')))
+ .appendTo($('#output').empty());
+
+ $('#frame-customizations').show();
+ }
+ }
+
+ /**
+ * Loads an image from a data URI. The callback will be called with the <img> once
+ * it loads.
+ */
+ function loadImageFromUri(uri, callback) {
+ callback = callback || function(){};
+
+ var img = document.createElement('img');
+ img.src = uri;
+ img.onload = function() {
+ callback(img);
+ };
+ img.onerror = function() {
+ callback(null);
+ }
+ }
+
+ /**
+ * Loads a set of images (organized by ID). Once all images are loaded, the callback
+ * is triggered with a dictionary of <img>'s, organized by ID.
+ */
+ function loadImageResources(images, callback) {
+ var imageResources = {};
+
+ var checkForCompletion_ = function() {
+ for (var id in images) {
+ if (!(id in imageResources))
+ return;
+ }
+ (callback || function(){})(imageResources);
+ callback = null;
+ };
+
+ for (var id in images) {
+ var img = document.createElement('img');
+ img.src = images[id];
+ (function(img, id) {
+ img.onload = function() {
+ imageResources[id] = img;
+ checkForCompletion_();
+ };
+ img.onerror = function() {
+ imageResources[id] = null;
+ checkForCompletion_();
+ }
+ })(img, id);
+ }
+ }
+
+ /**
+ * Loads the first valid image from a FileList (e.g. drag + drop source), as a data URI. This
+ * method will throw an alert() in case of errors and call back with null.
+ *
+ * @param {FileList} fileList The FileList to load.
+ * @param {Function} callback The callback to fire once image loading is done (or fails).
+ * @return Returns an object containing 'uri' representing the loaded image. There will also be
+ * a 'name' field indicating the file name, if one is available.
+ */
+ function loadImageFromFileList(fileList, callback) {
+ fileList = fileList || [];
+
+ var file = null;
+ for (var i = 0; i < fileList.length; i++) {
+ if (fileList[i].type.toLowerCase().match(/^image\/(png|jpeg|jpg)/)) {
+ file = fileList[i];
+ break;
+ }
+ }
+
+ if (!file) {
+ alert('Please use a valid screenshot file (PNG or JPEG format).');
+ callback(null);
+ return;
+ }
+
+ var fileReader = new FileReader();
+
+ // Closure to capture the file information.
+ fileReader.onload = function(e) {
+ callback({
+ uri: e.target.result,
+ name: file.name
+ });
+ };
+ fileReader.onerror = function(e) {
+ switch(e.target.error.code) {
+ case e.target.error.NOT_FOUND_ERR:
+ alert('File not found.');
+ break;
+ case e.target.error.NOT_READABLE_ERR:
+ alert('File is not readable.');
+ break;
+ case e.target.error.ABORT_ERR:
+ break; // noop
+ default:
+ alert('An error occurred reading this file.');
+ }
+ callback(null);
+ };
+ fileReader.onabort = function(e) {
+ alert('File read cancelled.');
+ callback(null);
+ };
+
+ fileReader.readAsDataURL(file);
+ }
+
+ /**
+ * Adds a simple version of Canvas.toBlob if toBlob isn't available.
+ */
+ function polyfillCanvasToBlob() {
+ if (!HTMLCanvasElement.prototype.toBlob && window.Blob) {
+ HTMLCanvasElement.prototype.toBlob = function(callback, mimeType, quality) {
+ if (typeof callback != 'function') {
+ throw new TypeError('Function expected');
+ }
+ var dataURL = this.toDataURL(mimeType, quality);
+ mimeType = dataURL.split(';')[0].split(':')[1];
+ var bs = window.atob(dataURL.split(',')[1]);
+ if (dataURL == 'data:,' || !bs.length) {
+ callback(null);
+ return;
+ }
+ for (var ui8arr = new Uint8Array(bs.length), i = 0; i < bs.length; ++i) {
+ ui8arr[i] = bs.charCodeAt(i);
+ }
+ callback(new Blob([ui8arr.buffer /* req'd for Safari */ || ui8arr], {type: mimeType}));
+ };
+ }
+ }
+</script>
diff --git a/docs/html/distribute/tools/promote/linking.jd b/docs/html/distribute/tools/promote/linking.jd
new file mode 100644
index 0000000..025480b
--- /dev/null
+++ b/docs/html/distribute/tools/promote/linking.jd
@@ -0,0 +1,218 @@
+page.title=Linking to Your Products
+page.image=/images/gp-linking-ex-crop.png
+meta.tags="promoting"
+page.tags="linking"
+page.metaDescription=Learn how to build links that take users to your published apps in Google Play from browse or search.
+
+@jd:body
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<a href="badges.html">
+ <img alt="Get it on Google Play"
+ src="{@docRoot}images/brand/en_app_rgb_wo_45.png" />
+</a>
+<p>For a link that includes the Google Play brand icon, check out the <a href="badges.html">Badges</a> page. </p>
+</div>
+</div>
+
+<p>Google Play provides several link formats that let you bring users to your
+products in the way you want, from Android apps, web pages, ads, reviews,
+articles, social media posts, and more.</p>
+
+<p>The link formats let you:</p>
+<ul>
+<li>Link to a specific app's <a href="#OpeningDetails">product details page</a></li>
+<li>Link to a <a href="#OpeningPublisher">list of all of your apps</a>, or</li>
+<li>Link to a <a href="#PerformingSearch">search result</a> of your choice</li>
+<li>Link to a <a href="#OpeningCollection">collection</a> on Google Play</li>
+</ul>
+
+<p>If you are linking from an Android app, you can also control whether the link
+launches the Play Store application or the browser, which takes the user
+to the Google Play website.</p>
+
+<h2 id="OpeningDetails">Linking to a Product Details Page</h2>
+
+<p>Use the format below to deep-link users directly to a specific app's product
+details page. At the product details page, users can see the app description,
+screenshots, reviews and more, and then install it.</p>
+
+<p>To create the link, you need to know the app's fully qualified <em>package
+name</em>, which is declared in the app's <a
+href="{@docRoot}guide/topics/manifest/manifest-element.html#package">manifest
+file</a>. The package name is also visible in the Developer Console. </p>
+
+<dl>
+<dt><strong>From a web site:</strong></dt>
+<dd>
+<pre>http://play.google.com/store/apps/details?id=<package_name></pre>
+</dd>
+<dt><strong>From an Android app:</strong></dt>
+<dd>
+<pre>market://details?id=<package_name></pre>
+</dd>
+</dl>
+
+<p>Here's an example:</p>
+
+<p style="margin-left:1em;"><code><a href="http://play.google.com/store/apps/details?id=com.google.android.apps.maps">http://play.google.com/store/apps/details?id=com.google.android.apps.maps</a></code></p>
+
+<p>For details on how to send the link in an Android app, see <a href="#android-app">Linking from an Android App</a>.</p>
+
+
+
+<h2 id="OpeningPublisher">Linking to a Product List</h2>
+
+<p>Use the format below to link users to a list of apps published by you. The
+product list lets users see all of the apps from a specific publisher, with
+ratings, editorial badges, and an Install button for each. </p>
+
+<p>To create the link, you need to know your <em>publisher name</em>, which is
+available from the Developer Console. </p>
+
+<dl>
+<dt><strong>From a web site:</strong></dt>
+<dd>
+<pre>http://play.google.com/store/search?q=pub:<publisher_name></pre>
+</dd>
+<dt><strong>From an Android app:</strong></dt>
+<dd>
+<pre>market://search?q=pub:<publisher_name></pre>
+</dd>
+</dl>
+
+<p>Here's an example:</p>
+
+<p style="margin-left:1em;"><code><a href="http://play.google.com/store/search?q=pub:Google Inc.">http://play.google.com/store/search?q=pub:Google Inc.</a></code></p>
+
+<p>For details on how to send the link in an Android app, see <a href="#android-app">Linking from an Android App</a>.</p>
+
+
+<h2 id="PerformingSearch">Linking to a Search Result</h2>
+
+<p>Use the format below to link users to a search query result on Google Play.
+The search result page shows a list of apps (and optionally other content) that
+match the query, with ratings, badges, and an Install button for each. </p>
+
+<p>To create the link, you just need a search query string. If you want the
+query to search outside of the Google Play Apps listings, you can remove the
+<code>&c=apps</code> part of the link URL.</p>
+
+<dl>
+<dt><strong>From a web site:</strong></dt>
+<dd>
+<pre>http://play.google.com/store/search?q=<search_query>&c=apps</pre>
+</dd>
+<dt><strong>From an Android app:</strong></dt>
+<dd>
+<pre>market://search?q=<seach_query>&c=apps</pre>
+</dd>
+</dl>
+
+<p>Here's an example:</p>
+
+<p style="margin-left:1em;"><code><a href="http://play.google.com/store/search?q=maps&c=apps">http://play.google.com/store/search?q=maps&c=apps</a></code></p>
+
+<p>For details on how to send the link in an Android app, see <a href="#android-app">Linking from an Android App</a>.</p>
+
+
+
+<h2 id="OpeningCollection">Linking to a Collection</h2>
+
+<p>If your app is featured or appears in one of the Google Play Top charts or
+collections, you can use the format below to link users directly to the
+collection. The collection shows a ranked list of apps in the collection, with
+ratings, short descriptions, and an Install button.</p>
+
+<dl>
+<dt><strong>From a web site:</strong></dt>
+<dd>
+<pre>http://play.google.com/store/apps/collection/<collection_name></pre>
+</dd>
+<dt><strong>From an Android app:</strong></dt>
+<dd>
+<pre>market://apps/collection/<collection_name></pre>
+</dd>
+</dl>
+
+<p>Here's an example:</p>
+
+<p style="margin-left:1em;"><code><a href="http://play.google.com/store/apps/collection/editors_choice">http://play.google.com/store/apps/collection/editors_choice</a></code></p>
+
+<p>For details on how to send the link in an Android app, see <a href="#android-app">Linking from an Android App</a>.</p>
+
+<p class="table-caption"><strong>Table 1.</strong> Collections on Google Play</a>.</p>
+
+<table>
+<tr>
+<th>Collection</th><th>collection_name</th>
+</tr>
+<tr><td>Staff Picks (Featured)</td><td>featured</td></tr>
+<tr><td>Editor's Choice</td><td>editors_choice</td></tr>
+<tr><td>Top Paid</td><td>topselling_paid</td></tr>
+<tr><td>Top Free</td><td>topselling_free</td></tr>
+<tr><td>Top New Free</td><td>topselling_new_free</td></tr>
+<tr><td>Top New Paid</td><td>topselling_new_paid</td></tr>
+<tr><td>Top Grossing</td><td>topgrossing</td></tr>
+<tr><td>Trending</td><td>movers_shakers</td></tr>
+<tr><td>Best Selling in Games</td><td>topselling_paid_game</td></tr>
+</table>
+
+
+<h2 id="android-app">Linking from an Android App</h2>
+
+<p>There are two general formats for links that are accessible to users on
+Android devices, The two formats trigger slightly different behaviors on the
+device:</p>
+
+<ul>
+<li><code>market://</code> Launches the Play Store app to load the
+target page.</li>
+<li><code>http://</code> Lets the user choose whether to launch the
+Play Store app or the browser to handle the request. If the browser handles the
+request, it loads the target page on the Google Play web site.</li>
+</ul>
+
+<p>In general, you should use <code>http://</code> format for links on web pages
+and <code>market://</code> for links in Android apps.</p>
+
+<p>If you want to link to your products from an Android app, create an {@link
+android.content.Intent} that opens a Google Play URL, as shown in the example
+below.</p>
+
+<pre>
+Intent intent = new Intent(Intent.ACTION_VIEW);
+intent.setData(Uri.parse("market://details?id=com.example.android"));
+startActivity(intent);
+</pre>
+
+
+<h2 id="UriSummary">Summary of URL formats</h2>
+
+<p>The table below provides a summary of the URIs currently supported by the Google Play (both on
+the web and in an Android application), as discussed in the previous sections.</p>
+
+<table>
+<tr>
+<th>For this result</th>
+<th>Web page link</th>
+<th>Android app link</th>
+</tr>
+<tr>
+<td style="width:72px;">Show the product details page for a specific app</td>
+<td><code>http://play.google.com/store/apps/details?id=<package_name></code>
+<td><code>market://details?id=<package_name></code></td>
+</tr>
+<tr>
+<td>Show apps by a specific publisher</td>
+<td><nobr><code>http://play.google.com/store/search?q=pub:<publisher_name></code></nobr></td>
+<td><nobr><code>market://search?q=pub:<publisher_name></code></nobr></td>
+</tr>
+<tr>
+<td>Search for apps using a general string query.</td>
+<td><code>http://play.google.com/store/search?q=<query></code></td>
+<td><code>market://search?q=<query></code></td>
+</tr>
+</table>
+
diff --git a/docs/html/distribute/users/build-buzz.jd b/docs/html/distribute/users/build-buzz.jd
new file mode 100644
index 0000000..b76498e
--- /dev/null
+++ b/docs/html/distribute/users/build-buzz.jd
@@ -0,0 +1,301 @@
+page.title=Build Buzz
+page.image=/distribute/images/build-buzz.jpg
+page.metaDescription=Generate interest and demand for your app. Here are some ways to help users find, download, and install your apps.
+page.tags="users, growth, promotion"
+
+@jd:body
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>
+ Contents
+ </h2>
+
+ <ol>
+ <li>
+ <a href="#link-to-your-apps">Link to Your Apps</a>
+ </li>
+ <li>
+ <a href="#use-the-google-play-badge">Use the Badge</a>
+ </li>
+ <li>
+ <a href="#cross-promote-from-your-other-apps">Cross-Promote Your Apps</a>
+ </li>
+ <li>
+ <a href="#hold-a-contest">Hold a Contest</a>
+ </li>
+ <li>
+ <a href="#leverage-pr">Leverage PR</a>
+ </li>
+ <li>
+ <a href="#use-social-media">Use Social Media</a>
+ </li>
+ <li>
+ <a href="#publish-youtube-videos">Publish YouTube Videos</a>
+ </li>
+ <li>
+ <a href="#advertise">Advertise</a>
+ </li>
+ <li>
+ <a href="#maximize-your-marketing-spend">Maximize Your Marketing
+ spend</a>
+ </li>
+ <li><a href="#related-resources">Related Resources</a></li>
+ </ol>
+ </div>
+</div>
+
+<div style="float:right;border 2px solid #ddd;">
+ <img src="{@docRoot}distribute/images/build-buzz.jpg" style=
+ "width:240px;margin:0 0 1.5em 1em;">
+</div>
+
+<p>
+ With more apps published each week in Google Play, building buzz
+ around your own apps helps them get noticed and makes it easier for
+ users to find and download them.
+</p>
+
+<p>
+ Building buzz doesn’t have a single formula. The tools and techniques
+ described here have worked for other developers, but finding the right mix
+ will depend on your apps, your audience, and your competition. And don’t be
+ afraid to try something different or quirky, taking a risk could pay big
+ dividends.
+</p>
+
+<div class="headerLine">
+ <h1 id="link-to-your-apps">
+ Link to Your Apps in Google Play
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ After publishing your apps, you can take Android users directly to your
+ app/games detail page on Google Play by <a href=
+ "{@docRoot}distribute/tools/promote/linking.html">providing links</a> in your
+ social network posts, ad campaigns, app reviews and articles, your website,
+ and more.
+</p>
+
+<p>
+ You can also link to:
+</p>
+
+<ul>
+ <li>A <a href=
+ "{@docRoot}distribute/tools/promote/linking.html#OpeningPublisher">list</a>
+ of all of your apps
+ </li>
+
+ <li>A Google Play <a href=
+ "{@docRoot}distribute/tools/promote/linking.html#PerformingSearch">search
+ result</a>
+ </li>
+
+ <li>A <a href=
+ "{@docRoot}distribute/tools/promote/linking.html#OpeningCollection">collection</a>
+ on Google Play
+ </li>
+</ul>
+
+<div class="headerLine clearfloat">
+ <h1 id="use-the-google-play-badge">
+ Use the Google Play Badge
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure" style="margin:0 3em;">
+ <img src="{@docRoot}images/gp-build-buzz-uplift-1.png">
+</div>
+
+<p>
+ <a href="{@docRoot}distribute/tools/promote/badges.html">Google Play
+ badges</a> are an especially great way let Android users know that your apps
+ are available and link them directly to your Google Play page. Users are more
+ likely to download and trust your apps and games when the Google Play badge
+ is used.
+</p>
+
+<p>Badge your
+ websites, collateral, and ad campaigns. With the badge generator, they're
+ also easy to make and available in multiple languages.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="cross-promote-from-your-other-apps">
+ Cross-Promote from Your Other Apps
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure-right">
+ <img src="{@docRoot}images/gp-buzz-1.jpg">
+ <p class="img-caption">
+ Cross-promoting related apps.
+ </p>
+</div>
+
+<p>
+ Cross promoting, or house ads, is a great cost effective way to get users to
+ try out new titles. Be sure that your house ad is unobtrusive and presented
+ at a time convenient for users to leave your apps and try out your new title.
+ Also, be sure to include logic that allows users to dismiss the ad and
+ control if they will be asked again later.
+</p>
+
+<p>
+ Consider using free AdMob <a href=
+ "https://support.google.com/admob/v2/answer/3210452?hl=en#subid=us-en-et-dac">
+ house ads</a> within your apps to create awareness and promote your entire
+ portfolio of apps. When launching new apps, an easy way to quickly attract
+ users is to promote directly to your existing customers.
+</p>
+
+<div class="headerLine">
+ <h1 id="hold-a-contest">
+ Hold a Contest
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Contests can be a great way to engage your users. If you have a game, hold a
+ tournament and promote it through your marketing channels. Use Google Play
+ Games APIs for leaderboards and achievements to stimulate competition. Some
+ app developers have provided prizes for creative uses of an app or social
+ engagement. For example, a photo app developer can hold a photo contest.
+</p>
+
+<p>
+ But be sure you’re complying with the appropriate legal requirements in your
+ country and provide a clear set of terms and conditions, accessible online.
+ Don’t let a lack of attention to detail spoil a great marketing opportunity.
+</p>
+
+<div class="headerLine">
+ <h1 id="leverage-pr">
+ Leverage PR
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Public Relations outreach can be a valuable marketing initiative. Many
+ developers use PR to announce new features in their apps or games, which, in
+ turn, builds demand for the updated release when it comes out. You can also
+ provide early copies of your app or game for the press to review, and publish
+ their reviews when the app or game launches.
+</p>
+
+<div class="headerLine">
+ <h1 id="use-social-media">
+ Use Social Media
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Social media is your opportunity to build promotion for your apps. Start with
+ your own channels: update users on your plans before launch, announce your
+ launch, and talk about progress after launch (downloads, new features, and
+ alike.) Then expand by encouraging your users to forward and share your
+ posts.
+</p>
+
+<p>
+ Take advantage of bloggers. Look for bloggers that cover Android and learn
+ what interest them. Remember to look locally as well as globally, gaining a
+ local following can be a great springboard to global success. When you’ve
+ selected a target group of bloggers focus on them by sending details of your
+ apps and free versions if the apps are priced. Follow up and ask them to
+ review your apps. A review on the right blog is a great promotion.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="publish-youtube-videos">
+ Publish YouTube Videos
+ </h1>
+
+ <hr>
+</div>
+
+<div class="center-img" style="padding-top:1em;">
+ <img src="{@docRoot}images/gp-build-buzz-yt.png">
+</div>
+
+<p>
+ YouTube videos are now an essential part of building buzz. Use them to
+ showcase your apps’ feature. Remember to do this before, at, and after
+ launch. Taking users on a journey through the development of your apps can be
+ a great way to drive downloads at launch.
+</p>
+
+<div class="headerLine">
+ <h1 id="advertise">
+ Advertise
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure">
+ <img src="{@docRoot}images/google/gps-ads.png" style="width:340px">
+</div>
+
+<p>
+ Advertise your app in other apps to increase downloads. There are many tools
+ to help you target the right users for your apps and games. You can use
+ <a href=
+ "http://www.google.com/ads/admob/promote.html#subid=us-en-et-dac">AdMob</a>
+ to drive installs of your app at a target cost-per-acquisition (CPA). You
+ also get free house ads for your own app. <a href=
+ "https://apps.admob.com/admob/signup?subid=us-en-et-dac&_adc=ww-ww-et-admob2&hl=en">
+ Sign up for an AdMob account</a> to get started.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="maximize-your-marketing-spend">
+ Maximize your Marketing Spend
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure" style="margin: 0 3em;">
+ <img src="{@docRoot}images/gp-build-buzz-uplift-2.png" style="">
+</div>
+
+<p>
+ Maximize buzz and leverage the halo effect of cross-platform, multimedia,
+ simultaneous launches.
+</p>
+
+<p><strong>Developers who launch on multiple platforms at
+ the same time have received a 10-20% uplift.</strong>If you’re spending money
+ to advertise your launch or spending effort on press, shipping on multiple
+ platforms simultaneously helps you maximize your return on investment.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="related-resources">
+ Related Resources
+ </h1>
+
+ <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/users/buildbuzz"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/users/build-community.jd b/docs/html/distribute/users/build-community.jd
new file mode 100644
index 0000000..1623939
--- /dev/null
+++ b/docs/html/distribute/users/build-community.jd
@@ -0,0 +1,202 @@
+page.title=Build Community
+page.metaDescription=Build a loyal following with great support and communication.
+page.tags="users, growth, community"
+
+@jd:body
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>
+ Contents
+ </h2>
+
+ <ol>
+ <li>
+ <a href="#starting-your-community">Starting Your Community</a>
+ </li>
+
+ <li>
+ <a href="#tools-to-build-your-community">Tools to Build Your Community</a>
+ </li>
+
+ <li>
+ <a href="#managing-your-community">Managing Your Community</a>
+ </li>
+ <li>
+ <a href="#related-resources">Related Resources</a>
+ </li>
+ </ol>
+ </div>
+</div>
+
+<p>
+ Fans of your apps love to help others, turn newer users into fans, and bring
+ you more users as they talk about your app. Building a community can help you
+ tap into those influencers to help you improve your app and provide support
+ to others.
+</p>
+
+<p>
+ Building your own community can help you bring content that will delight
+ users and get them talking about your apps to friends, family and others in
+ their social network.
+</p>
+
+<div class="headerLine">
+ <h1 id="starting-your-community">
+ Starting Your Community
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ In conjunction with your apps’ design and development, you should start
+ defining and building your community infrastructure. There’s no one approach
+ that fits all, and the approach for each of your apps may need to be a little
+ different. You should start by thinking about your potential users and asking
+ questions such as:
+</p>
+
+<ul>
+ <li>
+ <p>
+ How will my users prefer to interact? Game users may prefer a modern feed
+ style community, users of a financial management app a more traditional
+ discussion forum.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Should I have a community for all my apps or should each app have its
+ own? Will users be turned off if the community isn’t just about the app
+ that interests them or can I make it a way to turn them onto my other
+ apps?
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Will different countries or territories, or speakers of particular
+ languages need separate forums? How will I handle feedback in languages I
+ don’t know?
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Do I need any additional policies beyond those governing the tool used to
+ host the community?
+ </p>
+ </li>
+</ul>
+
+<p>
+ Any way you do it, starting your community early helps you build momentum as
+ you turn happy users into influencers.
+</p>
+
+<p>
+ Consider inviting your existing users through a rich notification or an
+ opt-in on your website. Don’t overlook inviting your critics too. If you have
+ been able to address their earlier issues you may convert them into
+ supporters — it’s not unknown for your harshest critics to become your most
+ enthusiastic fans if you address their concerns.
+</p>
+
+<p>
+ When you use the <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta-testing
+ feature</a> in Google Play, you’ll create a testers group through a <a href=
+ "https://support.google.com/groups/answer/46601">Google Group</a> or <a href=
+ "https://support.google.com/plus/topic/2888488">Google+ Community</a> to
+ define who gets your software for testing. Consider managing these groups as
+ communities in their own right.
+</p>
+
+<div class="headerLine">
+ <h1 id="tools-to-build-your-community">
+ Tools to Build Your Community
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ There are many tools you can use to build your community. Before you launch,
+ inviting <a href="http://www.google.com/+/business/">Google+</a> users or
+ <a href="https://support.google.com/groups/answer/46601?hl=en">Google
+ Groups</a> to <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta-test</a>
+ your app can help you kickstart your community while you listen to and
+ respond to your user feedback.
+</p>
+
+<p>
+ Once you’ve launched, your Google+ or other social media presence can help
+ you continue to gather feedback, answer questions, and get input on updates.
+ Use social media to get the conversation started. Post updates to your
+ followers, announce new apps, and host contests. Ask followers to re-post so
+ that they bring new users into the conversation. Fans love to profess their
+ passion for great apps, so be sure to give them plenty of reason to do so.
+</p>
+
+<p>
+ Forums like <a href=
+ "https://support.google.com/groups/answer/46601?hl=en">Google Groups</a> are
+ particularly well suited to help you and your users provide support to
+ others. By helping out your community, you’re building your fan base who will
+ share their experiences with other prospective customers.
+</p>
+
+<p>
+ Respond to comments and reviews on both your product details page on Google
+ Play and <a href="http://youtube.com">YouTube</a> pages. Prospective
+ customers are influenced by reviews and comments, so be sure to manage your
+ brand in every channel you can.
+</p>
+
+<div class="headerLine">
+ <h1 id="managing-your-community">
+ Managing Your Community
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-community-0.png">
+</div>
+
+<p>
+ Engaged users want you to succeed. Let them know you’re listening! Responding
+ to posts, comments, and other social media mentions improves your ratings by
+ letting users know you care.
+</p>
+
+<p>
+ Update the product based on user feedback and announce new releases. Users
+ often change their original star ratings after feeling heard, inspiring more
+ users to install your apps.
+</p>
+
+<p>
+ There are many ways to make your community feel special. Consider polls to
+ let users influence product updates. Use competitions to inspire and reward
+ your community. Giving a special <em>member of the week</em> badge is an easy
+ way to recognize those that help others. Or get users involved in testing new
+ versions or new apps to make them feel special.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="related-resources">
+ Related Resources
+ </h1>
+ <hr>
+</div>
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/users/buildcommunity"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/distribute/users/expand-to-new-markets.jd b/docs/html/distribute/users/expand-to-new-markets.jd
new file mode 100644
index 0000000..cc94a92
--- /dev/null
+++ b/docs/html/distribute/users/expand-to-new-markets.jd
@@ -0,0 +1,325 @@
+page.title=Expand Into New Markets
+page.metaDescription=Tap fast-growing markets in Japan, Korea, India, Brazil, and many other countries around the world.
+page.image=/distribute/images/expand-into-new-markets.jpg
+page.tags="users, growth, global"
+
+@jd:body
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>
+ Contents
+ </h2>
+
+ <ol>
+ <li>
+ <a href="#localize-your-product">Localize Your Product</a>
+ </li>
+
+ <li>
+ <a href="#testing-and-support">Testing and Support</a>
+ </li>
+
+ <li>
+ <a href="#localize-your-google-play-listing">Localize Your Store
+ Listing</a>
+ </li>
+
+ <li>
+ <a href="#marketing">Marketing</a>
+ </li>
+
+ <li>
+ <a href="#related-resources">Related Resources</a>
+ </li>
+ </ol>
+ </div>
+</div>
+<p>
+ Android and Google Play give you a worldwide audience for your apps, with an
+ addressable user base that's growing very rapidly in countries such as Japan,
+ Korea, India, and Brazil. You can sell your app in more than 130 countries.
+</p>
+
+<p>
+ To <strong>maximize your app's distribution potential and earn high
+ ratings</strong> from users around the world, we encourage you to localize
+ your app. Once you’ve built a solid foundation in your home market, take
+ advantage of Android’s powerful growth around the world and expand your app
+ to new markets.
+</p>
+
+<div class="sidebox-wrapper" style="float:right;">
+ <div class="sidebox">
+ <p>
+ <strong>Tip:</strong> Localization is more than translation. Plan product
+ features, launch, and marketing for key markets.
+ </p>
+ </div>
+</div>
+
+<p class="caution" style="font-size:15.5px;">
+</p>
+
+<p>
+ Localization involves a variety of tasks throughout your app development
+ cycle, and advance planning is essential. But <strong>localization is more
+ than just translating your UI</strong>. To be successful, you also need to
+ localize your Google Play listing and ensure your marketing is suitable for
+ the demographic you’re addressing.
+</p>
+
+<p>
+ To reduce development and maintenance effort, use a single APK for all
+ regions. A single APK also allows you to more easily track metrics by
+ country. Google Play takes care of providing the appropriate localized
+ version of your app based on user location.
+</p>
+
+<div class="headerLine">
+ <h1 id="localize-your-product">
+ Localize Your Product
+ </h1>
+
+ <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+ <div class="sidebox">
+ <p>
+ <strong>Tip:</strong> Use a professional translation service located in
+ your target country to ensure high quality and good user ratings.
+ </p>
+ </div>
+</div>
+
+<p>
+ The first step is to identify your target markets and associated languages,
+ then focus your product localization on those countries. Some of the tasks
+ include translating your UI strings and localizing dates and times, layouts,
+ text direction, and finally your Google Play store listing. To learn more
+ about how to localize your app, visit our <a href=
+ "{@docRoot}distribute/tools/localization-checklist.html">Localization
+ Checklist</a>.
+</p>
+<!-- <p>[Need graphic highlighting that it’s all about getting high ratings]</p> -->
+
+<p>
+ Work with a professional translator, preferably located in the country you’re
+ localizing your apps for, to ensure high quality results. Machine
+ translations may affect your apps’ ratings, as they’re less reliable than
+ high-quality professional translations. For example, a professional service
+ will know to consider the vocabulary expansion, left-to-right and
+ right-to-left support, and other factors in each language. Learn more about
+ UI considerations and other factors in the <a href=
+ "{@docRoot}distribute/tools/localization-checklist.html#design">Design for
+ Localization</a> section of the Localization Checklist.
+</p>
+
+<p>
+ <strong>Google Play App Translation Service</strong> can help you quickly
+ find and purchase translations of your apps. In the <a href=
+ "https://play.google.com/apps/publish/">Developer Console</a>, you can browse
+ a list of third-party vendors who are pre-qualified by Google to offer
+ high-quality professional translations at competitive prices.
+</p>
+
+<div style="float:left; width:48%; padding:8px;">
+ <img src="{@docRoot}images/gp-listing-3.jpg">
+</div>
+
+<div style="width:48%; padding:8px; float:left">
+ <img src="{@docRoot}images/gp-expand-2.jpg">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="testing-and-support">
+ Testing and Support
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Before you launch, be sure to use our <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta
+ testing</a> and <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html#staged-rollouts">staged
+ rollouts</a> to identify and address issues before users can rate your app.
+ Feedback can be gathered using a <a href=
+ "https://support.google.com/groups/answer/46601">Google Group</a> or <a href=
+ "https://support.google.com/plus/topic/2888488">Google+ Community</a>. Watch
+ user sentiment and respond if necessary as you add countries.
+</p>
+
+<p>
+ After you launch, <strong>offer support hours in the local time zone in the
+ local language</strong>. When possible, having a local presence can
+ dramatically increase your daily active users and revenue. For example,
+ <a href="">this developer</a> was able to <strong>increase their revenue over
+ 500% after creating a local presence</strong> in Asia and taking great care
+ of their users.
+</p>
+
+<div class="headerLine">
+ <h1 id="localize-your-google-play-listing">
+ Localize Your Google Play Store Listing
+ </h1>
+
+ <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+ <div class="sidebox">
+ <p>
+ <strong>Tip:</strong> You can select regions, set regional pricing, and
+ localize your listing while maintaining only one APK.
+ </p>
+ </div>
+</div>
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-buyer-currency.png" class="border-img">
+</div>
+
+<p>
+ Within your Google Play listing, you’ll need to set the regions in which your
+ apps will be available, set pricing for each, and customize your Google Play
+ listing to ensure it speaks to local audiences. You can change your country
+ and carrier targeting at any time just by saving changes in the Google Play
+ Developer Console.
+</p>
+
+<h3>
+ Region selection
+</h3>
+
+<p>
+ In the Developer Console, you can set the regions you make your app available
+ to, pricing in local currencies, and all Google Play listing marketing. You
+ can specify which countries and territories you want to distribute to, and
+ even which carriers (for some countries).
+</p>
+
+<h3>
+ Pricing
+</h3>
+
+<p>
+ When you start to address new markets you have several options for setting
+ the prices of your products: apps, in-app products, and subscriptions. You
+ can set a default price for each product and allow Google Play to adjust this
+ each month for changes in exchange rates, or manually set prices.
+</p>
+
+<p>
+ There are several reasons why it might be beneficial to set prices manually,
+ such as:
+</p>
+
+<ul>
+ <li>
+ <p>
+ Cost of living differences. To better target developing markets you may
+ consider offering your apps at a lower price to make them more affordable
+ in relation to local incomes.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Price perception. Users in some countries respond well to prices set to
+ x.99, while others prefer x.00 pricing.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Numerology. You may wish to avoid using certain numbers that are
+ considered unlucky, such as 13 or 4.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Competition. Your app may have local competition in some markets that you
+ need to account for.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Local trends and interests. Your apps may be able to bear a higher price
+ in some markets. For example, the interest in various sports varies
+ greatly from country to country.
+ </p>
+ </li>
+</ul>
+
+<p>
+ You may also want to run short-term promotions and discounts in specific
+ countries.
+</p>
+
+<p>
+ The <a href=
+ "{@docRoot}distribute/googleplay/developer-console.html#selling-pricing-your-products">
+ Pricing & Distribution</a> section in the <a href=
+ "https://play.google.com/apps/publish/">Developer Console</a> is where you
+ set and manage regional distribution and local prices.
+</p>
+
+<h3>
+ Copy and creative
+</h3>
+
+<p>
+ To market to users around the world, <strong>localize your store listing,
+ including app details and description, promotional graphics, screenshots, and
+ more.</strong> Graphical assets and copy can be uploaded for each country you
+ are targeting.
+</p>
+
+<div>
+ <img src="{@docRoot}images/gp-expand-4.jpg" class="border-img">
+</div>
+
+<div>
+ <img src="{@docRoot}images/gp-expand-5.jpg" class="border-img">
+</div>
+
+<p>
+ Learn more about how to localize your <a href=
+ "{@docRoot}distribute/tools/launch-checklist.html#prepare-graphics">store
+ listing</a>.
+</p>
+
+<div class="headerLine">
+ <h1 id="marketing">
+ Marketing
+ </h1>
+
+ <hr>
+</div>
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-badge-jp.png">
+</div>
+
+<p>
+ Just like your Google Play listing, all other marketing should be localized
+ to speak to the local audience. This includes images, colors, icons, and
+ audio. To maximize effectiveness, <strong>run promotions, contests, and
+ announcements at local time</strong>. You can build a localized <a href=
+ "{@docRoot}distribute/tools/promote/badges.html">Google Play badge</a> and
+ <a href="{@docRoot}distribute/tools/promote/device-art.html">device art</a>
+ for each language you support.
+</p>
+
+<div class="headerLine clearfloat"><h1 id="related-resources">Related Resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/getusers/expandnewmarkets"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x3,6x3,6x3,6x3,6x3,6x3"
+ data-maxResults="6"></div>
diff --git a/docs/html/distribute/users/index.jd b/docs/html/distribute/users/index.jd
new file mode 100644
index 0000000..77ef609
--- /dev/null
+++ b/docs/html/distribute/users/index.jd
@@ -0,0 +1,30 @@
+page.title=Get Users
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+<p>
+ You’ve published your app, now how do you acquire users? Every app and game
+ is different, but there are some common themes from successful Google Play
+ developers. These best practices are critical to your app or game’s success.
+</p>
+
+<div class="dynamic-grid">
+
+<div class="resource-widget resource-flow-layout landing col-16"
+ data-query="collection:distribute/users"
+ data-cardSizes="6x6, 6x6, 6x6, 9x6, 9x6, 6x6, 6x6, 6x6"
+ data-maxResults="8">
+</div>
+
+<h3>Related resources</h3>
+
+ <div class="resource-widget resource-flow-layout col-16"
+ data-query="type:youtube+tag:users,tag:global,type:blog+tag:users"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x3"
+ data-maxResults="6">
+ </div>
+
+</div>
diff --git a/docs/html/distribute/users/know-your-user.jd b/docs/html/distribute/users/know-your-user.jd
new file mode 100644
index 0000000..fb91a05
--- /dev/null
+++ b/docs/html/distribute/users/know-your-user.jd
@@ -0,0 +1,153 @@
+page.title=Know Your User
+page.metaDescription=It\'s essential to understand your users and listen to their input. Here are some ideas.
+page.image=/distribute/images/know-your-user.jpg
+page.tags="users, growth, global"
+
+@jd:body
+
+<div style="width:100%">
+ <img src="{@docRoot}images/gp-androidify.png">
+</div>
+
+<p>
+ A key part of growing your apps' installed base is knowing more about your
+ users — how they discover your app, what devices they use, what they do
+ when they use your app, and how often they return to it.
+</p>
+
+<div class="headerLine">
+ <h1 id="read-ratings-comments">
+ Read Ratings Comments
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ The most obvious way to get to know your users is by reading review comments
+ for your apps on Google Play. While the details provided in reviews will vary
+ greatly, in addition to telling you about what users like and dislike in your
+ apps, they can also provide insight into your users’ motivations for using
+ your apps. And remember that users can update their ratings and comments
+ about an app when you fix issues.
+</p>
+
+<p>
+ Learn more about <a href=
+ "{@docRoot}distribute/essentials/optimizing-your-app.html#listen-to-your-users">
+ how to listen to users</a>.
+</p>
+
+<div>
+ <img src="{@docRoot}images/gp-your-user-0.jpg" class="border-img">
+ <p class="img-caption">
+ User ratings
+ </p>
+</div>
+
+<div class="headerLine">
+ <h1 id="start-community">
+ Start a Community
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Another great way to get to know your users, learn who they are, and what
+ they are looking for, is to start a community. There are many support tools
+ you can use, from forums such as <a href="http://groups.google.com/">Google
+ Groups</a> to comprehensive customer support products. You can integrate some
+ directly into your apps. And once you deploy a support tool, make sure to
+ fill in the support link in your Google Play product details page.
+</p>
+
+<p>
+ <a href="{@docRoot}distribute/users/build-community.html">Learn more about
+ starting and managing a community</a>.
+</p>
+
+<div class="headerLine">
+ <h1 id="create-survey">
+ Create a Survey
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Consider using a survey to gather information about your users and their
+ views on your apps. Compared to app reviews, a questionnaire enables you to
+ seek specific information. However use with care, as the creation of suitable
+ question is something of an art. Also consider providing an appropriate
+ incentive for completing the questionnaire, as too few responses can be worse
+ than no responses at all.
+</p>
+
+<p>
+ You can create a questionnaire with <a href=
+ "http://www.google.com/drive/apps.html#forms">Google Drive Forms</a> or use
+ one of the various third-party survey and questionnaire hosting tools
+ available, such as SurveyMonkey.
+</p>
+
+<div class="headerLine">
+ <h1 id="add-analytics">
+ Add Analytics to your Apps
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Analytics data can tell you a lot about your users, by exposing their
+ behaviour in your apps. You can use <a href=
+ "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html">
+ Google Analytics by linking it with your Google Play account</a> or use a
+ third-party analytics tool. Analytics tools can help you gather information
+ on app installs, feature popularity, unused features, and more. You can see
+ any usage pattern differences by region, device, time day and other
+ variables.
+</p>
+
+<p>
+ Read more about <a href=
+ "{@docRoot}distribute/essentials/optimizing-your-app.html#measuring-analyzing-responding">
+ measuring behavior</a>.
+</p>
+
+<div>
+ <img src="{@docRoot}images/gp-dc-stats.png" class="border-img">
+</div>
+
+<div class="headerLine">
+ <h1 id="use-google">
+ Use Google+
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ <a href="https://plus.google.com/">Google+</a> is a great way to gather user
+ feedback, announce surveys and contests, and see how users react to new
+ features and functionality. Many developers manage a Google+ page to
+ communicate with their users. It’s also a good way to get feedback from your
+ beta-testing. Some developers have a page for each of their apps. This is
+ especially true for game developers, who post challenges and tournaments.
+ Google+ can also be used to post game walkthroughs and tips.
+</p>
+
+<div>
+ <img src="{@docRoot}images/gp-your-user-2.jpg">
+</div>
+
+<div class="headerLine clearfloat">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/users/knowyouruser"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x3"
+ data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/distribute/users/users_toc.cs b/docs/html/distribute/users/users_toc.cs
new file mode 100644
index 0000000..a2437a6
--- /dev/null
+++ b/docs/html/distribute/users/users_toc.cs
@@ -0,0 +1,40 @@
+<ul id="nav">
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/know-your-user.html">
+ <span class="en">Know Your User</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/your-listing.html">
+ <span class="en">Create a Great Listing</span>
+ </a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/build-buzz.html">
+ <span class="en">Build Buzz</span>
+ </a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/build-community.html">
+ <span class="en">Build Community</span>
+ </a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/expand-to-new-markets.html">
+ <span class="en">Expand to New Markets</span>
+ </a>
+ </div>
+ </li>
+
+</ul>
+
+
+<script type="text/javascript">
+<!--
+ buildToggleLists();
+ changeNavLang(getLangPref());
+//-->
+</script>
diff --git a/docs/html/distribute/users/your-listing.jd b/docs/html/distribute/users/your-listing.jd
new file mode 100644
index 0000000..cc72fff
--- /dev/null
+++ b/docs/html/distribute/users/your-listing.jd
@@ -0,0 +1,191 @@
+page.title=Create a Great Listing
+page.metaDescription=Make your listing page compelling and integrate it into your marketing campaigns.
+page.image=/distribute/images/create-listing.jpg
+page.tags="listing, google play, users, growth"
+
+@jd:body
+
+<p>
+ Your Google Play app listings are a vital part of your app marketing, from
+ organic traffic or visits you generate through marketing and promotion.
+ Potential users will quickly move on from a poor listing, so the importance
+ of having a great one can't be ignored.
+</p>
+
+<div class="headerLine">
+ <h1 id="graphics-imagery">
+ Graphics & Imagery Tips
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Be sure to supply a variety of high-quality graphic assets to showcase your
+ apps or brand on Google Play search results and your product details pages.
+ These graphic assets are key parts of successful product details pages that
+ attracts and engages users, so consider having a professional produce them
+ for you.
+</p>
+
+<div>
+ <img src="{@docRoot}images/gp-listing-0.jpg" class="border-img">
+</div>
+
+<h3>
+ Icons
+</h3>
+
+<p>
+ For most users, the <a href=
+ "{@docRoot}design/style/iconography.html#launcher">launcher icon</a>
+ (sometimes referred to as the app icon) is the first impression of your app.
+ As higher density screens on both phones and tablets gain popularity, it's
+ important to make sure your launcher icon is crisp and high quality. To do
+ this, make sure you’re including XHDPI (320dpi) and XXHDPI (480dpi) versions
+ of the icon in your apps. Learn more about <a href=
+ "http://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html">
+ Making Beautiful Android App Icons</a> from the <a href=
+ "http://android-developers.blogspot.com/">Android Developers blog</a>.
+</p>
+
+<div>
+ <img src="{@docRoot}images/gp-listing-1.png" class="border-img">
+</div>
+
+<h3>
+ Screenshots and videos
+</h3>
+
+<p>
+ Be sure to showcase how your apps look, their important features, and what
+ makes them different. Showcase any game play, characters, and their
+ personalities. Some developers build special screens to highlight what’s
+ happening in the screenshot, and extra video footage to highlight the brand.
+ Get more details <a href=
+ "{@docRoot}distribute/tools/launch-checklist.html#prepare-graphics">here</a>.
+</p>
+
+<div>
+ <img src="{@docRoot}images/gp-listing-2.jpg">
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+ <div class="sidebox">
+ <p>
+ <strong>Tip:</strong> If your app runs on both phones and tablets, be
+ sure to include screenshots from both devices, including both horizontal
+ and portrait aspect ratios.
+ </p>
+ </div>
+</div>
+
+<h3>
+ Featured image
+</h3>
+
+<p>
+ Choosing the right featured image is important, it needs to convey as much
+ about the features of your apps and what makes them special as possible,
+ without being cluttered and confusing. Check out the <a href=
+ "http://android-developers.blogspot.com/">Android Developers blog</a> post
+ for more <a href=
+ "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">
+ Featured-Image Guidelines</a>.
+</p>
+
+<div class="headerLine clearfloat">
+ <h1 id="localization-tips">
+ Localization Tips
+ </h1>
+
+ <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+ <div class="sidebox">
+ <p>
+ <strong>Tip:</strong> Translate any embedded text, use different imagery
+ or presentation, and match any marketing promotion to the needs of users
+ in other markets. For example: Some eastern markets respond to price
+ points that end in .00 or .05 more than .99.
+ </p>
+ </div>
+</div>
+
+<p>
+ Many developers start in their country of strength, then expand into new
+ markets. To help you market your apps more effectively to a global audience,
+ create <a href=
+ "http://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html">
+ localized versions of your promotional graphics, screenshots, and videos</a>.
+ When a user visits your product display pages, Google Play will show the
+ localized assets that you’ve provided for that country. Find out more about
+ <a href="{@docRoot}distribute/users/expand-to-new-markets.html">capitalize on
+ the growing international audience</a>.
+</p>
+
+<div style="float:left;">
+ <img src="{@docRoot}images/gp-listing-3.jpg">
+</div>
+
+<div class="headerLine clearfloat">
+ <h1 id="keyword-tips">
+ Keyword Tips
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ Think carefully about the keywords you use for your apps. Think about words
+ that represent the core feature of your apps. Also consider other words that
+ the user might use to search for your app. For example, if you have a Live
+ Wallpaper app, you may want to include the term ‘background’. This way, users
+ who don’t yet know the terminology can find your app.
+</p>
+
+<div class="headerLine">
+ <h1 id="app-indexing">
+ Sign Up for App Indexing
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ App Indexing provides deep links from Google searches to your apps. Get more
+ details and a link to the sign up page <a href=
+ "https://developers.google.com/app-indexing/">here</a>.
+</p>
+
+<div class="center-img">
+ <img src="{@docRoot}images/gp-listing-4.jpg">
+</div>
+
+<div class="headerLine">
+ <h1 id="education-app">
+ Education App Tips
+ </h1>
+
+ <hr>
+</div>
+
+<p>
+ If you’ve an educational app for the K-12 market, include it in Google Play
+ for Education. Google Play for Education can help your innovative educational
+ apps gain visibility with the right audiences, without having to knock on
+ school doors. Learn more about <a href=
+ "{@docRoot}distribute/googleplay/edu/about.html">Google Play for
+ Education</a>.
+</p>
+
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/users/createagreatlisting"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x3"
+ data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/google/play/billing/billing_subscriptions.jd b/docs/html/google/play/billing/billing_subscriptions.jd
index aa25092..d0e6dc5 100644
--- a/docs/html/google/play/billing/billing_subscriptions.jd
+++ b/docs/html/google/play/billing/billing_subscriptions.jd
@@ -1,6 +1,10 @@
-page.title=Subscriptions
+page.title=Google Play In-App Subscriptions
parent.title=In-app Billing
parent.link=index.html
+page.metaDescription=Subscriptions let you sell content or features in your app with automated, recurring billing.
+page.image=/images/play_dev.jpg
+page.tags="inapp, iap, billing"
+meta.tags="monetization, inappbilling, subscriptions"
@jd:body
<div id="qv-wrapper">
diff --git a/docs/html/google/play/billing/billing_testing.jd b/docs/html/google/play/billing/billing_testing.jd
index 9d1964a..df6c657 100644
--- a/docs/html/google/play/billing/billing_testing.jd
+++ b/docs/html/google/play/billing/billing_testing.jd
@@ -367,6 +367,6 @@
publish your application on Google Play. You can follow the normal steps for <a
href="{@docRoot}tools/publishing/preparing.html">preparing</a>, <a
href="{@docRoot}tools/publishing/app-signing.html">signing</a>, and <a
-href="{@docRoot}distribute/googleplay/publish/preparing.html">publishing on Google Play</a>.
+href="{@docRoot}distribute/tools/launch-checklist.html">publishing on Google Play</a>.
</p>
diff --git a/docs/html/google/play/billing/index.jd b/docs/html/google/play/billing/index.jd
index 481a79c..dce20cb 100644
--- a/docs/html/google/play/billing/index.jd
+++ b/docs/html/google/play/billing/index.jd
@@ -1,4 +1,8 @@
page.title=Google Play In-app Billing
+page.metaDescription=In-app Billing lets you sell digital content as one-time purchases or subscriptions.
+page.image=/images/play_dev.jpg
+meta.tags="monetizing, inappbilling, subscriptions"
+page.tags="inapp, iap, subscriptions"
@jd:body
<p>In-app Billing is a Google Play service that lets you sell digital content from inside
@@ -40,8 +44,6 @@
<p>To get started, read the documents below or take the <a href="{@docRoot}training/in-app-billing/index.html">Selling
In-app Products</a> training class.</p>
-</div>
-</div>
<dl>
<dt><strong><a href="{@docRoot}google/play/billing/billing_overview.html">Overview</a></strong></dt>
diff --git a/docs/html/google/play/billing/v2/billing_subscriptions.jd b/docs/html/google/play/billing/v2/billing_subscriptions.jd
index 9c86e20..f8051a9 100644
--- a/docs/html/google/play/billing/v2/billing_subscriptions.jd
+++ b/docs/html/google/play/billing/v2/billing_subscriptions.jd
@@ -382,7 +382,7 @@
startActivity(intent);</pre>
<p>For more information, see
- <a href="{@docRoot}distribute/googleplay/promote/linking.html">Linking to Your Products</a>.</p>
+ <a href="{@docRoot}distribute/tools/promote/linking.html">Linking to Your Products</a>.</p>
<h2 id="purchase-state-changes">Recurring Billing, Cancellation, and Changes In Purchase State</h2>
diff --git a/docs/html/google/play/expansion-files.jd b/docs/html/google/play/expansion-files.jd
index a21fbc5..e90f8fa 100644
--- a/docs/html/google/play/expansion-files.jd
+++ b/docs/html/google/play/expansion-files.jd
@@ -1,4 +1,6 @@
page.title=APK Expansion Files
+page.metaDescription=If your app needs more than the 50MB APK max, use free APK expansion files from Google Play.
+page.tags="apk size, apk max, large assets"
@jd:body
diff --git a/docs/html/google/play/licensing/adding-licensing.jd b/docs/html/google/play/licensing/adding-licensing.jd
index 93561f6..3bf4c1a 100644
--- a/docs/html/google/play/licensing/adding-licensing.jd
+++ b/docs/html/google/play/licensing/adding-licensing.jd
@@ -646,7 +646,7 @@
deep-links the user to the application's details page on Google Play, from which the
use can purchase the application. For more information on how to set up such
links, see <a
-href="{@docRoot}distribute/googleplay/promote/linking.html">Linking to Your Products</a>. </li>
+href="{@docRoot}distribute/tools/promote/linking.html">Linking to Your Products</a>. </li>
<li>Display a Toast notification that indicates that the features of the
application are limited because it is not licensed. </li>
</ul>
@@ -988,7 +988,7 @@
publish the application on Google Play. Follow the normal steps to <a
href="{@docRoot}tools/publishing/preparing.html">prepare</a>, <a
href="{@docRoot}tools/publishing/app-signing.html">sign</a>, and then <a
-href="{@docRoot}distribute/googleplay/publish/preparing.html">publish the application</a>.
+href="{@docRoot}distribute/tools/launch-checklist.html">publish the application</a>.
</p>
diff --git a/docs/html/google/play/licensing/index.jd b/docs/html/google/play/licensing/index.jd
index 6632fc0..a7ae57a 100644
--- a/docs/html/google/play/licensing/index.jd
+++ b/docs/html/google/play/licensing/index.jd
@@ -1,4 +1,7 @@
-page.title=Application Licensing
+page.title=App Licensing
+page.metaDescription=Information on using the licensing feature of Google Play to protect your apps.
+meta.tags="licensing, drm"
+page.image=/assets/images/resource-card-default-android.jpg
@jd:body
diff --git a/docs/html/google/play/licensing/setting-up.jd b/docs/html/google/play/licensing/setting-up.jd
index d83f91b..f43e4aba 100644
--- a/docs/html/google/play/licensing/setting-up.jd
+++ b/docs/html/google/play/licensing/setting-up.jd
@@ -42,7 +42,7 @@
using your Google account and agree to the Google Play terms of service.</p>
<p>For more information, see <a
-href="{@docRoot}distribute/googleplay/publish/register.html">Get Started with Publishing</a>.</p>
+href="{@docRoot}distribute/googleplay/start.html">Get Started with Publishing</a>.</p>
<p>If you already have a publisher account on Google Play, use your
Developer Console to set up licensing.</p>
diff --git a/docs/html/guide/components/index.jd b/docs/html/guide/components/index.jd
index 37fb7e9..811d015 100644
--- a/docs/html/guide/components/index.jd
+++ b/docs/html/guide/components/index.jd
@@ -1,7 +1,9 @@
page.title=App Components
page.landing=true
page.landing.intro=Android's application framework lets you create rich and innovative apps using a set of reusable components. This section explains how you can build the components that define the building blocks of your app and how to connect them together using intents.
+page.metaDescription=Android's application framework lets you create rich and innovative apps using a set of reusable components. This section explains how you can build the components that define the building blocks of your app and how to connect them together using intents.
page.landing.image=images/develop/app_components.png
+page.image=images/develop/app_components.png
@jd:body
diff --git a/docs/html/guide/practices/screens_support.jd b/docs/html/guide/practices/screens_support.jd
index 8c76411..dbe6c1a 100644
--- a/docs/html/guide/practices/screens_support.jd
+++ b/docs/html/guide/practices/screens_support.jd
@@ -1,4 +1,7 @@
page.title=Supporting Multiple Screens
+page.metaDescription=Nanaging UIs for the best display on multiple screen sizes.
+meta.tags="multiple screens"
+
@jd:body
<div id="qv-wrapper">
diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
index 6143b4b..a716bf8 100644
--- a/docs/html/guide/topics/manifest/uses-feature-element.jd
+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
@@ -689,7 +689,7 @@
<td>The application requires landscape orientation.</td>
<td rowspan="2">
<p>For example, if your app requires portrait orientation, you should declare
-<code><uses-feature android:name="android.hardware.screen.portrait"/></code> so that only devices
+<code><uses-feature android:name="android.hardware.screen.portrait"/></code> so that only devices
that support portrait orientation (whether always or by user choice) can install your app. If your
application <em>supports</em> both orientations, then you don't need to declare either.</p>
<p>Both orientations are assumed <em>not required</em>, by default, so your app may be installed
diff --git a/docs/html/guide/topics/resources/index.jd b/docs/html/guide/topics/resources/index.jd
index 386abf5..b85170b 100644
--- a/docs/html/guide/topics/resources/index.jd
+++ b/docs/html/guide/topics/resources/index.jd
@@ -2,6 +2,8 @@
page.landing=true
page.landing.intro=It takes more than just code to build a great app. Resources are the additional files and static content that your code uses, such as bitmaps, layout definitions, user interface strings, animation instructions, and more.
page.landing.image=images/develop/resources.png
+page.image=/images/develop/resources.png
+page.metaDescription=Developer guide about how to use resources in your Android apps.
@jd:body
diff --git a/docs/html/guide/topics/resources/localization.jd b/docs/html/guide/topics/resources/localization.jd
index 3bb9ab5..e86d4c9 100644
--- a/docs/html/guide/topics/resources/localization.jd
+++ b/docs/html/guide/topics/resources/localization.jd
@@ -1,485 +1,487 @@
-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/googleplay/publish/localizing.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/googleplay/publish/localizing.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 on a device, use the Settings application (Home >
-Menu > Settings > Locale & text > Select locale). </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 language and region codes, for
-example <code>fr</code> for French and <code>CA</code> for Canada.<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.language [<em>language code</em>];setprop
-persist.sys.country [<em>country code</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.language fr;setprop persist.sys.country
-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 on a device, use the Settings application (Home >
+Menu > Settings > Locale & text > Select locale). </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 language and region codes, for
+example <code>fr</code> for French and <code>CA</code> for Canada.<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.language [<em>language code</em>];setprop
+persist.sys.country [<em>country code</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.language fr;setprop persist.sys.country
+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/html/guide/topics/resources/string-resource.jd b/docs/html/guide/topics/resources/string-resource.jd
index 5a96ba1..e2326ec 100644
--- a/docs/html/guide/topics/resources/string-resource.jd
+++ b/docs/html/guide/topics/resources/string-resource.jd
@@ -20,9 +20,6 @@
information about styling and formatting strings, see the section about <a
href="#FormattingAndStyling">Formatting and Styling</a>.</p>
-
-
-
<h2 id="String">String</h2>
<p>A single string that can be referenced from the application or from other resource files (such
@@ -433,7 +430,7 @@
-<h3>Styling with HTML markup</h3>
+<h3 id="StylingWithHTML">Styling with HTML markup</h3>
<p>You can add styling to your strings with HTML markup. For example:</p>
<pre>
@@ -497,5 +494,107 @@
CharSequence styledText = Html.fromHtml(text);
</pre>
+<h2 id="StylingWithSpannables">Styling with Spannables</h2>
+<p>
+A {@link android.text.Spannable} is a text object that you can style with
+typeface properties such as color and font weight. You use
+{@link android.text.SpannableStringBuilder} to build
+your text and then apply styles defined in the {@link android.text.style}
+package to the text.
+</p>
+<p>You can use the following helper methods to set up much of the work
+of creating spannable text:</p>
+<pre style="pretty-print">
+/**
+ * Returns a CharSequence that concatenates the specified array of CharSequence
+ * objects and then applies a list of zero or more tags to the entire range.
+ *
+ * @param content an array of character sequences to apply a style to
+ * @param tags the styled span objects to apply to the content
+ * such as android.text.style.StyleSpan
+ *
+ */
+private static CharSequence apply(CharSequence[] content, Object... tags) {
+ SpannableStringBuilder text = new SpannableStringBuilder();
+ openTags(text, tags);
+ for (CharSequence item : content) {
+ text.append(item);
+ }
+ closeTags(text, tags);
+ return text;
+}
+
+/**
+ * Iterates over an array of tags and applies them to the beginning of the specified
+ * Spannable object so that future text appended to the text will have the styling
+ * applied to it. Do not call this method directly.
+ */
+private static void openTags(Spannable text, Object[] tags) {
+ for (Object tag : tags) {
+ text.setSpan(tag, 0, 0, Spannable.SPAN_MARK_MARK);
+ }
+}
+
+/**
+ * "Closes" the specified tags on a Spannable by updating the spans to be
+ * endpoint-exclusive so that future text appended to the end will not take
+ * on the same styling. Do not call this method directly.
+ */
+private static void closeTags(Spannable text, Object[] tags) {
+ int len = text.length();
+ for (Object tag : tags) {
+ if (len > 0) {
+ text.setSpan(tag, 0, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ } else {
+ text.removeSpan(tag);
+ }
+ }
+}
+</pre>
+
+<p>
+The following <code>bold</code>, <code>italic</code>, and <code>color</code>
+methods show you how to call the helper methods to apply
+styles defined in the {@link android.text.style} package. You
+can create similar methods to do other types of text styling.
+</p>
+
+<pre style="pretty-print">
+/**
+ * Returns a CharSequence that applies boldface to the concatenation
+ * of the specified CharSequence objects.
+ */
+public static CharSequence bold(CharSequence... content) {
+ return apply(content, new StyleSpan(Typeface.BOLD));
+}
+
+/**
+ * Returns a CharSequence that applies italics to the concatenation
+ * of the specified CharSequence objects.
+ */
+public static CharSequence italic(CharSequence... content) {
+ return apply(content, new StyleSpan(Typeface.ITALIC));
+}
+
+/**
+ * Returns a CharSequence that applies a foreground color to the
+ * concatenation of the specified CharSequence objects.
+ */
+public static CharSequence color(int color, CharSequence... content) {
+ return apply(content, new ForegroundColorSpan(color));
+}
+</pre>
+
+<p>
+Here's an example of how to chain these methods to create a character sequence
+with different types of styling applied to individual words:
+</p>
+
+<pre style="pretty-print">
+// Create an italic "hello, " a red "world",
+// and bold the entire sequence.
+CharSequence text = bold(italic(res.getString(R.string.hello)),
+ color(Color.RED, res.getString(R.string.world)));
+</pre>
\ No newline at end of file
diff --git a/docs/html/guide/topics/ui/accessibility/index.jd b/docs/html/guide/topics/ui/accessibility/index.jd
index 56efc4c..dcc22d7 100644
--- a/docs/html/guide/topics/ui/accessibility/index.jd
+++ b/docs/html/guide/topics/ui/accessibility/index.jd
@@ -1,5 +1,9 @@
page.title=Accessibility
parent.title=User Interface
+page.metaDescription=How to make your apps accessible to users with visual, physical, or other limitations. Robust support will increase your app's user base.
+
+page.tags="accessibility"
+page.image=/design/media/accessibility_contentdesc.png
parent.link=../index.html
@jd:body
diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd
index 3b1292e..59c2269 100644
--- a/docs/html/guide/topics/ui/notifiers/notifications.jd
+++ b/docs/html/guide/topics/ui/notifiers/notifications.jd
@@ -16,6 +16,7 @@
<li><a href="#Required">Required notification contents</a></li>
<li><a href="#Optional">Optional notification contents and settings</a></li>
<li><a href="#Actions">Notification actions</a></li>
+ <li><a href="#Priority">Notification priority</a></li>
<li><a href="#SimpleNotification">Creating a simple notification</a></li>
<li><a href="#ApplyStyle">Applying a big view style to a notification</a></li>
<li><a href="#Compatibility">Handling compatibility</a></li>
@@ -290,6 +291,26 @@
{@link android.support.v4.app.NotificationCompat.Builder}.
</p>
<!-- ------------------------------------------------------------------------------------------ -->
+<h3 id="Priority">Notification priority</h3>
+<p>
+ If you wish, you can set the priority of a notification. The priority acts
+ as a hint to the device UI about how the notification should be displayed.
+ To set a notification's priority, call {@link
+ android.support.v4.app.NotificationCompat.Builder#setPriority(int)
+ NotificationCompat.Builder.setPriority()} and pass in one of the {@link
+ android.support.v4.app.NotificationCompat} priority constants. There are
+ five priority levels, ranging from {@link
+ android.support.v4.app.NotificationCompat#PRIORITY_MIN} (-2) to {@link
+ android.support.v4.app.NotificationCompat#PRIORITY_MAX} (2); if not set, the
+ priority defaults to {@link
+ android.support.v4.app.NotificationCompat#PRIORITY_DEFAULT} (0).
+</p>
+<p> For information about setting an appropriate priority level, see "Correctly
+ set and manage notification priority" in the <a
+ href="{@docRoot}design/patterns/notifications.html">Notifications</a> Design
+ guide.
+</p>
+<!-- ------------------------------------------------------------------------------------------ -->
<h3 id="SimpleNotification">Creating a simple notification</h3>
<p>
The following snippet illustrates a simple notification that specifies an activity to open when
diff --git a/docs/html/images/blog.jpg b/docs/html/images/blog.jpg
new file mode 100644
index 0000000..a3ee7d8
--- /dev/null
+++ b/docs/html/images/blog.jpg
Binary files differ
diff --git a/docs/html/images/device-art-ex-crop.jpg b/docs/html/images/device-art-ex-crop.jpg
new file mode 100644
index 0000000..42c769b
--- /dev/null
+++ b/docs/html/images/device-art-ex-crop.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-0.jpg b/docs/html/images/gp-about-0.jpg
new file mode 100644
index 0000000..2dd6a8c
--- /dev/null
+++ b/docs/html/images/gp-about-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-listing.jpg b/docs/html/images/gp-about-listing.jpg
new file mode 100644
index 0000000..256c051
--- /dev/null
+++ b/docs/html/images/gp-about-listing.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-picks1.jpg b/docs/html/images/gp-about-picks1.jpg
new file mode 100644
index 0000000..555bd7b
--- /dev/null
+++ b/docs/html/images/gp-about-picks1.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-picks2.jpg b/docs/html/images/gp-about-picks2.jpg
new file mode 100644
index 0000000..ec25e74
--- /dev/null
+++ b/docs/html/images/gp-about-picks2.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-picks3.jpg b/docs/html/images/gp-about-picks3.jpg
new file mode 100644
index 0000000..eb57da9
--- /dev/null
+++ b/docs/html/images/gp-about-picks3.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-top.jpg b/docs/html/images/gp-about-top.jpg
new file mode 100644
index 0000000..01a2744
--- /dev/null
+++ b/docs/html/images/gp-about-top.jpg
Binary files differ
diff --git a/docs/html/images/gp-androidify.png b/docs/html/images/gp-androidify.png
new file mode 100644
index 0000000..122d596
--- /dev/null
+++ b/docs/html/images/gp-androidify.png
Binary files differ
diff --git a/docs/html/images/gp-apps-home.png b/docs/html/images/gp-apps-home.png
deleted file mode 100644
index 851f722..0000000
--- a/docs/html/images/gp-apps-home.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-badge-jp.png b/docs/html/images/gp-badge-jp.png
new file mode 100644
index 0000000..00b5d1f
--- /dev/null
+++ b/docs/html/images/gp-badge-jp.png
Binary files differ
diff --git a/docs/html/images/gp-badges-set.png b/docs/html/images/gp-badges-set.png
new file mode 100644
index 0000000..e2e0e94
--- /dev/null
+++ b/docs/html/images/gp-badges-set.png
Binary files differ
diff --git a/docs/html/images/gp-balance.png b/docs/html/images/gp-balance.png
new file mode 100644
index 0000000..7802bcc
--- /dev/null
+++ b/docs/html/images/gp-balance.png
Binary files differ
diff --git a/docs/html/images/gp-build-buzz-yt.png b/docs/html/images/gp-build-buzz-yt.png
new file mode 100644
index 0000000..7901aa5
--- /dev/null
+++ b/docs/html/images/gp-build-buzz-yt.png
Binary files differ
diff --git a/docs/html/images/gp-buzz-1.jpg b/docs/html/images/gp-buzz-1.jpg
new file mode 100644
index 0000000..ce2444b
--- /dev/null
+++ b/docs/html/images/gp-buzz-1.jpg
Binary files differ
diff --git a/docs/html/images/gp-collectibles.png b/docs/html/images/gp-collectibles.png
deleted file mode 100644
index a63cd50..0000000
--- a/docs/html/images/gp-collectibles.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-community-0.png b/docs/html/images/gp-community-0.png
new file mode 100644
index 0000000..bb8fde2
--- /dev/null
+++ b/docs/html/images/gp-community-0.png
Binary files differ
diff --git a/docs/html/images/gp-core-quality.png b/docs/html/images/gp-core-quality.png
new file mode 100644
index 0000000..196459f
--- /dev/null
+++ b/docs/html/images/gp-core-quality.png
Binary files differ
diff --git a/docs/html/images/gp-dc-ab.png b/docs/html/images/gp-dc-ab.png
new file mode 100644
index 0000000..0604a1b
--- /dev/null
+++ b/docs/html/images/gp-dc-ab.png
Binary files differ
diff --git a/docs/html/images/gp-dc-inapp.jpg b/docs/html/images/gp-dc-inapp.jpg
new file mode 100644
index 0000000..e830e31
--- /dev/null
+++ b/docs/html/images/gp-dc-inapp.jpg
Binary files differ
diff --git a/docs/html/images/gp-dc-invite.png b/docs/html/images/gp-dc-invite.png
new file mode 100644
index 0000000..403b53d
--- /dev/null
+++ b/docs/html/images/gp-dc-invite.png
Binary files differ
diff --git a/docs/html/images/gp-dc-startscreen.jpg b/docs/html/images/gp-dc-startscreen.jpg
new file mode 100644
index 0000000..afaa91b
--- /dev/null
+++ b/docs/html/images/gp-dc-startscreen.jpg
Binary files differ
diff --git a/docs/html/images/gp-details-pages-magicpiano.png b/docs/html/images/gp-details-pages-magicpiano.png
deleted file mode 100644
index 4bb1962..0000000
--- a/docs/html/images/gp-details-pages-magicpiano.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-details-ww.png b/docs/html/images/gp-details-ww.png
deleted file mode 100644
index ccc522c..0000000
--- a/docs/html/images/gp-details-ww.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-e-value.png b/docs/html/images/gp-e-value.png
new file mode 100644
index 0000000..86c8f86
--- /dev/null
+++ b/docs/html/images/gp-e-value.png
Binary files differ
diff --git a/docs/html/images/gp-ecom-0.png b/docs/html/images/gp-ecom-0.png
new file mode 100644
index 0000000..22b6040
--- /dev/null
+++ b/docs/html/images/gp-ecom-0.png
Binary files differ
diff --git a/docs/html/images/gp-edu-monetize.png b/docs/html/images/gp-edu-monetize.png
new file mode 100644
index 0000000..6db273c
--- /dev/null
+++ b/docs/html/images/gp-edu-monetize.png
Binary files differ
diff --git a/docs/html/images/gp-edu-optin-console.jpg b/docs/html/images/gp-edu-optin-console.jpg
new file mode 100644
index 0000000..239b966
--- /dev/null
+++ b/docs/html/images/gp-edu-optin-console.jpg
Binary files differ
diff --git a/docs/html/images/gp-edu-quality.png b/docs/html/images/gp-edu-quality.png
new file mode 100644
index 0000000..b103483
--- /dev/null
+++ b/docs/html/images/gp-edu-quality.png
Binary files differ
diff --git a/docs/html/images/gp-engage-0.jpg b/docs/html/images/gp-engage-0.jpg
new file mode 100644
index 0000000..b4f44b5
--- /dev/null
+++ b/docs/html/images/gp-engage-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-engage-5.jpg b/docs/html/images/gp-engage-5.jpg
new file mode 100644
index 0000000..10fa0c2
--- /dev/null
+++ b/docs/html/images/gp-engage-5.jpg
Binary files differ
diff --git a/docs/html/images/gp-engage-6.jpg b/docs/html/images/gp-engage-6.jpg
new file mode 100644
index 0000000..2da09e1
--- /dev/null
+++ b/docs/html/images/gp-engage-6.jpg
Binary files differ
diff --git a/docs/html/images/gp-engage-9.jpg b/docs/html/images/gp-engage-9.jpg
new file mode 100644
index 0000000..46b94f0
--- /dev/null
+++ b/docs/html/images/gp-engage-9.jpg
Binary files differ
diff --git a/docs/html/images/gp-engage-share-plus.png b/docs/html/images/gp-engage-share-plus.png
new file mode 100644
index 0000000..a1aa46e
--- /dev/null
+++ b/docs/html/images/gp-engage-share-plus.png
Binary files differ
diff --git a/docs/html/images/gp-engage-smule.jpg b/docs/html/images/gp-engage-smule.jpg
new file mode 100644
index 0000000..087da79
--- /dev/null
+++ b/docs/html/images/gp-engage-smule.jpg
Binary files differ
diff --git a/docs/html/images/gp-expand-2.jpg b/docs/html/images/gp-expand-2.jpg
new file mode 100644
index 0000000..a7b6916
--- /dev/null
+++ b/docs/html/images/gp-expand-2.jpg
Binary files differ
diff --git a/docs/html/images/gp-expand-4.jpg b/docs/html/images/gp-expand-4.jpg
new file mode 100644
index 0000000..1d5b1a1
--- /dev/null
+++ b/docs/html/images/gp-expand-4.jpg
Binary files differ
diff --git a/docs/html/images/gp-expand-5.jpg b/docs/html/images/gp-expand-5.jpg
new file mode 100644
index 0000000..b2b2264
--- /dev/null
+++ b/docs/html/images/gp-expand-5.jpg
Binary files differ
diff --git a/docs/html/images/gp-freemium-0.jpg b/docs/html/images/gp-freemium-0.jpg
new file mode 100644
index 0000000..767c1f3
--- /dev/null
+++ b/docs/html/images/gp-freemium-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-freemium-1.jpg b/docs/html/images/gp-freemium-1.jpg
new file mode 100644
index 0000000..1e509c5
--- /dev/null
+++ b/docs/html/images/gp-freemium-1.jpg
Binary files differ
diff --git a/docs/html/images/gp-games-home.png b/docs/html/images/gp-games-home.png
deleted file mode 100644
index 81b7f7a..0000000
--- a/docs/html/images/gp-games-home.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-growth-downloads.png b/docs/html/images/gp-growth-downloads.png
deleted file mode 100644
index 4a4b194..0000000
--- a/docs/html/images/gp-growth-downloads.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-launch-checklist-1.png b/docs/html/images/gp-launch-checklist-1.png
new file mode 100644
index 0000000..069cd69
--- /dev/null
+++ b/docs/html/images/gp-launch-checklist-1.png
Binary files differ
diff --git a/docs/html/images/gp-linking-ex-crop.png b/docs/html/images/gp-linking-ex-crop.png
new file mode 100644
index 0000000..c108651
--- /dev/null
+++ b/docs/html/images/gp-linking-ex-crop.png
Binary files differ
diff --git a/docs/html/images/gp-listing-0.jpg b/docs/html/images/gp-listing-0.jpg
new file mode 100644
index 0000000..a204f9f
--- /dev/null
+++ b/docs/html/images/gp-listing-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-listing-1.png b/docs/html/images/gp-listing-1.png
new file mode 100644
index 0000000..ed15d96
--- /dev/null
+++ b/docs/html/images/gp-listing-1.png
Binary files differ
diff --git a/docs/html/images/gp-listing-2.jpg b/docs/html/images/gp-listing-2.jpg
new file mode 100644
index 0000000..73304f4
--- /dev/null
+++ b/docs/html/images/gp-listing-2.jpg
Binary files differ
diff --git a/docs/html/images/gp-listing-3.jpg b/docs/html/images/gp-listing-3.jpg
new file mode 100644
index 0000000..a4def2e
--- /dev/null
+++ b/docs/html/images/gp-listing-3.jpg
Binary files differ
diff --git a/docs/html/images/gp-listing-4.jpg b/docs/html/images/gp-listing-4.jpg
new file mode 100644
index 0000000..f580f86
--- /dev/null
+++ b/docs/html/images/gp-listing-4.jpg
Binary files differ
diff --git a/docs/html/images/gp-localization-trans-0.png b/docs/html/images/gp-localization-trans-0.png
new file mode 100644
index 0000000..2e7b73e
--- /dev/null
+++ b/docs/html/images/gp-localization-trans-0.png
Binary files differ
diff --git a/docs/html/images/gp-optimize-analytics.png b/docs/html/images/gp-optimize-analytics.png
new file mode 100644
index 0000000..81298d0
--- /dev/null
+++ b/docs/html/images/gp-optimize-analytics.png
Binary files differ
diff --git a/docs/html/images/gp-optimize-speed.png b/docs/html/images/gp-optimize-speed.png
new file mode 100644
index 0000000..6ebb995
--- /dev/null
+++ b/docs/html/images/gp-optimize-speed.png
Binary files differ
diff --git a/docs/html/images/gp-optimize.png b/docs/html/images/gp-optimize.png
new file mode 100644
index 0000000..e8388ea
--- /dev/null
+++ b/docs/html/images/gp-optimize.png
Binary files differ
diff --git a/docs/html/images/gp-optimizing-chat-bubbles.png b/docs/html/images/gp-optimizing-chat-bubbles.png
new file mode 100644
index 0000000..71ac767
--- /dev/null
+++ b/docs/html/images/gp-optimizing-chat-bubbles.png
Binary files differ
diff --git a/docs/html/images/gp-optimizing-image-4.jpg b/docs/html/images/gp-optimizing-image-4.jpg
new file mode 100644
index 0000000..949ca81
--- /dev/null
+++ b/docs/html/images/gp-optimizing-image-4.jpg
Binary files differ
diff --git a/docs/html/images/gp-payments-1.png b/docs/html/images/gp-payments-1.png
new file mode 100644
index 0000000..6eaca93
--- /dev/null
+++ b/docs/html/images/gp-payments-1.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-eula-violation.png b/docs/html/images/gp-policy-ads-eula-violation.png
deleted file mode 100644
index 204c320..0000000
--- a/docs/html/images/gp-policy-ads-eula-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-impersonate-violation-app-ui.png b/docs/html/images/gp-policy-ads-impersonate-violation-app-ui.png
deleted file mode 100644
index a2a39a9..0000000
--- a/docs/html/images/gp-policy-ads-impersonate-violation-app-ui.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-impersonate-violation-sys-warning.png b/docs/html/images/gp-policy-ads-impersonate-violation-sys-warning.png
deleted file mode 100644
index f323b06..0000000
--- a/docs/html/images/gp-policy-ads-impersonate-violation-sys-warning.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-impersonate-violation.png b/docs/html/images/gp-policy-ads-impersonate-violation.png
deleted file mode 100644
index 385ae6e..0000000
--- a/docs/html/images/gp-policy-ads-impersonate-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-interstitial-violation.png b/docs/html/images/gp-policy-ads-interstitial-violation.png
deleted file mode 100644
index 4871493..0000000
--- a/docs/html/images/gp-policy-ads-interstitial-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-maturity-violation.png b/docs/html/images/gp-policy-ads-maturity-violation.png
deleted file mode 100644
index d41870e..0000000
--- a/docs/html/images/gp-policy-ads-maturity-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-notif-attr-violation.png b/docs/html/images/gp-policy-ads-notif-attr-violation.png
deleted file mode 100644
index 3d6393b..0000000
--- a/docs/html/images/gp-policy-ads-notif-attr-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-notif-attr.png b/docs/html/images/gp-policy-ads-notif-attr.png
deleted file mode 100644
index da39cfb..0000000
--- a/docs/html/images/gp-policy-ads-notif-attr.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-paywall-violation.png b/docs/html/images/gp-policy-ads-paywall-violation.png
deleted file mode 100644
index 8bbfd1b..0000000
--- a/docs/html/images/gp-policy-ads-paywall-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-paywall.png b/docs/html/images/gp-policy-ads-paywall.png
deleted file mode 100644
index e7b1e19..0000000
--- a/docs/html/images/gp-policy-ads-paywall.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-terms.png b/docs/html/images/gp-policy-ads-terms.png
deleted file mode 100644
index dcbdf4a..0000000
--- a/docs/html/images/gp-policy-ads-terms.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ip-copyright-violation.png b/docs/html/images/gp-policy-ip-copyright-violation.png
deleted file mode 100644
index a4e96a8..0000000
--- a/docs/html/images/gp-policy-ip-copyright-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ip-impersonation-violation.png b/docs/html/images/gp-policy-ip-impersonation-violation.png
deleted file mode 100644
index b1d9923..0000000
--- a/docs/html/images/gp-policy-ip-impersonation-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ip-trademark-violation.png b/docs/html/images/gp-policy-ip-trademark-violation.png
deleted file mode 100644
index c05b67b..0000000
--- a/docs/html/images/gp-policy-ip-trademark-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-spam-negreview.png b/docs/html/images/gp-policy-spam-negreview.png
deleted file mode 100644
index f68eba3..0000000
--- a/docs/html/images/gp-policy-spam-negreview.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-spam-reqrating.png b/docs/html/images/gp-policy-spam-reqrating.png
deleted file mode 100644
index 20e17c1..0000000
--- a/docs/html/images/gp-policy-spam-reqrating.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-premium-0.png b/docs/html/images/gp-premium-0.png
new file mode 100644
index 0000000..4bacc25
--- /dev/null
+++ b/docs/html/images/gp-premium-0.png
Binary files differ
diff --git a/docs/html/images/gp-rating-web.png b/docs/html/images/gp-rating-web.png
index 0885826..14582af 100644
--- a/docs/html/images/gp-rating-web.png
+++ b/docs/html/images/gp-rating-web.png
Binary files differ
diff --git a/docs/html/images/gp-sendto.png b/docs/html/images/gp-sendto.png
deleted file mode 100644
index 7409c14..0000000
--- a/docs/html/images/gp-sendto.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-start-button.png b/docs/html/images/gp-start-button.png
new file mode 100644
index 0000000..fa3d5e1
--- /dev/null
+++ b/docs/html/images/gp-start-button.png
Binary files differ
diff --git a/docs/html/images/gp-start-wallet-icon.png b/docs/html/images/gp-start-wallet-icon.png
new file mode 100644
index 0000000..3ecbcf6
--- /dev/null
+++ b/docs/html/images/gp-start-wallet-icon.png
Binary files differ
diff --git a/docs/html/images/gp-subs.png b/docs/html/images/gp-subs.png
deleted file mode 100644
index 9b3a7df..0000000
--- a/docs/html/images/gp-subs.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-subscription-0.jpg b/docs/html/images/gp-subscription-0.jpg
new file mode 100644
index 0000000..0c4b389
--- /dev/null
+++ b/docs/html/images/gp-subscription-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-tab.png b/docs/html/images/gp-tab.png
deleted file mode 100644
index 4673d21..0000000
--- a/docs/html/images/gp-tab.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-tablet-quality-4.jpg b/docs/html/images/gp-tablet-quality-4.jpg
new file mode 100644
index 0000000..33dfcbd
--- /dev/null
+++ b/docs/html/images/gp-tablet-quality-4.jpg
Binary files differ
diff --git a/docs/html/images/gp-tablet-quality-5.jpg b/docs/html/images/gp-tablet-quality-5.jpg
new file mode 100644
index 0000000..668482a
--- /dev/null
+++ b/docs/html/images/gp-tablet-quality-5.jpg
Binary files differ
diff --git a/docs/html/images/gp-tablets-full-feature-set.png b/docs/html/images/gp-tablets-full-feature-set.png
new file mode 100644
index 0000000..fa04082
--- /dev/null
+++ b/docs/html/images/gp-tablets-full-feature-set.png
Binary files differ
diff --git a/docs/html/images/gp-top-new-paid.png b/docs/html/images/gp-top-new-paid.png
deleted file mode 100644
index d98d6ca..0000000
--- a/docs/html/images/gp-top-new-paid.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-your-user-0.jpg b/docs/html/images/gp-your-user-0.jpg
new file mode 100644
index 0000000..9286b54
--- /dev/null
+++ b/docs/html/images/gp-your-user-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-your-user-2.jpg b/docs/html/images/gp-your-user-2.jpg
new file mode 100644
index 0000000..0f44e2a
--- /dev/null
+++ b/docs/html/images/gp-your-user-2.jpg
Binary files differ
diff --git a/docs/html/images/gpfe-developer.png b/docs/html/images/gpfe-developer.png
new file mode 100644
index 0000000..4b3251c
--- /dev/null
+++ b/docs/html/images/gpfe-developer.png
Binary files differ
diff --git a/docs/html/images/gpfe-educator.png b/docs/html/images/gpfe-educator.png
new file mode 100644
index 0000000..6e49a7fd
--- /dev/null
+++ b/docs/html/images/gpfe-educator.png
Binary files differ
diff --git a/docs/html/images/gpfe-start-0.jpg b/docs/html/images/gpfe-start-0.jpg
new file mode 100644
index 0000000..e97381d
--- /dev/null
+++ b/docs/html/images/gpfe-start-0.jpg
Binary files differ
diff --git a/docs/html/images/gpp-cat-feature280-photo.png b/docs/html/images/gpp-cat-feature280-photo.png
deleted file mode 100644
index ae2749b..0000000
--- a/docs/html/images/gpp-cat-feature280-photo.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gpp-cat-feature280-puzzle.png b/docs/html/images/gpp-cat-feature280-puzzle.png
deleted file mode 100644
index db203c6..0000000
--- a/docs/html/images/gpp-cat-feature280-puzzle.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gpp-cat-feature280-sports.png b/docs/html/images/gpp-cat-feature280-sports.png
deleted file mode 100644
index dcd70aa..0000000
--- a/docs/html/images/gpp-cat-feature280-sports.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/play_dev.jpg b/docs/html/images/play_dev.jpg
new file mode 100644
index 0000000..6aae165
--- /dev/null
+++ b/docs/html/images/play_dev.jpg
Binary files differ
diff --git a/docs/html/images/play_dev.png b/docs/html/images/play_dev_sm.png
similarity index 100%
rename from docs/html/images/play_dev.png
rename to docs/html/images/play_dev_sm.png
Binary files differ
diff --git a/docs/html/images/plus.jpg b/docs/html/images/plus.jpg
new file mode 100644
index 0000000..652aa1a
--- /dev/null
+++ b/docs/html/images/plus.jpg
Binary files differ
diff --git a/docs/html/images/tools/studio_error_gradle5.png b/docs/html/images/tools/studio_error_gradle5.png
deleted file mode 100644
index 13de607..0000000
--- a/docs/html/images/tools/studio_error_gradle5.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/tools/studio_error_supportlib.png b/docs/html/images/tools/studio_error_supportlib.png
deleted file mode 100644
index 603b54c..0000000
--- a/docs/html/images/tools/studio_error_supportlib.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/video-Colopl.png b/docs/html/images/video-Colopl.png
deleted file mode 100644
index 0ee88c6..0000000
--- a/docs/html/images/video-Colopl.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 99a469a..a4b0683 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -39,13 +39,12 @@
<script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
<div style="box-shadow: 3px 10px 18px 1px #999;width:600px;height:336px">
<div id="ytapiplayer">
- <a href="http://www.youtube.com/watch?v=i2uvYI6blEE"><img width=600
- src="https://i1.ytimg.com/vi/i2uvYI6blEE/maxresdefault.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
+ <a href="http://www.youtube.com/watch?v=WWArLD6nqrk"><img width=600 src="{@docRoot}images/video-kiwi.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
</div>
<script type="text/javascript">
var params = { allowScriptAccess: "always" };
var atts = { id: "ytapiplayer" };
- swfobject.embedSWF("//www.youtube.com/v/i2uvYI6blEE?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
+ swfobject.embedSWF("//www.youtube.com/v/WWArLD6nqrk?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
"ytapiplayer", "600", "336", "8", null, null, params, atts);
// Callback used to pause/resume carousel based on video state
@@ -74,9 +73,10 @@
</div>
</div>
<div class="content-right col-4">
- <h1 style="white-space:nowrap;line-height:1.2em;">Developer Story: <br />Box Inc.</h1>
- <p>Box is a cloud-based platform and app for users to share business information. See how they got over 5 million downloads by leveraging the flexibility in the Android platform.</p>
- <p><a href="{@docRoot}distribute/googleplay/spotlight/index.html" class="button">Watch more videos </a></p>
+ <h1 style="white-space:nowrap;line-height:1.2em;">Developer Story: <br />Kiwi, Inc.</h1>
+ <p>Game developer Kiwi has had five titles in the top 25 grossing on Google Play. Hear how Google Play
+ has helped them double revenue every six months.</p>
+ <p><a href="{@docRoot}distribute/stories/index.html" class="button">Watch more videos </a></p>
</div>
</li>
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
new file mode 100644
index 0000000..8a4ac47
--- /dev/null
+++ b/docs/html/jd_collections.js
@@ -0,0 +1,697 @@
+var RESOURCE_COLLECTIONS = {
+ "launch/static": {
+ "title": "",
+ "resources": [
+ "http://www.youtube.com/watch?v=1RIz-cmTQB4",
+ "http://www.youtube.com/watch?v=MVBMWDzyHAI",
+ "http://android-developers.blogspot.com/2013/11/app-translation-service-now-available.html",
+ "http://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
+ "http://android-developers.blogspot.com/2013/11/bring-your-apps-into-classroom-with.html",
+ "distribute/essentials/quality/tablets.html",
+ "distribute/users/build-buzz.html",
+ "distribute/monetize/premium.html",
+ "distribute/monetize/freemium.html",
+ "distribute/monetize/ads.html",
+ "distribute/essentials/best-practices/apps.html",
+ "distribute/essentials/best-practices/games.html",
+ "distribute/users/know-your-user.html",
+ "distribute/googleplay/developer-console.html"
+ ]
+ },
+ "distribute/gp/gplanding": {
+ "resources": [
+ "distribute/googleplay/about.html",
+ "distribute/googleplay/start.html",
+ "distribute/googleplay/developer-console.html"
+ ]
+ },
+ "distribute/gp/gpfelanding": {
+ "resources": [
+ "distribute/googleplay/edu/about.html",
+ "distribute/googleplay/edu/start.html",
+ "distribute/googleplay/edu/faq.html"
+ ]
+ },
+ "distribute/essentials": {
+ "resources": [
+ "distribute/essentials/quality/core.html",
+ "distribute/essentials/quality/tablets.html",
+ "distribute/essentials/gpfe-guidelines.html",
+ "distribute/essentials/optimizing-your-app.html",
+ "distribute/essentials/best-practices/apps.html",
+ "distribute/essentials/best-practices/games.html"
+ ]
+ },
+ "distribute/users": {
+ "title": "",
+ "resources": [
+ "distribute/users/know-your-user.html",
+ "distribute/users/your-listing.html",
+ "distribute/users/build-buzz.html",
+ "distribute/users/build-community.html",
+ "distribute/users/expand-to-new-markets.html"
+ ]
+ },
+ "distribute/engagelanding": {
+ "resources": [
+ "distribute/engage/widgets.html",
+ "distribute/engage/notifications.html",
+ "distribute/engage/gcm.html",
+ "distribute/engage/easy-signin.html",
+ "distribute/engage/deep-linking.html",
+ "distribute/engage/game-services.html",
+ "distribute/engage/app-updates.html",
+ "distribute/engage/community.html",
+ "distribute/engage/video.html"
+ ]
+ },
+ "distribute/monetize": {
+ "resources": [
+ "distribute/monetize/premium.html",
+ "distribute/monetize/freemium.html",
+ "distribute/monetize/subscriptions.html",
+ "distribute/monetize/ecommerce.html",
+ "distribute/monetize/ads.html",
+ "distribute/monetize/payments.html"
+ ]
+ },
+ "distribute/tools/checklists": {
+ "title": "",
+ "resources": [
+ "distribute/tools/launch-checklist.html",
+ "distribute/tools/localization-checklist.html"
+ ]
+ },
+ "distribute/tools/promote": {
+ "resources": [
+ "distribute/tools/promote/device-art.html",
+ "distribute/tools/promote/badges.html",
+ "distribute/tools/promote/linking.html"
+ ]
+ },
+ "distribute/tools/support": {
+ "title": "Google Play",
+ "resources": [
+ "https://support.google.com/googleplay/android-developer",
+ "https://support.google.com/googleplay/android-developer/answer/4430948",
+ "support.html"
+ ]
+ },
+ "distribute/tools/news": {
+ "title": "",
+ "resources": [
+ "http://android-developers.blogspot.com/",
+ "https://plus.google.com/+AndroidDevelopers/"
+ ]
+ },
+ "distribute/tools/more": {
+ "title": "Google Play",
+ "resources": [
+ "distribute/tools/promote/brand.html",
+ "distribute/tools/open-distribution.html",
+ "about/dashboards/index.html"
+ ]
+ },
+ "distribute/googleplay": {
+ "title": "Google Play",
+ "resources": [
+ "distribute/googleplay/developer-console.html",
+ "distribute/essentials/best-practices/apps.html",
+ "distribute/tools/launch-checklist.html",
+ "distribute/essentials/best-practices/games.html",
+ ]
+ },
+ "distribute/googleplay/gettingstarted": {
+ "title": "Get Started",
+ "resources": [
+ "distribute/googleplay/developer-console.html",
+ "https://support.google.com/googleplay/android-developer/answer/113468",
+ "https://support.google.com/googleplay/android-developer/answer/138294",
+ "https://support.google.com/googleplay/android-developer"
+ ]
+ },
+ "distribute/googleplay/developerconsole": {
+ "title": "Developer Console",
+ "resources": [
+ "google/play/billing/index.html",
+ "https://support.google.com/googleplay/android-developer/answer/138294"
+ ]
+ },
+ "distribute/googleplay/gpfe/highlight": {
+ "title": "About Google Play for Education",
+ "resources": [
+ "http://youtu.be/vzvpcEffvaE"
+ ]
+ },
+ "distribute/googleplay/gpfe/dev/about": {
+ "title": "About Google Play for Education / Developers",
+ "resources": [
+ "distribute/googleplay/edu/start.html",
+ "distribute/essentials/gpfe-guidelines.html",
+ "distribute/googleplay/edu/faq.html",
+ "distribute/essentials/quality/tablets.html"
+ ]
+ },
+ "distribute/googleplay/gpfe/dev": {
+ "title": "About Google Play for Education / Developers",
+ "resources": [
+ "distribute/googleplay/edu/about.html",
+ "distribute/essentials/gpfe-guidelines.html",
+ "distribute/essentials/quality/tablets.html",
+ "distribute/googleplay/developer-console.html",
+ "http://play.google.com/about/developer-distribution-agreement-addendum.html",
+ ]
+ },
+ "distribute/googleplay/aboutgpfe/educators/about": {
+ "title": "About Google Play for Education / Educators",
+ "resources": [
+ "http://www.google.com/edu/tablets/",
+ "http://www.youtube.com/watch?v=haEmsMo0f3w"
+ ]
+ },
+ "distribute/googleplay/aboutgpfe/educators": {
+ "title": "About Google Play for Education / Educators",
+ "resources": [
+ "http://www.google.com/edu/tablets/",
+ "http://youtu.be/vzvpcEffvaE"
+ ]
+ },
+ "distribute/googleplay/gettingstartedgpfe/educators": {
+ "title": "About Google Play for Education / Educators",
+ "resources": [
+ "http://www.google.com/edu/tablets/",
+ "http://youtu.be/vzvpcEffvaE"
+ ]
+ },
+ "distribute/essentials/eduessentials/developers": {
+ "title": "",
+ "resources": [
+ "distribute/googleplay/developer-console.html",
+ "distribute/googleplay/edu/start.html",
+ "distribute/googleplay/edu/faq.html"
+ ]
+ },
+ "distribute/essentials/eduessentials/educators": {
+ "title": "",
+ "resources": [
+ "http://www.google.com/edu/tablets/",
+ "distribute/essentials/quality/tablets.html",
+ ]
+ },
+ "distribute/essentials/optimizing": {
+ "title": "Optimizing Your App",
+ "resources": [
+ "design/index.html",
+ "training/articles/perf-anr.html",
+ "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html"
+ ]
+ },
+ "distribute/users/knowyouruser": {
+ "title": "",
+ "resources": [
+ "distribute/essentials/optimizing-your-app.html",
+ "http://www.youtube.com/watch?v=RRelFvc6Czo",
+ "distribute/stories/localization.html"
+ ]
+ },
+ "distribute/users/buildbuzz": {
+ "title": "",
+ "resources": [
+ "distribute/tools/promote/badges.html",
+ "distribute/tools/promote/linking.html",
+ "distribute/tools/promote/device-art.html",
+ "http://plus.google.com/+GooglePlay"
+ ]
+ },
+ "distribute/users/createagreatlisting": {
+ "title": "",
+ "resources": [
+ "https://support.google.com/googleplay/android-developer/answer/1078870",
+ "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
+ "distribute/tools/launch-checklist.html",
+ "http://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html",
+ "http://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html",
+ "http://android-developers.blogspot.com/2013/10/making-your-app-content-more-accessible.html"
+ ]
+ },
+ "distribute/users/buildcommunity": {
+ "title": "",
+ "resources": [
+ "distribute/googleplay/developer-console.html",
+ "https://support.google.com/groups/answer/46601",
+ "https://support.google.com/plus/topic/2888488",
+ "http://www.youtube.com/yt/dev/"
+ ]
+ },
+ "distribute/toolsreference/bestpractices/apps": {
+ "title": "",
+ "resources": [
+ "distribute/googleplay/developer-console.html",
+ "http://android-developers.blogspot.com/"
+ ]
+ },
+ "distribute/toolsreference/bestpractices/games": {
+ "title": "",
+ "resources": [
+ "google/play-services/games.html",
+ "http://android-developers.blogspot.com/",
+ "distribute/googleplay/developer-console.html",
+ "http://www.youtube.com/watch?v=1RIz-cmTQB4"
+ ]
+ },
+ "distribute/essentials/corequalityguidelines/visualdesign": {
+ "title": "",
+ "resources": [
+ "design/index.html",
+ "design/patterns/navigation.html",
+ "design/patterns/actionbar.html",
+ "design/style/iconography.html",
+ "design/patterns/notifications.html"
+ ]
+ },
+ "distribute/essentials/corequalityguidelines/functionality": {
+ "title": "",
+ "resources": [
+ "http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html",
+ "guide/components/tasks-and-back-stack.html",
+ "training/basics/activity-lifecycle/recreating.html"
+ ]
+ },
+ "distribute/essentials/core/performance": {
+ "title": "",
+ "resources": [
+ "http://android-developers.blogspot.com/2010/12/new-gingerbread-api-strictmode.html",
+ "training/articles/perf-anr.html",
+ "http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html"
+ ]
+ },
+ "distribute/essentials/core/play": {
+ "title": "",
+ "resources": [
+ "distribute/tools/launch-checklist.html",
+ "http://play.google.com/about/developer-content-policy.html",
+ "https://support.google.com/googleplay/android-developer/answer/188189",
+ "https://support.google.com/googleplay/android-developer/answer/1078870",
+ "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
+ "https://support.google.com/googleplay/android-developer/answer/113477"
+ ]
+ },
+ "distribute/essentials/tabletguidelines/optimize": {
+ "title": "",
+ "resources": [
+ "design/style/metrics-grids.html",
+ "design/style/devices-displays.html",
+ "guide/practices/screens_support.html",
+ //"guide/practices/screens_support.html#ConfigurationExamples",
+ ]
+ },
+ "distribute/essentials/tabletguidelines/extrascreen": {
+ "title": "",
+ "resources": [
+ "design/patterns/multi-pane-layouts.html",
+ "training/design-navigation/multiple-sizes.html",
+ "training/multiscreen/index.html",
+ ]
+ },
+ "distribute/essentials/tabletguidelines/assets": {
+ "title": "",
+ "resources": [
+ "design/style/iconography.html",
+ "guide/topics/resources/providing-resources.html",
+ "guide/practices/screens_support.html",
+ "training/basics/supporting-devices/screens.html"
+ ]
+ },
+ "distribute/essentials/tabletguidelines/fonts": {
+ "title": "",
+ "resources": [
+ "design/style/metrics-grids.html",
+ "design/style/typography.html",
+ "guide/practices/screens_support.html",
+ "training/multiscreen/screendensities.html"
+ ]
+ },
+ "distribute/essentials/tabletguidelines/widgets": {
+ "title": "",
+ "resources": [
+ "guide/topics/appwidgets/index.html#MetaData",
+ "guide/topics/appwidgets/index.html",
+ "design/patterns/widgets.html"
+ ]
+ },
+ "distribute/essentials/tabletguidelines/versions": {
+ "title": "",
+ "resources": [
+ "guide/topics/manifest/uses-sdk-element.html#ApiLevels",
+ "guide/topics/manifest/uses-sdk-element.html",
+ "training/basics/supporting-devices/platforms.html"
+ ]
+ },
+ "distribute/essentials/tabletguidelines/hardware": {
+ "title": "",
+ "resources": [
+ "guide/topics/manifest/uses-feature-element.html",
+ "guide/topics/manifest/uses-feature-element.html#testing"
+ ]
+ },
+ "distribute/essentials/tabletguidelines/tabletscreens": {
+ "title": "",
+ "resources": [
+ "guide/practices/screens_support.html#DeclaringScreenSizeSupport",
+ "guide/practices/screens_support.html"
+ ]
+ },
+ "distribute/essentials/tabletguidelines/showcase": {
+ "title": "",
+ "resources": [
+ "distribute/tools/launch-checklist.html",
+ "https://play.google.com/apps/publish/",
+ "distribute/tools/promote/badges.html",
+ "distribute/tools/promote/device-art.html"
+ ]
+ },
+ "distribute/essentials/tabletguidelines/googleplay": {
+ "title": "",
+ "resources": [
+ "http://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
+ "google/play/filters.html"
+ ]
+ },
+ "distribute/essentials/tabletguidelines": {
+ "title": "",
+ "resources": [
+ "distribute/essentials/quality/core.html",
+ "http://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
+ "distribute/tools/launch-checklist.html",
+ "distribute/tools/promote/device-art.html"
+ ]
+ },
+ "distribute/getusers/notifications": {
+ "title": "",
+ "resources": [
+ "design/patterns/notifications.html",
+ "distribute/engage/gcm.html",
+ "http://play.google.com/about/developer-content-policy.html"
+ ]
+ },
+ "distribute/engage/widgets": {
+ "title": "",
+ "resources": [
+ "design/patterns/widgets.html",
+ "guide/topics/appwidgets/index.html"
+ ]
+ },
+ "distribute/getusers/expandnewmarkets": {
+ "title": "",
+ "resources": [
+ "distribute/tools/localization-checklist.html",
+ "https://support.google.com/googleplay/android-developer/table/3541286",
+ "distribute/stories/localization.html",
+ "distribute/tools/promote/badges.html",
+ "distribute/tools/promote/device-art.html",
+ "http://www.youtube.com/watch?v=SkHHPf3EdzE"
+ ]
+ },
+ "distribute/engage/gcm": {
+ "title": "",
+ "resources": [
+ "google/gcm/index.html",
+ "http://developer.chrome.com/apps/cloudMessagingV2",
+ "http://www.youtube.com/watch?v=y76rjidm8cU"
+ ]
+ },
+ "distribute/engage/googleplaygames": {
+ "title": "",
+ "resources": [
+ "google/play-services/games.html",
+ "distribute/essentials/best-practices/games.html"
+ ]
+ },
+ "distribute/engage/gplus": {
+ "title": "",
+ "resources": [
+ "google/play-services/plus.html",
+ "google/play-services/games.html",
+ "https://developers.google.com/+/mobile/android/share/interactive-post",
+ "https://developers.google.com/+/mobile/android/share/deep-link"
+ ]
+ },
+ "distribute/engage/community": {
+ "title": "",
+ "resources": [
+ "distribute/users/build-community.html",
+ "distribute/engage/video.html"
+ ]
+ },
+ "distribute/engage/deeplinks": {
+ "title": "",
+ "resources": [
+ "distribute/engage/easy-signin.html",
+ "https://developers.google.com/app-indexing/",
+ "https://developers.google.com/+/mobile/android/share/interactive-post"
+ ]
+ },
+ "distribute/engage/appupdates": {
+ "title": "",
+ "resources": [
+ "distribute/essentials/optimizing-your-app.html",
+ "distribute/tools/launch-checklist.html",
+ "distribute/googleplay/developer-console.html",
+ "design/patterns/notifications.html"
+ ]
+ },
+ "distribute/engage/video/more": {
+ "title": "",
+ "resources": [
+ "http://www.youtube.com/yt/dev/",
+ "distribute/essentials/best-practices/games.html",
+ "http://www.youtube.com/watch?v=RRelFvc6Czo"
+ ]
+ },
+ "distribute/engage/community": {
+ "title": "",
+ "resources": [
+ "distribute/users/build-community.html",
+ "distribute/engage/video.html"
+ ]
+ },
+ "distribute/engage/kiwi": {
+ "title": "",
+ "resources": [
+ "http://www.youtube.com/watch?v=WWArLD6nqrk"
+ ]
+ },
+ "distribute/toolsreference/gpfefaq": {
+ "title": "",
+ "resources": [
+ "http://www.google.com/edu/tablets/",
+ "distribute/googleplay/edu/start.html",
+ "http://play.google.com/about/developer-distribution-agreement-addendum.html",
+ "distribute/essentials/quality/core.html",
+ "distribute/essentials/quality/tablets.html"
+ ]
+ },
+ "distribute/toolsreference/localizationchecklist/identifylocales": {
+ "title": "",
+ "resources": [
+ "https://support.google.com/googleplay/android-developer/answer/138294"
+ ]
+ },
+ "distribute/tools/loc/designforloc": {
+ "title": "",
+ "resources": [
+ "http://android-developers.blogspot.com/2013/03/native-rtl-support-in-android-42.html",
+ "guide/topics/resources/string-resource.html#Plurals",
+ "guide/topics/resources/string-resource.html",
+ "reference/java/util/Locale.html"
+ ]
+ },
+ "distribute/toolsreference/localizationchecklist/managestrings": {
+ "title": "",
+ "resources": [
+ "guide/topics/resources/string-resource.html",
+ "design/style/writing.html",
+ "http://en.wikipedia.org/wiki/XLIFF"
+ ]
+ },
+ "distribute/toolsreference/localizationchecklist/translatestrings": {
+ "title": "",
+ "resources": [
+ "distribute/stories/localization.html",
+ ]
+ },
+ "distribute/toolsreference/localizationchecklist/preplaunch": {
+ "title": "",
+ "resources": [
+ "distribute/tools/promote/badges.html",
+ "distribute/tools/promote/device-art.html"
+ ]
+ },
+ "distribute/toolsreference/localizationchecklist/supportlaunch": {
+ "title": "",
+ "resources": [
+ "distribute/tools/launch-checklist.html",
+ ]
+ },
+ "distribute/toolsreference/launchchecklist/understanding": {
+ "title": "",
+ "resources": [
+ "tools/publishing/publishing_overview.html",
+ "tools/publishing/preparing.html"
+ ]
+ },
+ "distribute/toolsreference/launchchecklist/policies": {
+ "title": "",
+ "resources": [
+ "https://support.google.com/googleplay/android-developer/answer/4430948",
+ "https://support.google.com/googleplay/android-developer/topic/2364761",
+ "https://support.google.com/googleplay/android-developer"
+ ]
+ },
+ "distribute/toolsreference/launchchecklist/quality": {
+ "title": "",
+ "resources": [
+ "distribute/essentials/quality/core.html",
+ "distribute/essentials/quality/tablets.html",
+ "distribute/essentials/gpfe-guidelines.html"
+ ]
+ },
+ "distribute/toolsreference/launchchecklist/rating": {
+ "title": "",
+ "resources": [
+ "https://support.google.com/googleplay/android-developer/answer/188189",
+ ]
+ },
+ "distribute/toolsreference/launchchecklist/country": {
+ "title": "",
+ "resources": [
+ "https://support.google.com/googleplay/android-developer/answer/138294"
+ ]
+ },
+ "distribute/toolsreference/launchchecklist/size": {
+ "title": "",
+ "resources": [
+ "google/play/expansion-files.html",
+ "tools/help/proguard.html"
+ ]
+ },
+ "distribute/toolsreference/launchchecklist/platform": {
+ "title": "",
+ "resources": [
+ "guide/practices/screens_support.html",
+ "about/dashboards/index.html",
+ "guide/topics/manifest/uses-sdk-element.html"
+ ]
+ },
+ "distribute/toolsreference/launchchecklist/price": {
+ "title": "",
+ "resources": [
+ "https://support.google.com/googleplay/android-developer/table/3541286",
+ ]
+ },
+ "distribute/toolsreference/launchchecklist/purchasemethod": {
+ "title": "",
+ "resources": [
+ "google/play/billing/index.html",
+ "google/play/billing/billing_subscriptions.html"
+ ]
+ },
+ "distribute/toolsreference/launchchecklist/setprice": {
+ "title": "",
+ "resources": [
+ "https://support.google.com/googleplay/android-developer/answer/1169947",
+ "https://support.google.com/googleplay/android-developer/answer/138412",
+ "https://support.google.com/googleplay/android-developer/answer/112622",
+ "https://support.google.com/googleplay/android-developer/answer/138000"
+ ]
+ },
+ "distribute/toolsreference/launchchecklist/localization": {
+ "title": "",
+ "resources": [
+ "distribute/tools/localization-checklist.html",
+ "guide/topics/resources/localization.html",
+ ]
+ },
+ "distribute/toolsreference/launchchecklist/graphics": {
+ "title": "",
+ "resources": [
+ "https://support.google.com/googleplay/android-developer/answer/1078870",
+ "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html"
+ ]
+ },
+ "distribute/toolsreference/launchchecklist/productdetails": {
+ "title": "",
+ "resources": [
+ "https://support.google.com/googleplay/android-developer/answer/113475",
+ "https://support.google.com/googleplay/android-developer/answer/1078870"
+ ]
+ },
+ "distribute/toolsreference/launchchecklist/badges": {
+ "title": "",
+ "resources": [
+ "distribute/tools/promote/badges.html",
+ "distribute/tools/promote/linking.html"
+ ]
+ },
+ "distribute/toolsreference/launchchecklist/finalchecks": {
+ "title": "",
+ "resources": [
+ "http://play.google.com/about/developer-content-policy.html",
+ "https://support.google.com/googleplay/android-developer/answer/113476",
+ "support.html"
+ ]
+ },
+ "distribute/toolsreference/launchchecklist/afterlaunch": {
+ "title": "",
+ "resources": [
+ "https://support.google.com/googleplay/android-developer/answer/113477",
+ "https://support.google.com/googleplay/android-developer/answer/1153479",
+ "https://support.google.com/payments/answer/2741495",
+ "distribute/essentials/optimizing-your-app.html"
+ ]
+ },
+ "distribute/monetize/premium": {
+ "title": "",
+ "resources": [
+ "google/play/billing/index.html",
+ "https://support.google.com/googleplay/android-developer/answer/4407611"
+ ]
+ },
+ "distribute/monetize/freemium": {
+ "title": "",
+ "resources": [
+ "google/play/billing/index.html",
+ "https://support.google.com/googleplay/android-developer/answer/4407611"
+ ]
+ },
+ "distribute/monetize/subscriptions": {
+ "title": "",
+ "resources": [
+ "google/play/billing/billing_subscriptions.html",
+ "https://support.google.com/googleplay/android-developer/answer/4407611"
+ ]
+ },
+ "distribute/monetize/ecommerce": {
+ "title": "",
+ "resources": [
+ "https://developers.google.com/wallet/instant-buy/",
+ "https://support.google.com/googleplay/android-developer/answer/4407611"
+ ]
+ },
+ "distribute/monetize/advertising": {
+ "title": "",
+ "resources": [
+ "http://www.google.com/ads/admob/#subid=us-en-et-dac",
+ "http://www.google.com/doubleclick/publishers/small-business/index.html",
+ "http://support.google.com/googleplay/android-developer/topic/2985714",
+ "training/monetization/ads-and-ux.html"
+ ]
+ },
+ "distribute/monetize/paymentmethods": {
+ "title": "",
+ "resources": [
+ "https://play.google.com/about/giftcards/",
+ "https://support.google.com/googleplay/answer/2651410"
+ ]
+ },
+}
diff --git a/docs/html/jd_extras.js b/docs/html/jd_extras.js
new file mode 100644
index 0000000..f26b747b
--- /dev/null
+++ b/docs/html/jd_extras.js
@@ -0,0 +1,1104 @@
+/* Metadata represendations of resources that are outside of the autogenerated
+ local resource lists, or that override local resource representations.
+
+ Resources listed here are referenced from sitemap sections and collections,
+ matched by url string if there is no resource existing in ALL_RESOURCES.
+
+ Currently, these articles can override only the generated resources
+ in DISTRIBUTE_RESOURCES. A representation defined here will not be applied
+ when a collection or section specifies a url that's not in DISTRIBUTE_RESOURCEs.
+ Also
+ So if a section url refers to a static doc that's
+ not in a distribute section, you need to create an item for
+ it in this file. Fix is to compare across
+ ALL_RESOURCES_BY_URL. */
+
+DISTRIBUTE_RESOURCES = DISTRIBUTE_RESOURCES.concat([
+ {
+ "title":"Developer Registration",
+ "titleFriendly":"",
+ "summary":"Additional information about the registration process.",
+ "url":"https://support.google.com/googleplay/android-developer/answer/113468",
+ "group":"",
+ "keywords": [],
+ "tags": [],
+ "image":"images/play_dev.jpg",
+ "type":"google"
+ },
+ {
+ "title": "Google Play Distribution and Seller Countries",
+ "titleFriendly":"",
+ "summary": "List of countries and territories where you can distribute your apps in Google Play.",
+ "url":"https://support.google.com/googleplay/android-developer/answer/138294",
+ "group":"",
+ "keywords": [],
+ "tags": [],
+ "image":"images/play_dev.jpg",
+ "type":"google"
+ },
+ {
+ "title":"Google Play Content Policies",
+ "titleFriendly":"",
+ "summary":"Details on policies relating to your developer account and app distribution is governed.",
+ "url":"https://support.google.com/googleplay/android-developer/topic/3453577",
+ "group":"",
+ "keywords": [],
+ "tags": ["#developersupport"],
+ "image":"images/play_dev.jpg",
+ "type":"google"
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": ["#developersupport #termsandpolicies"],
+ "url": "https://support.google.com/googleplay/android-developer/answer/4407611",
+ "timestamp": 1194884220000,
+ "image": 'images/play_dev.jpg',
+ "title": "Google Play Terms and Policies",
+ "summary": "Developer terms and policies that apply when you distribute apps in Google Play.",
+ "keywords": [],
+ "type": "distribute",
+ "titleFriendly": ""
+ },
+ {
+ "title":"Google Play Policy Center",
+ "titleFriendly":"",
+ "summary":"A central resource for you to learn about Google Play policies and guidelines.",
+ "url":"https://support.google.com/googleplay/android-developer/answer/4430948",
+ "group":"",
+ "keywords": [],
+ "tags": [],
+ "image":"http://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389397_en_v0",
+ "type":"google"
+ },
+ {
+ "title":"Developer Help Center",
+ "titleFriendly":"",
+ "summary":"Complete details on getting started, publishing, troubleshooting, and more.",
+ "url":"https://support.google.com/googleplay/android-developer",
+ "group":"",
+ "keywords": [],
+ "tags": [],
+ "image":"images/play_dev.jpg",
+ "type":"google"
+ },
+ {
+ "title":"Google for Education",
+ "titleFriendly":"",
+ "summary":"Find out more about how Google can support your work with apps and tablets.",
+ "url":"http://www.google.com/edu/tablets/",
+ "group":"",
+ "keywords": [],
+ "tags": [],
+ "image":"distribute/images/gp-edu-apps-image.jpg",
+ "type":"google"
+ },
+ {
+ "title":"Keeping Your App Responsive",
+ "titleFriendly":"",
+ "summary":"This document describes how the Android system determines whether an application is not responding and provides guidelines for ensuring that your application stays responsive.",
+ "url":"training/articles/perf-anr.html",
+ "group":"",
+ "keywords": [],
+ "tags": [],
+ "image":"",
+ "type":"google"
+ },
+ {
+ "title":"Google Play Game Services",
+ "titleFriendly":"",
+ "summary":"Tools to offer a better game experience.",
+ "url":"google/play-services/games.html",
+ "group":"",
+ "keywords": [],
+ "tags": [],
+ "image":"",
+ "type":"google"
+ },
+
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [
+ "versions", "blog", "googleplay"
+ ],
+ "url": "http://android-developers.blogspot.com/",
+ "timestamp": 1004884220000,
+ "image": "images/blog.jpg",
+ "title": "Android Developers Blog",
+ "summary": "Follow the latest news on Android design, development, and distribution.",
+ "keywords": [],
+ "type": "blog",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Making Android Apps that Play Nice",
+ "summary": "Audio lifecycle and expected audio behaviors for Android apps.",
+ "keywords": [],
+ "type": "blog",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Multithreading for Performance",
+ "summary": "Ways to improve performance through multi-threading.",
+ "keywords": [],
+ "type": "blog",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://play.google.com/about/developer-content-policy.html",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "Developer Program Policies",
+ "summary": "Guidelines acceptable content in Google Play. Please read and understand the policies before publishing.",
+ "keywords": [],
+ "type": "google",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://support.google.com/googleplay/android-developer/answer/188189",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "Rating your application content for Google Play",
+ "summary": "How to choose the appropriate content ratings level for your apps.",
+ "keywords": [],
+ "type": "support",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "Google Play Featured Image Guidelines",
+ "summary": "How to create attractive, effective Featured Images for your apps.",
+ "keywords": [],
+ "type": "support",
+ "titleFriendly": ""
+ },
+{
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://support.google.com/googleplay/android-developer/answer/113477",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "Supporting your users",
+ "summary": "Options for supporting users.",
+ "keywords": [],
+ "type": "support",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "guide/practices/screens_support.html#ConfigurationExamples",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Configuration examples",
+ "summary": "How to declare layouts and other resources for specific screen sizes.",
+ "keywords": [],
+ "type": "design",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "training/design-navigation/multiple-sizes.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Planning for Multiple Touchscreen Sizes",
+ "summary": "",
+ "keywords": [],
+ "type": "design",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "training/multiscreen/index.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Designing for Multiple Screens",
+ "summary": "Designing an intuitive, effective navigation for tablets and other devices.",
+ "keywords": [],
+ "type": "design",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "guide/topics/resources/providing-resources.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Providing Resources",
+ "summary": "Layouts and drawable resources for specific ranges of device screens.",
+ "keywords": [],
+ "type": "design",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "training/basics/supporting-devices/screens.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Supporting Different Screens",
+ "summary": "Optimizing the user experience for different screen sizes and densities.",
+ "keywords": [],
+ "type": "design",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "guide/topics/appwidgets/index.html#MetaData",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Adding the AppWidgetProviderInfo Metadata",
+ "summary": "How to set the height and width dimensions of a widget.",
+ "keywords": [],
+ "type": "design",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "guide/topics/manifest/uses-sdk-element.html#ApiLevels",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Android API Levels",
+ "summary": "Introduction to API levels and how they relate to compatibility.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "guide/practices/screens_support.html#DeclaringScreenSizeSupport",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Declaring screen size support",
+ "summary": "How to declare support for screen sizes in your app\'s manifest.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "guide/topics/manifest/uses-feature-element.html#testing",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Checking for hardware feature requirements",
+ "summary": "Determining an app’s hardware and software requirements.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://play.google.com/apps/publish/",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Google Play Developer Console",
+ "summary": "The tools console for publishing your app.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://youtu.be/SkHHPf3EdzE",
+ "timestamp": 1194884220000,
+ "image": "http://i1.ytimg.com/vi/SkHHPf3EdzE/maxresdefault.jpg",
+ "title": "Level Up Your Android Game",
+ "summary": "Learn how to take your game to the next level on Google Play.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://developers.google.com/+/mobile/android/share/interactive-post",
+ "timestamp": 1194884220000,
+ "image": 'images/google/gps-googleplus.png',
+ "title": "Sharing interactive posts to Google+ from your Android app",
+ "summary": "Interactive posts provide an easy and prominent way to allow users to share your site or app with their friends and invite them to take a specific action.",
+ "keywords": ["Interactive", "Google+"],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://play.google.com/about/developer-distribution-agreement.html",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "Developer Distribution Agreement",
+ "summary": "Terms for distributing and selling apps and in-app products in Google Play.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://support.google.com/googleplay/android-developer/answer/113417",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Inappropriate content in comments and applications",
+ "summary": "More details on what content is appropriate.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://support.google.com/legal/troubleshooter/1114905",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Removing content from Google",
+ "summary": "Find how how to request the removal of content that infringes on your trademark.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://play.google.com/about/developer-distribution-agreement-addendum.html",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "Google Play for Education Addendum",
+ "summary": "Review the education-specific requirements.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://android-developers.blogspot.com/2013/03/native-rtl-support-in-android-42.html",
+ "timestamp": null,
+ "image": null,
+ "title": "Native RTL Support in Android 4.2",
+ "summary": "Blog post that explains how to support RTL in your UI.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "guide/topics/resources/string-resource.html#Plurals",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Quantity Strings (Plurals)",
+ "summary": "How to work with string plurals according to rules of grammar in a given locale.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "reference/java/util/Locale.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Locale",
+ "summary": "Determine what CLDR data or version of the Unicode spec a particular Android platform version uses.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "guide/topics/resources/string-resource.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "String Resources",
+ "summary": "Explains how to use string resources in your UI.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "distribute/tools/localization-checklist.html#strings",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Manage strings for localization",
+ "summary": "Guidance on having your strings translation ready.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "tools/publishing/publishing_overview.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "General Publishing Overview",
+ "summary": "Start here for an overview of publishing options for Android apps.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "tools/publishing/preparing.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Preparing for Release",
+ "summary": "Developer documentation on how to build the signed, release-ready APK. This process is the same for all Android apps.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "distribute/googleplay/policies/index.html",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "Google Play Policies and Guidelines",
+ "summary": "An overview of Google Play policies for spam, intellectual property, and ads, with examples of common problems.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://support.google.com/googleplay/android-developer/topic/2364761",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "Policy and Best Practices",
+ "summary": "Help Center document describing various content policies and processes.",
+ "keywords": [],
+ "type": "distribute",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "google/play/expansion-files.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "APK Expansion Files",
+ "summary": "Developer documentation describing APK Expansion Files and how to support them in your app.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "tools/help/proguard.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "ProGuard",
+ "summary": "Developer documentation describing how to use ProGuard to shrink, optimize, and obfuscate your code prior to release.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "title":"Dashboards",
+ "titleFriendly":"",
+ "summary":"This page provides information about the relative number of devices that share a certain characteristic, such as Android version or screen size. This information may help you prioritize efforts for supporting different devices by revealing which devices…",
+ "url":"about/dashboards/index.html",
+ "group":"",
+ "keywords": ["android","dashboard","platforms","versions"],
+ "tags": ["#ecosystem","#versions","#whatsnew"],
+ "image":"http://chart.googleapis.com/chart?chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chf=bg%2Cs%2C00000000&chd=t%3A0.1%2C93.5%2C6.4&chco=c4df9b%2C6fad0c&chs=400x250&cht=p",
+ "lang":"en",
+ "type":"about"
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://developers.google.com/wallet/instant-buy/",
+ "timestamp": 1194884220000,
+ "image": "distribute/images/payment-method.jpg",
+ "title": "Google Wallet Instant Buy APIs",
+ "summary": "Developer documentation describing Instant Buy and how to support it in your apps.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://support.google.com/googleplay/android-developer/answer/1169947",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "Selling Apps in Multiple Currencies",
+ "summary": "Help Center document describing how pricing works in Google Play.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://support.google.com/googleplay/android-developer/answer/138412",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "Prices and supported currencies",
+ "summary": "Help Center document listing supported currencies for pricing your apps.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://support.google.com/googleplay/android-developer/answer/112622",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "Transaction Fees",
+ "summary": "Help Center document describing transaction fees for priced apps and in-app products.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://support.google.com/googleplay/android-developer/answer/138000",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "Specifying tax rates",
+ "summary": "Help Center document describing how to set tax rates for different countries.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "guide/topics/resources/localization.html",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "Localizing with Resources",
+ "summary": "Developer guide to localizing resources in your app.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://support.google.com/googleplay/android-developer/answer/113475",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "Category types",
+ "summary": "Help Center document listing available categories for apps.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://support.google.com/googleplay/android-developer/answer/113476",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "Updates",
+ "summary": "Requirements for app updates in Google Play.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://support.google.com/googleplay/android-developer/answer/1153479",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "In-app Billing",
+ "summary": "Help Center document describing how to correctly set up In-app Billing.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [
+ "#gpfe",
+ "#googleplay"
+ ],
+ "url": "http://youtu.be/vzvpcEffvaE",
+ "timestamp": 1383243492000,
+ "image": "http://i1.ytimg.com/vi/vzvpcEffvaE/maxresdefault.jpg",
+ "title": "Introducing Google Play for Education",
+ "summary": "Google Play for Education is a destination where schools can find great, teacher-approved, educational apps and videos on Play Store. Teachers can filter content by subject matter, grade and other criteria. Bulk purchase and instant distribution let educators bring your apps directly to classrooms and schools.",
+ "keywords": [],
+ "type": "youtube",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [
+ "#engagement",
+ ],
+ "url": "http://www.youtube.com/yt/dev/",
+ "timestamp": 1383243492000,
+ "image": "http://www.youtube.com/yt/dev/media/images/yt-dev-home-hero.jpg",
+ "title": "YouTube for Developers",
+ "summary": "The YouTube APIs and Tools enable you to integrate YouTube's video content and functionality into your website, app, or device.",
+ "keywords": [],
+ "type": "youtube",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [
+ "#engagement",
+ ],
+ "url": "https://developers.google.com/app-indexing/",
+ "timestamp": 1383243492000,
+ "image": "https://developers.google.com/app-indexing/images/allthecooks_srp.png",
+ "title": "Sign Up for App Indexing",
+ "summary": "Google is working with app developers and webmasters to index the content of apps and relate them to websites. When relevant, Google Search results on Android will include deep links to apps.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [
+ "#gcm",
+ ],
+ "url": "http://www.youtube.com/watch?v=y76rjidm8cU",
+ "timestamp": 1383243492000,
+ "image": "http://1.bp.blogspot.com/-IF-1-1kA0sg/UYwTidxdi3I/AAAAAAAAAEU/ellLeQ-E1vs/s800/google-io-lockup-2.png",
+ "title": "Google Cloud Messaging at I/O 2013",
+ "summary": "Google Cloud Messaging allows your services to efficiently send data to applications on Android devices. See what's new, and learn how to use GCM to make your apps more efficient.",
+ "keywords": ["gcm"],
+ "type": "youtube",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [
+ "#googleplus",
+ ],
+ "url": "https://developers.google.com/+/mobile/android/people",
+ "timestamp": 1383243492000,
+ "image": "images/google/gps-googleplus.png",
+ "title": "Sign Up for App Indexing",
+ "summary": "After you let users sign in with Google, you can access their age range, language, public profile information, and people that they have circled.",
+ "keywords": ["googleplus"],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [
+ "#gcm",
+ ],
+ "url": "http://developer.chrome.com/apps/cloudMessagingV2",
+ "timestamp": 1383243492000,
+ "image": "images/kk-chromium-icon.png",
+ "title": "Google Cloud Messaging for Chrome",
+ "summary": "Google Cloud Messaging for Chrome (GCM) is a service for signed-in Chrome users that helps developers send message data from servers to their Chrome apps and extensions.",
+ "keywords": ["gcm"],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [
+ "#sdkupdates"
+ ],
+ "url": "http://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Make Beautiful Android App Icons",
+ "summary": "Follow these in-depth launcher icon tips on the Android Developers blog.",
+ "keywords": [],
+ "type": "blog",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [
+ "#sdkupdates"
+ ],
+ "url": "http://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Localize Your Promotional Graphics",
+ "summary": "Learn how to capitalise on international audiences.",
+ "keywords": [],
+ "type": "blog",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [
+ "#sdkupdates"
+ ],
+ "url": "http://android-developers.blogspot.com/2013/10/making-your-app-content-more-accessible.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Make your App Content more Accessible with App Linking",
+ "summary": "About using search and deep linking to get more users.",
+ "keywords": [],
+ "type": "blog",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://developers.google.com/+/mobile/android/share/interactive-post",
+ "timestamp": 1194884220000,
+ "image": 'images/google/gps-googleplus.png',
+ "title": "Sharing interactive posts to Google+ from your Android app",
+ "summary": "Interactive posts provide an easy and prominent way to allow users to share your site or app with their friends and invite them to take a specific action.",
+ "keywords": ["Interactive", "Google+"],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://support.google.com/googleplay/android-developer/answer/2528691",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "How to add multiple user accounts to your Developer Console for testing and more.",
+ "summary": "",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://developers.google.com/+/mobile/android/share/deep-link",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Adding deep linking to Google+ posts shared from your Android app",
+ "summary": "",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "google/play/licensing/index.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Application Licensing",
+ "summary": "Information on the features of Google Play to protect your apps’ licences.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "design/style/writing.html",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "Writing Style",
+ "summary": "Android Design guidelines for voice and style in your UI.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://en.wikipedia.org/wiki/XLIFF",
+ "timestamp": 1194884220000,
+ "image": null,
+ "title": "XML Localisation Interchange File Format (XLIFF)",
+ "summary": "Background information on XLIFF.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://support.google.com/googleplay/android-developer/answer/1078870",
+ "timestamp": 1194884220000,
+ "image": "images/play_dev.jpg",
+ "title": "Graphic Assets for your Application",
+ "summary": "Details about the graphics you can add to your product listing.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "https://support.google.com/payments/answer/2741495",
+ "timestamp": null,
+ "image": null,
+ "title": "Issuing Refunds",
+ "summary": "Help Center document describing how to issue refunds.",
+ "keywords": [],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://android-developers.blogspot.com/2013/11/bring-your-apps-into-classroom-with.html",
+ "timestamp": null,
+ "image": "distribute/images/gp-edu-apps-image.jpg",
+ "title": "Google play for education",
+ "summary": " ",
+ "keywords": [],
+ "type": "distribute",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": ["localization", "pricing", "developer support"],
+ "url": "https://support.google.com/googleplay/android-developer/table/3541286",
+ "timestamp": null,
+ "image": "images/play_dev.jpg",
+ "title": "Supported locations for distributing your apps in Google Play",
+ "summary": "Countries and regions where you can distribute your app in Google Play.",
+ "keywords": [],
+ "type": "distribute",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": ["games", "localization", "quality"],
+ "url": "http://www.youtube.com/watch?v=SkHHPf3EdzE",
+ "timestamp": null,
+ "image": "https://developers.google.com/apps/images/io_2013/google-io-logo.png",
+ "title": "Level Up Your Android Game",
+ "summary": "Learn how to take your game to the next level in this Google I/O session.",
+ "keywords": [],
+ "type": "distribute",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": ["support"],
+ "url": "https://support.google.com/groups/answer/46601",
+ "timestamp": null,
+ "image": null,
+ "title": "Google Groups",
+ "summary": "Create a group for your community.",
+ "keywords": [],
+ "type": "distribute",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": ["support"],
+ "url": "https://support.google.com/plus/topic/2888488",
+ "timestamp": null,
+ "image": null,
+ "title": "Google+ Communities",
+ "summary": "Host a Google+ community for testers or users.",
+ "keywords": [],
+ "type": "distribute",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": ["monetize", "ads"],
+ "url": "http://www.google.com/ads/admob/#subid=us-en-et-dac",
+ "timestamp": null,
+ "image": "distribute/images/advertising.png",
+ "title": "AdMob for Android",
+ "summary": "Make money by connecting with over a million Google advertisers all over the world, so your revenue scales with your app.",
+ "keywords": ["ads"],
+ "type": "distribute",
+ "titleFriendly": ""
+ },
+
+ {
+ "lang": "en",
+ "group": "",
+ "tags": ["monetize", "ads"],
+ "url": "http://www.google.com/doubleclick/publishers/small-business/index.html",
+ "timestamp": null,
+ "image": "http://www.google.com/doubleclick/publishers/small-business/images/define_ad.png",
+ "title": "DoubleClick for Publishers",
+ "summary": "A free ad management solution that helps growing publishers sell, schedule, deliver, and measure all of their digital ad inventory.",
+ "keywords": ["ads"],
+ "type": "distribute",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": ["monetize", "ads"],
+ "url": "http://support.google.com/googleplay/android-developer/topic/2985714",
+ "timestamp": null,
+ "image": "http://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389397_en_v0",
+ "title": "Policy Center: Ads",
+ "summary": "Introduction to ads and system interference policies in Google Play",
+ "keywords": ["ads"],
+ "type": "distribute",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": ["monetize", "giftcards"],
+ "url": "https://play.google.com/about/giftcards/",
+ "timestamp": null,
+ "image": "images/gp-balance.png",
+ "title": "Google Play Gift Cards",
+ "summary": "Buy Google Play gift cards online or at a variety of retail stores.",
+ "keywords": ["gift card"],
+ "type": "distribute",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": ["monetize", "paymentmethods"],
+ "url": "https://support.google.com/googleplay/answer/2651410",
+ "timestamp": null,
+ "image": "images/play_dev.jpg",
+ "title": "Google Play Accepted Payment Methods",
+ "summary": "Support details on the payment methods supported in Google Play.",
+ "keywords": ["gift card"],
+ "type": "distribute",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": ["plus", "social"],
+ "url": "https://plus.google.com/+AndroidDevelopers/",
+ "timestamp": null,
+ "image": "images/plus.jpg",
+ "title": "+Android Developers",
+ "summary": "Sharing news, ideas, and techniques for success.",
+ "keywords": ["+AndroidDevelopers"],
+ "type": "Google+",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": ["plus", "social"],
+ "url": "http://plus.google.com/+GooglePlay",
+ "timestamp": null,
+ "image": "https://lh4.googleusercontent.com/-IKezweZlcXI/AAAAAAAAAAI/AAAAAAABOvg/uK8Z0jekVE4/s120-c/photo.jpg",
+ "title": "+Google Play",
+ "summary": "News and discussion about Google Play, apps, and other content in Google+.",
+ "keywords": ["+GooglePlay"],
+ "type": "Google+",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": ["support", "android"],
+ "url": "support.html",
+ "timestamp": null,
+ "image": null,
+ "title": "Developer Support",
+ "summary": "Links to community and support resources for Android developers.",
+ "keywords": ["support"],
+ "type": "Google+",
+ "titleFriendly": ""
+ },
+]);
\ No newline at end of file
diff --git a/docs/html/jd_tag_helpers.js b/docs/html/jd_tag_helpers.js
new file mode 100644
index 0000000..ca01386
--- /dev/null
+++ b/docs/html/jd_tag_helpers.js
@@ -0,0 +1,110 @@
+function mergeArrays() {
+ var arr = arguments[0] || [];
+ for (var i = 1; i < arguments.length; i++) {
+ arr = arr.concat(arguments[i]);
+ }
+ return arr;
+}
+
+var ALL_RESOURCES = mergeArrays(
+ DESIGN_RESOURCES,
+ DISTRIBUTE_RESOURCES,
+ GOOGLE_RESOURCES,
+ GUIDE_RESOURCES,
+ SAMPLES_RESOURCES,
+ TOOLS_RESOURCES,
+ TRAINING_RESOURCES,
+ YOUTUBE_RESOURCES,
+ BLOGGER_RESOURCES
+);
+
+for (var i = 0; i < ALL_RESOURCES.length; i++) {
+ ALL_RESOURCES[i].index = i;
+}
+
+function mergeMaps() {
+ var allRes = {};
+ var offset = 0;
+
+ for (var i = 0; i < arguments.length; i++) {
+ var r = arguments[i];
+ for (var tag in r.map) {
+ allRes[tag] = allRes[tag] || [];
+ allRes[tag] = allRes[tag].concat(r.map[tag].map(function(i){ return ALL_RESOURCES[i + offset]; }));
+ }
+ offset += r.arr.length;
+ }
+
+ return allRes;
+}
+
+function setFromArray(arr) {
+ arr = arr || [];
+ var set = {};
+ for (var i = 0; i < arr.length; i++) {
+ set[arr[i]] = true;
+ }
+ return set;
+}
+
+function buildResourceLookupMap(resourceDict) {
+ var map = {};
+ for (var key in resourceDict) {
+ var dictForKey = {};
+ var srcArr = resourceDict[key];
+ for (var i = 0; i < srcArr.length; i++) {
+ dictForKey[srcArr[i].index] = true;
+ }
+ map[key] = dictForKey;
+ }
+ return map;
+}
+
+// Type lookups
+
+var ALL_RESOURCES_BY_TYPE = {
+ 'design': DESIGN_RESOURCES,
+ 'distribute': DISTRIBUTE_RESOURCES,
+ 'google': GOOGLE_RESOURCES,
+ 'guide': GUIDE_RESOURCES,
+ 'samples': SAMPLES_RESOURCES,
+ 'tools': TOOLS_RESOURCES,
+ 'training': TRAINING_RESOURCES,
+ 'youtube': YOUTUBE_RESOURCES,
+ 'blog': BLOGGER_RESOURCES
+};
+var IS_RESOURCE_OF_TYPE = buildResourceLookupMap(ALL_RESOURCES_BY_TYPE);
+
+// Tag lookups
+
+var ALL_RESOURCES_BY_TAG = mergeMaps(
+ {map:DESIGN_BY_TAG,arr:DESIGN_RESOURCES},
+ {map:DISTRIBUTE_BY_TAG,arr:DISTRIBUTE_RESOURCES},
+ {map:GOOGLE_BY_TAG,arr:GOOGLE_RESOURCES},
+ {map:GUIDE_BY_TAG,arr:GUIDE_RESOURCES},
+ {map:SAMPLES_BY_TAG,arr:SAMPLES_RESOURCES},
+ {map:TOOLS_BY_TAG,arr:TOOLS_RESOURCES},
+ {map:TRAINING_BY_TAG,arr:TRAINING_RESOURCES},
+ {map:YOUTUBE_BY_TAG,arr:YOUTUBE_RESOURCES},
+ {map:BLOGGER_BY_TAG,arr:BLOGGER_RESOURCES}
+);
+var IS_RESOURCE_TAGGED = buildResourceLookupMap(ALL_RESOURCES_BY_TAG);
+
+// URL and language lookups
+
+var ALL_RESOURCES_BY_URL = {};
+var ALL_RESOURCES_BY_LANG = {};
+
+for (var i = 0; i < ALL_RESOURCES.length; i++) {
+ var res = ALL_RESOURCES[i];
+ var lang = res.lang;
+ if (lang) {
+ ALL_RESOURCES_BY_LANG[lang] = ALL_RESOURCES_BY_LANG[lang] || [];
+ ALL_RESOURCES_BY_LANG[lang].push(res);
+ }
+ var url = res.url;
+ if (url) {
+ ALL_RESOURCES_BY_URL[url] = res;
+ }
+}
+var IS_RESOURCE_IN_LANG = buildResourceLookupMap(ALL_RESOURCES_BY_LANG);
\ No newline at end of file
diff --git a/docs/html/legal.jd b/docs/html/legal.jd
index aaa3c39..c6143da 100644
--- a/docs/html/legal.jd
+++ b/docs/html/legal.jd
@@ -1,4 +1,5 @@
page.title=Legal Notice
+page.type=about
fullpage=1
@jd:body
@@ -39,7 +40,7 @@
use of it must be attributed as such.</p>
<p>For more information about Android brands, see the <a
-href="{@docRoot}distribute/googleplay/promote/brand.html">Brand Guidelines</a>.</p>
+href="{@docRoot}distribute/tools/promote/brand.html">Brand Guidelines</a>.</p>
<p>All other trademarks are the property of their respective owners.</p>
diff --git a/docs/html/license.jd b/docs/html/license.jd
index b98c912..0f671e2 100644
--- a/docs/html/license.jd
+++ b/docs/html/license.jd
@@ -1,4 +1,5 @@
page.title=Content License
+page.type=about
fullpage=1
excludeFromSuggestions=true
@jd:body
@@ -68,7 +69,7 @@
style="margin:0;padding:0 2px;vertical-align:baseline" /> stylized typeface logo) are not included
in the license.
Please see <a
-href="{@docRoot}distribute/googleplay/promote/brand.html">Brand Guidelines</a> for
+href="{@docRoot}distribute/tools/promote/brand.html">Brand Guidelines</a> for
information about this usage. </li>
<li>In some cases, a page may include content, such as an image, that is not
diff --git a/docs/html/reference/android/preview/support/package-summary.html b/docs/html/reference/android/preview/support/package-summary.html
index d367f87..2f50871 100644
--- a/docs/html/reference/android/preview/support/package-summary.html
+++ b/docs/html/reference/android/preview/support/package-summary.html
@@ -82,13 +82,6 @@
-
-
-
-
-
-
-
<html>
<head>
@@ -101,13 +94,15 @@
<!-- STYLESHEETS -->
<link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+ title="roboto">
<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
<!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
<script type="text/javascript">
var toRoot = "/";
@@ -131,7 +126,7 @@
<body class="gc-documentation
- develop">
+ preview">
<div id="doc-api-level" class="" style="display:none"></div>
<a name="top"></a>
@@ -139,31 +134,30 @@
<a name="top"></a>
- <!-- Header -->
- <div id="header">
- <div class="wrap" id="header-wrap">
- <div class="col-3 logo-wear">
- <a href="/wear/index.html">
- <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
- </a>
- </div>
+<!-- Header -->
+<div id="header-wrapper">
+ <div id="header">
+ <div class="wrap" id="header-wrap">
+ <div class="col_3 logo wear-logo">
+ <a href="/wear/index.html">
+ <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+ </a>
+ </div>
+ <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-
- <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
- color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-
-
- <!-- New Search -->
- <div class="menu-container">
- <div class="moremenu">
- <div id="more-btn"></div>
- </div>
+
+
+<div class="menu-container">
+ <div class="moremenu">
+ <div id="more-btn"></div>
+ </div>
<div class="morehover" id="moremenu">
<div class="top"></div>
<div class="mid">
<div class="header">Links</div>
<ul>
- <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+ <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
<li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
<li><a href="/about/index.html">About Android</a></li>
</ul>
@@ -173,16 +167,32 @@
<li class="active"><a>Android Developers</a></li>
<li><a href="http://source.android.com">Android Open Source Project</a></li>
</ul>
-
-
-
-
-
+
+
+ <div class="header">Language</div>
+ <div id="language" class="locales">
+ <select name="language" onChange="changeLangPref(this.value, true)">
+ <option value="en">English</option>
+ <option value="es">Español</option>
+ <option value="ja">日本語</option>
+ <option value="ko">한국어</option>
+ <option value="ru">Русский</option>
+ <option value="zh-cn">中文 (中国)</option>
+ <option value="zh-tw">中文 (台灣)</option>
+ </select>
+ </div>
+ <script type="text/javascript">
+ <!--
+ loadLangPref();
+ //-->
+ </script>
+
+
<br class="clearfix" />
- </div><!-- end mid -->
+ </div><!-- end 'mid' -->
<div class="bottom"></div>
- </div><!-- end morehover -->
+ </div><!-- end 'moremenu' -->
<div class="search" id="search-container">
<div class="search-inner">
@@ -190,16 +200,16 @@
<div class="left"></div>
<form onsubmit="return submit_search()">
<input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')"
-onkeyup="return search_changed(event, false, '/')" />
+ onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+ onkeydown="return search_changed(event, true, '/')"
+ onkeyup="return search_changed(event, false, '/')" />
</form>
<div class="right"></div>
- <a class="close hide">close</a>
- <div class="left"></div>
- <div class="right"></div>
- </div>
- </div><!-- end search -->
+ <a class="close hide">close</a>
+ <div class="left"></div>
+ <div class="right"></div>
+ </div><!-- end search-inner -->
+ </div><!-- end search-container -->
<div class="search_filtered_wrapper reference">
<div class="suggest-card reference no-display">
@@ -228,30 +238,37 @@
<ul class="search_filtered">
</ul>
</div>
- </div><!-- end search_filtered_wrapper -->
-
</div>
- <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
- </div><!-- end header-wrap -->
- </div>
- <!-- /Header -->
+ </div><!-- end header-wrap -->
+ </div><!-- /Header -->
<div id="searchResults" class="wrap" style="display:none;">
<h2 id="searchTitle">Results</h2>
<div id="leftSearchControl" class="search-control">Loading...</div>
</div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+ <div>
+ <a class="logo" href="#top"></a>
+ <a class="top" href="#top"></a>
+ <ul class="breadcrumb">
+
+ <li class="current">Preview Notifications Reference</li>
+ </ul>
+ </div>
+</div>
-
<div class="wrap clearfix" id="body-content">
<div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
<div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
<ul id="nav">
@@ -328,7 +345,7 @@
</ul>
-
+
</div>
</div> <!-- end side-nav -->
@@ -362,12 +379,6 @@
-
-
-
-
-
-
<h2>android.preview.support.v4.app</h2>
<div class="jd-sumtable">
@@ -418,14 +429,6 @@
-
-
-
-
-
-
-
-
diff --git a/docs/html/reference/android/preview/support/v4/app/NotificationManagerCompat.html b/docs/html/reference/android/preview/support/v4/app/NotificationManagerCompat.html
index 6375d9a..8322ab2 100644
--- a/docs/html/reference/android/preview/support/v4/app/NotificationManagerCompat.html
+++ b/docs/html/reference/android/preview/support/v4/app/NotificationManagerCompat.html
@@ -82,13 +82,6 @@
-
-
-
-
-
-
-
<html>
<head>
@@ -101,13 +94,15 @@
<!-- STYLESHEETS -->
<link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+ title="roboto">
<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
<!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
<script type="text/javascript">
var toRoot = "/";
@@ -130,7 +125,7 @@
</head>
<body class="gc-documentation
- develop" itemscope itemtype="http://schema.org/Article">
+ preview" itemscope itemtype="http://schema.org/Article">
<div id="doc-api-level" class="" style="display:none"></div>
<a name="top"></a>
@@ -138,31 +133,30 @@
<a name="top"></a>
- <!-- Header -->
- <div id="header">
- <div class="wrap" id="header-wrap">
- <div class="col-3 logo-wear">
- <a href="/wear/index.html">
- <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
- </a>
- </div>
+<!-- Header -->
+<div id="header-wrapper">
+ <div id="header">
+ <div class="wrap" id="header-wrap">
+ <div class="col_3 logo wear-logo">
+ <a href="/wear/index.html">
+ <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+ </a>
+ </div>
+ <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-
- <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
- color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-
-
- <!-- New Search -->
- <div class="menu-container">
- <div class="moremenu">
- <div id="more-btn"></div>
- </div>
+
+
+<div class="menu-container">
+ <div class="moremenu">
+ <div id="more-btn"></div>
+ </div>
<div class="morehover" id="moremenu">
<div class="top"></div>
<div class="mid">
<div class="header">Links</div>
<ul>
- <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+ <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
<li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
<li><a href="/about/index.html">About Android</a></li>
</ul>
@@ -172,16 +166,32 @@
<li class="active"><a>Android Developers</a></li>
<li><a href="http://source.android.com">Android Open Source Project</a></li>
</ul>
-
-
-
-
-
+
+
+ <div class="header">Language</div>
+ <div id="language" class="locales">
+ <select name="language" onChange="changeLangPref(this.value, true)">
+ <option value="en">English</option>
+ <option value="es">Español</option>
+ <option value="ja">日本語</option>
+ <option value="ko">한국어</option>
+ <option value="ru">Русский</option>
+ <option value="zh-cn">中文 (中国)</option>
+ <option value="zh-tw">中文 (台灣)</option>
+ </select>
+ </div>
+ <script type="text/javascript">
+ <!--
+ loadLangPref();
+ //-->
+ </script>
+
+
<br class="clearfix" />
- </div><!-- end mid -->
+ </div><!-- end 'mid' -->
<div class="bottom"></div>
- </div><!-- end morehover -->
+ </div><!-- end 'moremenu' -->
<div class="search" id="search-container">
<div class="search-inner">
@@ -189,16 +199,16 @@
<div class="left"></div>
<form onsubmit="return submit_search()">
<input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')"
-onkeyup="return search_changed(event, false, '/')" />
+ onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+ onkeydown="return search_changed(event, true, '/')"
+ onkeyup="return search_changed(event, false, '/')" />
</form>
<div class="right"></div>
- <a class="close hide">close</a>
- <div class="left"></div>
- <div class="right"></div>
- </div>
- </div><!-- end search -->
+ <a class="close hide">close</a>
+ <div class="left"></div>
+ <div class="right"></div>
+ </div><!-- end search-inner -->
+ </div><!-- end search-container -->
<div class="search_filtered_wrapper reference">
<div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
<ul class="search_filtered">
</ul>
</div>
- </div><!-- end search_filtered_wrapper -->
-
</div>
- <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
- </div><!-- end header-wrap -->
- </div>
- <!-- /Header -->
+ </div><!-- end header-wrap -->
+ </div><!-- /Header -->
<div id="searchResults" class="wrap" style="display:none;">
<h2 id="searchTitle">Results</h2>
<div id="leftSearchControl" class="search-control">Loading...</div>
</div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+ <div>
+ <a class="logo" href="#top"></a>
+ <a class="top" href="#top"></a>
+ <ul class="breadcrumb">
+
+ <li class="current">NotificationManagerCompat</li>
+ </ul>
+ </div>
+</div>
-
<div class="wrap clearfix" id="body-content">
<div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
<div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
<ul id="nav">
@@ -327,7 +344,7 @@
</ul>
-
+
</div>
</div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
+
<div class="col-12" id="doc-col">
<div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html b/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html
index 6fbf8b6..77807e4 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html
@@ -82,13 +82,6 @@
-
-
-
-
-
-
-
<html>
<head>
@@ -101,13 +94,15 @@
<!-- STYLESHEETS -->
<link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+ title="roboto">
<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
<!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
<script type="text/javascript">
var toRoot = "/";
@@ -130,7 +125,7 @@
</head>
<body class="gc-documentation
- develop" itemscope itemtype="http://schema.org/Article">
+ preview" itemscope itemtype="http://schema.org/Article">
<div id="doc-api-level" class="" style="display:none"></div>
<a name="top"></a>
@@ -138,31 +133,30 @@
<a name="top"></a>
- <!-- Header -->
- <div id="header">
- <div class="wrap" id="header-wrap">
- <div class="col-3 logo-wear">
- <a href="/wear/index.html">
- <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
- </a>
- </div>
+<!-- Header -->
+<div id="header-wrapper">
+ <div id="header">
+ <div class="wrap" id="header-wrap">
+ <div class="col_3 logo wear-logo">
+ <a href="/wear/index.html">
+ <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+ </a>
+ </div>
+ <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-
- <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
- color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-
-
- <!-- New Search -->
- <div class="menu-container">
- <div class="moremenu">
- <div id="more-btn"></div>
- </div>
+
+
+<div class="menu-container">
+ <div class="moremenu">
+ <div id="more-btn"></div>
+ </div>
<div class="morehover" id="moremenu">
<div class="top"></div>
<div class="mid">
<div class="header">Links</div>
<ul>
- <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+ <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
<li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
<li><a href="/about/index.html">About Android</a></li>
</ul>
@@ -172,16 +166,32 @@
<li class="active"><a>Android Developers</a></li>
<li><a href="http://source.android.com">Android Open Source Project</a></li>
</ul>
-
-
-
-
-
+
+
+ <div class="header">Language</div>
+ <div id="language" class="locales">
+ <select name="language" onChange="changeLangPref(this.value, true)">
+ <option value="en">English</option>
+ <option value="es">Español</option>
+ <option value="ja">日本語</option>
+ <option value="ko">한국어</option>
+ <option value="ru">Русский</option>
+ <option value="zh-cn">中文 (中国)</option>
+ <option value="zh-tw">中文 (台灣)</option>
+ </select>
+ </div>
+ <script type="text/javascript">
+ <!--
+ loadLangPref();
+ //-->
+ </script>
+
+
<br class="clearfix" />
- </div><!-- end mid -->
+ </div><!-- end 'mid' -->
<div class="bottom"></div>
- </div><!-- end morehover -->
+ </div><!-- end 'moremenu' -->
<div class="search" id="search-container">
<div class="search-inner">
@@ -189,16 +199,16 @@
<div class="left"></div>
<form onsubmit="return submit_search()">
<input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')"
-onkeyup="return search_changed(event, false, '/')" />
+ onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+ onkeydown="return search_changed(event, true, '/')"
+ onkeyup="return search_changed(event, false, '/')" />
</form>
<div class="right"></div>
- <a class="close hide">close</a>
- <div class="left"></div>
- <div class="right"></div>
- </div>
- </div><!-- end search -->
+ <a class="close hide">close</a>
+ <div class="left"></div>
+ <div class="right"></div>
+ </div><!-- end search-inner -->
+ </div><!-- end search-container -->
<div class="search_filtered_wrapper reference">
<div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
<ul class="search_filtered">
</ul>
</div>
- </div><!-- end search_filtered_wrapper -->
-
</div>
- <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
- </div><!-- end header-wrap -->
- </div>
- <!-- /Header -->
+ </div><!-- end header-wrap -->
+ </div><!-- /Header -->
<div id="searchResults" class="wrap" style="display:none;">
<h2 id="searchTitle">Results</h2>
<div id="leftSearchControl" class="search-control">Loading...</div>
</div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+ <div>
+ <a class="logo" href="#top"></a>
+ <a class="top" href="#top"></a>
+ <ul class="breadcrumb">
+
+ <li class="current">RemoteInput.Builder</li>
+ </ul>
+ </div>
+</div>
-
<div class="wrap clearfix" id="body-content">
<div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
<div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
<ul id="nav">
@@ -327,7 +344,7 @@
</ul>
-
+
</div>
</div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
+
<div class="col-12" id="doc-col">
<div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.html b/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.html
index 0e1cebe..43fd36e 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.html
@@ -82,13 +82,6 @@
-
-
-
-
-
-
-
<html>
<head>
@@ -101,13 +94,15 @@
<!-- STYLESHEETS -->
<link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+ title="roboto">
<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
<!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
<script type="text/javascript">
var toRoot = "/";
@@ -130,7 +125,7 @@
</head>
<body class="gc-documentation
- develop" itemscope itemtype="http://schema.org/Article">
+ preview" itemscope itemtype="http://schema.org/Article">
<div id="doc-api-level" class="" style="display:none"></div>
<a name="top"></a>
@@ -138,31 +133,30 @@
<a name="top"></a>
- <!-- Header -->
- <div id="header">
- <div class="wrap" id="header-wrap">
- <div class="col-3 logo-wear">
- <a href="/wear/index.html">
- <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
- </a>
- </div>
+<!-- Header -->
+<div id="header-wrapper">
+ <div id="header">
+ <div class="wrap" id="header-wrap">
+ <div class="col_3 logo wear-logo">
+ <a href="/wear/index.html">
+ <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+ </a>
+ </div>
+ <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-
- <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
- color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-
-
- <!-- New Search -->
- <div class="menu-container">
- <div class="moremenu">
- <div id="more-btn"></div>
- </div>
+
+
+<div class="menu-container">
+ <div class="moremenu">
+ <div id="more-btn"></div>
+ </div>
<div class="morehover" id="moremenu">
<div class="top"></div>
<div class="mid">
<div class="header">Links</div>
<ul>
- <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+ <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
<li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
<li><a href="/about/index.html">About Android</a></li>
</ul>
@@ -172,16 +166,32 @@
<li class="active"><a>Android Developers</a></li>
<li><a href="http://source.android.com">Android Open Source Project</a></li>
</ul>
-
-
-
-
-
+
+
+ <div class="header">Language</div>
+ <div id="language" class="locales">
+ <select name="language" onChange="changeLangPref(this.value, true)">
+ <option value="en">English</option>
+ <option value="es">Español</option>
+ <option value="ja">日本語</option>
+ <option value="ko">한국어</option>
+ <option value="ru">Русский</option>
+ <option value="zh-cn">中文 (中国)</option>
+ <option value="zh-tw">中文 (台灣)</option>
+ </select>
+ </div>
+ <script type="text/javascript">
+ <!--
+ loadLangPref();
+ //-->
+ </script>
+
+
<br class="clearfix" />
- </div><!-- end mid -->
+ </div><!-- end 'mid' -->
<div class="bottom"></div>
- </div><!-- end morehover -->
+ </div><!-- end 'moremenu' -->
<div class="search" id="search-container">
<div class="search-inner">
@@ -189,16 +199,16 @@
<div class="left"></div>
<form onsubmit="return submit_search()">
<input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')"
-onkeyup="return search_changed(event, false, '/')" />
+ onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+ onkeydown="return search_changed(event, true, '/')"
+ onkeyup="return search_changed(event, false, '/')" />
</form>
<div class="right"></div>
- <a class="close hide">close</a>
- <div class="left"></div>
- <div class="right"></div>
- </div>
- </div><!-- end search -->
+ <a class="close hide">close</a>
+ <div class="left"></div>
+ <div class="right"></div>
+ </div><!-- end search-inner -->
+ </div><!-- end search-container -->
<div class="search_filtered_wrapper reference">
<div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
<ul class="search_filtered">
</ul>
</div>
- </div><!-- end search_filtered_wrapper -->
-
</div>
- <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
- </div><!-- end header-wrap -->
- </div>
- <!-- /Header -->
+ </div><!-- end header-wrap -->
+ </div><!-- /Header -->
<div id="searchResults" class="wrap" style="display:none;">
<h2 id="searchTitle">Results</h2>
<div id="leftSearchControl" class="search-control">Loading...</div>
</div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+ <div>
+ <a class="logo" href="#top"></a>
+ <a class="top" href="#top"></a>
+ <ul class="breadcrumb">
+
+ <li class="current">RemoteInput</li>
+ </ul>
+ </div>
+</div>
-
<div class="wrap clearfix" id="body-content">
<div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
<div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
<ul id="nav">
@@ -327,7 +344,7 @@
</ul>
-
+
</div>
</div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
+
<div class="col-12" id="doc-col">
<div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html
index f27d406..9592e27 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html
@@ -82,13 +82,6 @@
-
-
-
-
-
-
-
<html>
<head>
@@ -101,13 +94,15 @@
<!-- STYLESHEETS -->
<link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+ title="roboto">
<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
<!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
<script type="text/javascript">
var toRoot = "/";
@@ -130,7 +125,7 @@
</head>
<body class="gc-documentation
- develop" itemscope itemtype="http://schema.org/Article">
+ preview" itemscope itemtype="http://schema.org/Article">
<div id="doc-api-level" class="" style="display:none"></div>
<a name="top"></a>
@@ -138,31 +133,30 @@
<a name="top"></a>
- <!-- Header -->
- <div id="header">
- <div class="wrap" id="header-wrap">
- <div class="col-3 logo-wear">
- <a href="/wear/index.html">
- <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
- </a>
- </div>
+<!-- Header -->
+<div id="header-wrapper">
+ <div id="header">
+ <div class="wrap" id="header-wrap">
+ <div class="col_3 logo wear-logo">
+ <a href="/wear/index.html">
+ <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+ </a>
+ </div>
+ <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-
- <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
- color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-
-
- <!-- New Search -->
- <div class="menu-container">
- <div class="moremenu">
- <div id="more-btn"></div>
- </div>
+
+
+<div class="menu-container">
+ <div class="moremenu">
+ <div id="more-btn"></div>
+ </div>
<div class="morehover" id="moremenu">
<div class="top"></div>
<div class="mid">
<div class="header">Links</div>
<ul>
- <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+ <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
<li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
<li><a href="/about/index.html">About Android</a></li>
</ul>
@@ -172,16 +166,32 @@
<li class="active"><a>Android Developers</a></li>
<li><a href="http://source.android.com">Android Open Source Project</a></li>
</ul>
-
-
-
-
-
+
+
+ <div class="header">Language</div>
+ <div id="language" class="locales">
+ <select name="language" onChange="changeLangPref(this.value, true)">
+ <option value="en">English</option>
+ <option value="es">Español</option>
+ <option value="ja">日本語</option>
+ <option value="ko">한국어</option>
+ <option value="ru">Русский</option>
+ <option value="zh-cn">中文 (中国)</option>
+ <option value="zh-tw">中文 (台灣)</option>
+ </select>
+ </div>
+ <script type="text/javascript">
+ <!--
+ loadLangPref();
+ //-->
+ </script>
+
+
<br class="clearfix" />
- </div><!-- end mid -->
+ </div><!-- end 'mid' -->
<div class="bottom"></div>
- </div><!-- end morehover -->
+ </div><!-- end 'moremenu' -->
<div class="search" id="search-container">
<div class="search-inner">
@@ -189,16 +199,16 @@
<div class="left"></div>
<form onsubmit="return submit_search()">
<input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')"
-onkeyup="return search_changed(event, false, '/')" />
+ onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+ onkeydown="return search_changed(event, true, '/')"
+ onkeyup="return search_changed(event, false, '/')" />
</form>
<div class="right"></div>
- <a class="close hide">close</a>
- <div class="left"></div>
- <div class="right"></div>
- </div>
- </div><!-- end search -->
+ <a class="close hide">close</a>
+ <div class="left"></div>
+ <div class="right"></div>
+ </div><!-- end search-inner -->
+ </div><!-- end search-container -->
<div class="search_filtered_wrapper reference">
<div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
<ul class="search_filtered">
</ul>
</div>
- </div><!-- end search_filtered_wrapper -->
-
</div>
- <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
- </div><!-- end header-wrap -->
- </div>
- <!-- /Header -->
+ </div><!-- end header-wrap -->
+ </div><!-- /Header -->
<div id="searchResults" class="wrap" style="display:none;">
<h2 id="searchTitle">Results</h2>
<div id="leftSearchControl" class="search-control">Loading...</div>
</div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+ <div>
+ <a class="logo" href="#top"></a>
+ <a class="top" href="#top"></a>
+ <ul class="breadcrumb">
+
+ <li class="current">WearableNotifications.Action.Builder</li>
+ </ul>
+ </div>
+</div>
-
<div class="wrap clearfix" id="body-content">
<div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
<div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
<ul id="nav">
@@ -327,7 +344,7 @@
</ul>
-
+
</div>
</div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
+
<div class="col-12" id="doc-col">
<div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html
index ff9c904..8073fa8 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html
@@ -82,13 +82,6 @@
-
-
-
-
-
-
-
<html>
<head>
@@ -101,13 +94,15 @@
<!-- STYLESHEETS -->
<link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+ title="roboto">
<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
<!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
<script type="text/javascript">
var toRoot = "/";
@@ -130,7 +125,7 @@
</head>
<body class="gc-documentation
- develop" itemscope itemtype="http://schema.org/Article">
+ preview" itemscope itemtype="http://schema.org/Article">
<div id="doc-api-level" class="" style="display:none"></div>
<a name="top"></a>
@@ -138,31 +133,30 @@
<a name="top"></a>
- <!-- Header -->
- <div id="header">
- <div class="wrap" id="header-wrap">
- <div class="col-3 logo-wear">
- <a href="/wear/index.html">
- <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
- </a>
- </div>
+<!-- Header -->
+<div id="header-wrapper">
+ <div id="header">
+ <div class="wrap" id="header-wrap">
+ <div class="col_3 logo wear-logo">
+ <a href="/wear/index.html">
+ <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+ </a>
+ </div>
+ <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-
- <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
- color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-
-
- <!-- New Search -->
- <div class="menu-container">
- <div class="moremenu">
- <div id="more-btn"></div>
- </div>
+
+
+<div class="menu-container">
+ <div class="moremenu">
+ <div id="more-btn"></div>
+ </div>
<div class="morehover" id="moremenu">
<div class="top"></div>
<div class="mid">
<div class="header">Links</div>
<ul>
- <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+ <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
<li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
<li><a href="/about/index.html">About Android</a></li>
</ul>
@@ -172,16 +166,32 @@
<li class="active"><a>Android Developers</a></li>
<li><a href="http://source.android.com">Android Open Source Project</a></li>
</ul>
-
-
-
-
-
+
+
+ <div class="header">Language</div>
+ <div id="language" class="locales">
+ <select name="language" onChange="changeLangPref(this.value, true)">
+ <option value="en">English</option>
+ <option value="es">Español</option>
+ <option value="ja">日本語</option>
+ <option value="ko">한국어</option>
+ <option value="ru">Русский</option>
+ <option value="zh-cn">中文 (中国)</option>
+ <option value="zh-tw">中文 (台灣)</option>
+ </select>
+ </div>
+ <script type="text/javascript">
+ <!--
+ loadLangPref();
+ //-->
+ </script>
+
+
<br class="clearfix" />
- </div><!-- end mid -->
+ </div><!-- end 'mid' -->
<div class="bottom"></div>
- </div><!-- end morehover -->
+ </div><!-- end 'moremenu' -->
<div class="search" id="search-container">
<div class="search-inner">
@@ -189,16 +199,16 @@
<div class="left"></div>
<form onsubmit="return submit_search()">
<input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')"
-onkeyup="return search_changed(event, false, '/')" />
+ onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+ onkeydown="return search_changed(event, true, '/')"
+ onkeyup="return search_changed(event, false, '/')" />
</form>
<div class="right"></div>
- <a class="close hide">close</a>
- <div class="left"></div>
- <div class="right"></div>
- </div>
- </div><!-- end search -->
+ <a class="close hide">close</a>
+ <div class="left"></div>
+ <div class="right"></div>
+ </div><!-- end search-inner -->
+ </div><!-- end search-container -->
<div class="search_filtered_wrapper reference">
<div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
<ul class="search_filtered">
</ul>
</div>
- </div><!-- end search_filtered_wrapper -->
-
</div>
- <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
- </div><!-- end header-wrap -->
- </div>
- <!-- /Header -->
+ </div><!-- end header-wrap -->
+ </div><!-- /Header -->
<div id="searchResults" class="wrap" style="display:none;">
<h2 id="searchTitle">Results</h2>
<div id="leftSearchControl" class="search-control">Loading...</div>
</div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+ <div>
+ <a class="logo" href="#top"></a>
+ <a class="top" href="#top"></a>
+ <ul class="breadcrumb">
+
+ <li class="current">WearableNotifications.Action</li>
+ </ul>
+ </div>
+</div>
-
<div class="wrap clearfix" id="body-content">
<div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
<div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
<ul id="nav">
@@ -327,7 +344,7 @@
</ul>
-
+
</div>
</div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
+
<div class="col-12" id="doc-col">
<div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html
index d6ec260..15d3303 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html
@@ -82,13 +82,6 @@
-
-
-
-
-
-
-
<html>
<head>
@@ -101,13 +94,15 @@
<!-- STYLESHEETS -->
<link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+ title="roboto">
<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
<!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
<script type="text/javascript">
var toRoot = "/";
@@ -130,7 +125,7 @@
</head>
<body class="gc-documentation
- develop" itemscope itemtype="http://schema.org/Article">
+ preview" itemscope itemtype="http://schema.org/Article">
<div id="doc-api-level" class="" style="display:none"></div>
<a name="top"></a>
@@ -138,31 +133,30 @@
<a name="top"></a>
- <!-- Header -->
- <div id="header">
- <div class="wrap" id="header-wrap">
- <div class="col-3 logo-wear">
- <a href="/wear/index.html">
- <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
- </a>
- </div>
+<!-- Header -->
+<div id="header-wrapper">
+ <div id="header">
+ <div class="wrap" id="header-wrap">
+ <div class="col_3 logo wear-logo">
+ <a href="/wear/index.html">
+ <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+ </a>
+ </div>
+ <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-
- <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
- color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-
-
- <!-- New Search -->
- <div class="menu-container">
- <div class="moremenu">
- <div id="more-btn"></div>
- </div>
+
+
+<div class="menu-container">
+ <div class="moremenu">
+ <div id="more-btn"></div>
+ </div>
<div class="morehover" id="moremenu">
<div class="top"></div>
<div class="mid">
<div class="header">Links</div>
<ul>
- <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+ <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
<li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
<li><a href="/about/index.html">About Android</a></li>
</ul>
@@ -172,16 +166,32 @@
<li class="active"><a>Android Developers</a></li>
<li><a href="http://source.android.com">Android Open Source Project</a></li>
</ul>
-
-
-
-
-
+
+
+ <div class="header">Language</div>
+ <div id="language" class="locales">
+ <select name="language" onChange="changeLangPref(this.value, true)">
+ <option value="en">English</option>
+ <option value="es">Español</option>
+ <option value="ja">日本語</option>
+ <option value="ko">한국어</option>
+ <option value="ru">Русский</option>
+ <option value="zh-cn">中文 (中国)</option>
+ <option value="zh-tw">中文 (台灣)</option>
+ </select>
+ </div>
+ <script type="text/javascript">
+ <!--
+ loadLangPref();
+ //-->
+ </script>
+
+
<br class="clearfix" />
- </div><!-- end mid -->
+ </div><!-- end 'mid' -->
<div class="bottom"></div>
- </div><!-- end morehover -->
+ </div><!-- end 'moremenu' -->
<div class="search" id="search-container">
<div class="search-inner">
@@ -189,16 +199,16 @@
<div class="left"></div>
<form onsubmit="return submit_search()">
<input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')"
-onkeyup="return search_changed(event, false, '/')" />
+ onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+ onkeydown="return search_changed(event, true, '/')"
+ onkeyup="return search_changed(event, false, '/')" />
</form>
<div class="right"></div>
- <a class="close hide">close</a>
- <div class="left"></div>
- <div class="right"></div>
- </div>
- </div><!-- end search -->
+ <a class="close hide">close</a>
+ <div class="left"></div>
+ <div class="right"></div>
+ </div><!-- end search-inner -->
+ </div><!-- end search-container -->
<div class="search_filtered_wrapper reference">
<div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
<ul class="search_filtered">
</ul>
</div>
- </div><!-- end search_filtered_wrapper -->
-
</div>
- <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
- </div><!-- end header-wrap -->
- </div>
- <!-- /Header -->
+ </div><!-- end header-wrap -->
+ </div><!-- /Header -->
<div id="searchResults" class="wrap" style="display:none;">
<h2 id="searchTitle">Results</h2>
<div id="leftSearchControl" class="search-control">Loading...</div>
</div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+ <div>
+ <a class="logo" href="#top"></a>
+ <a class="top" href="#top"></a>
+ <ul class="breadcrumb">
+
+ <li class="current">WearableNotifications.Builder</li>
+ </ul>
+ </div>
+</div>
-
<div class="wrap clearfix" id="body-content">
<div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
<div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
<ul id="nav">
@@ -327,7 +344,7 @@
</ul>
-
+
</div>
</div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
+
<div class="col-12" id="doc-col">
<div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.html b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.html
index e03e16e..c9948b8 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.html
@@ -82,13 +82,6 @@
-
-
-
-
-
-
-
<html>
<head>
@@ -101,13 +94,15 @@
<!-- STYLESHEETS -->
<link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+ title="roboto">
<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
<!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
<script type="text/javascript">
var toRoot = "/";
@@ -130,7 +125,7 @@
</head>
<body class="gc-documentation
- develop" itemscope itemtype="http://schema.org/Article">
+ preview" itemscope itemtype="http://schema.org/Article">
<div id="doc-api-level" class="" style="display:none"></div>
<a name="top"></a>
@@ -138,31 +133,30 @@
<a name="top"></a>
- <!-- Header -->
- <div id="header">
- <div class="wrap" id="header-wrap">
- <div class="col-3 logo-wear">
- <a href="/wear/index.html">
- <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
- </a>
- </div>
+<!-- Header -->
+<div id="header-wrapper">
+ <div id="header">
+ <div class="wrap" id="header-wrap">
+ <div class="col_3 logo wear-logo">
+ <a href="/wear/index.html">
+ <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+ </a>
+ </div>
+ <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-
- <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
- color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-
-
- <!-- New Search -->
- <div class="menu-container">
- <div class="moremenu">
- <div id="more-btn"></div>
- </div>
+
+
+<div class="menu-container">
+ <div class="moremenu">
+ <div id="more-btn"></div>
+ </div>
<div class="morehover" id="moremenu">
<div class="top"></div>
<div class="mid">
<div class="header">Links</div>
<ul>
- <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+ <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
<li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
<li><a href="/about/index.html">About Android</a></li>
</ul>
@@ -172,16 +166,32 @@
<li class="active"><a>Android Developers</a></li>
<li><a href="http://source.android.com">Android Open Source Project</a></li>
</ul>
-
-
-
-
-
+
+
+ <div class="header">Language</div>
+ <div id="language" class="locales">
+ <select name="language" onChange="changeLangPref(this.value, true)">
+ <option value="en">English</option>
+ <option value="es">Español</option>
+ <option value="ja">日本語</option>
+ <option value="ko">한국어</option>
+ <option value="ru">Русский</option>
+ <option value="zh-cn">中文 (中国)</option>
+ <option value="zh-tw">中文 (台灣)</option>
+ </select>
+ </div>
+ <script type="text/javascript">
+ <!--
+ loadLangPref();
+ //-->
+ </script>
+
+
<br class="clearfix" />
- </div><!-- end mid -->
+ </div><!-- end 'mid' -->
<div class="bottom"></div>
- </div><!-- end morehover -->
+ </div><!-- end 'moremenu' -->
<div class="search" id="search-container">
<div class="search-inner">
@@ -189,16 +199,16 @@
<div class="left"></div>
<form onsubmit="return submit_search()">
<input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')"
-onkeyup="return search_changed(event, false, '/')" />
+ onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+ onkeydown="return search_changed(event, true, '/')"
+ onkeyup="return search_changed(event, false, '/')" />
</form>
<div class="right"></div>
- <a class="close hide">close</a>
- <div class="left"></div>
- <div class="right"></div>
- </div>
- </div><!-- end search -->
+ <a class="close hide">close</a>
+ <div class="left"></div>
+ <div class="right"></div>
+ </div><!-- end search-inner -->
+ </div><!-- end search-container -->
<div class="search_filtered_wrapper reference">
<div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
<ul class="search_filtered">
</ul>
</div>
- </div><!-- end search_filtered_wrapper -->
-
</div>
- <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
- </div><!-- end header-wrap -->
- </div>
- <!-- /Header -->
+ </div><!-- end header-wrap -->
+ </div><!-- /Header -->
<div id="searchResults" class="wrap" style="display:none;">
<h2 id="searchTitle">Results</h2>
<div id="leftSearchControl" class="search-control">Loading...</div>
</div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+ <div>
+ <a class="logo" href="#top"></a>
+ <a class="top" href="#top"></a>
+ <ul class="breadcrumb">
+
+ <li class="current">WearableNotifications</li>
+ </ul>
+ </div>
+</div>
-
<div class="wrap clearfix" id="body-content">
<div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
<div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
<ul id="nav">
@@ -327,7 +344,7 @@
</ul>
-
+
</div>
</div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
+
<div class="col-12" id="doc-col">
<div id="api-info-block">
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index e12dfd8..7bf366c 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -75,7 +75,7 @@
<div class="sidebox-wrapper">
<div class="sidebox">
<h2>App Translations in Google Play</h2>
-<p>Google Play <a href="{@docRoot}distribute/googleplay/publish/localizing.html#gp-trans">App
+<p>Google Play <a href="{@docRoot}distribute/tools/localization-checklist.html#gp-trans">App
Translation Service</a> is available in the Developer Console to help you
localize your app for a global user base. You can browse qualified vendors, get
estimates, upload strings for translation, and then import the translations directly
@@ -99,7 +99,7 @@
localization works instantly.</p>
<p>For more information about translation services in Google Play, see <a
-href="{@docRoot}distribute/googleplay/publish/localizing.html#gp-trans">Purchase
+href="{@docRoot}distribute/tools/localization-checklist.html#gp-trans">Purchase
professional translations through the Developer Console</a>.</p>
<p>To install the ADT Translation Manager Plugin follow these steps:</p>
@@ -129,7 +129,7 @@
<ul>
<li>The full ADT Plugin must be installed in your Eclipse environment before you install the ADT Translation Manager Plugin.</li>
<li>ADT Translation Manager Plugin is designed for use with the translation services offered through the Google Play Developer Console. It is not designed for general purpose import/export of strings. </li>
-<li>To use the plugin, you must <a href="{@docRoot}distribute/googleplay/publish/register.html">set up a Developer Console account</a>. </li>
+<li>To use the plugin, you must <a href="{@docRoot}distribute/googleplay/start.html">set up a Developer Console account</a>. </li>
<li>Currently, translation services are available through the Developer Console only as part of a pilot program. To use the plugin, you must first sign up for the pilot program by visiting the Developer Console.</li>
<li>If you downloaded ADT as part of the SDK ADT bundle, you may encounter an error when attempting to download the ADT Translation Manager Plugin from the remote repository. In that case, open the <strong>Install New
Software</strong>, uncheck "Contact all update sites during install to find required software" at the bottom and try again. </li>
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index 8ea5e7e..a2c32f0 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -312,11 +312,6 @@
</div>
-<p>Also note that due to the update to Android Gradle Plugin 0.6, you will encounter errors when opening
-existing projects. See the <a href="#Troubleshooting">Troubleshooting</a> notes below for
-information about how to resolve them.</p>
-
-
<h2 id="Installing">Installing Android Studio</h2>
<p>Android Studio requires JDK 6 or greater (JRE alone is not sufficient). To check if you
have JDK installed (and which version), open a terminal and type <code>javac -version</code>.
@@ -491,8 +486,7 @@
<li>Android Gradle plug-in updated to 0.5.0.
<p class="caution"><strong>Caution:</strong> This new version is not backwards compatible.
When opening a project that uses an older version of the plug-in, Studio will show an error
- stating <strong>Gradle <project_name> project refresh failed.</strong> See <a
- href="#Troubleshooting">Troubleshooting</a> below for details.</p>
+ stating <strong>Gradle <project_name> project refresh failed.</strong></p>
<p>The updated Gradle plug-in includes the following changes:</p>
<ul>
<li>Fixed IDE model to contain the output file even if it's customized through the DSL. Also
@@ -566,65 +560,7 @@
<h2 id="Troubleshooting">Troubleshooting</h2>
-
-<div class="figure" style="width:330px">
-<img src="{@docRoot}images/tools/studio_error_gradle5.png" width="330"/>
-<p class="img-caption"><strong>Figure 1.</strong> Error dialog when opening an existing project.</p>
-</div>
-
-<h3>Error: Gradle project refresh failed</h3>
-
-<p>Android Studio 0.2.0 has updated the Gradle plug-in to 0.5.0, which is not backwards compatible.
-When opening a project that uses an older version of the plug-in, Studio will display the error
-shown in figure 1 in the upper right corner of the IDE.
-To resolve the error, you must change the version of the Android Gradle plug-in to 0.5.0.</p>
-
-<ol>
- <li>Click the link in the error dialog <strong>Search in build.gradle files</strong>. If the dialog
-is no longer visible, click <strong>Event Log</strong>
-<img src="{@docRoot}images/tools/studio_error_eventlog.png"
-style="vertical-align:bottom;margin:0;height:19px"/> in the bottom-right corner of the IDE,
-then click <strong>Search in build.gradle files</strong>.</li>
- <li>Double-click the line under the <em>build.gradle</em> usage. For example:
- <strong>classpath 'com.android.tools.build:gradle:0.4</strong>. This opens the project
- <code>build.gradle</code> file.</li>
- <li>Edit the <code>classpath</code> to change the gradle version to <code>0.5.+</code>.
- For example:
- <pre class="no-pretty-print">
-dependencies {
- classpath 'com.android.tools.build:gradle:<strong>0.5.+</strong>'
-}
-</pre>
- </li>
- <li>Save the file and rebuild your project.</li>
-</ol>
-
-
-
-<div class="figure" style="width:330px">
-<img src="{@docRoot}images/tools/studio_error_supportlib.png" width="330"/>
-<p class="img-caption"><strong>Figure 2.</strong> Error dialog when creating a new project
-or opening a project using the support library.</p>
-</div>
-
-<h3>Error: Failed to import Gradle project</h3>
-
-<p>If, after updating to Android Studio 0.2.x and creating or opening a project, you receive an
-error stating <em>"Could not find any version that matches
-com.android.support:support-v4:13.0.+"</em>, then you must install the <strong>Android Support
-Repository</strong>. This was likely caused because you're pointing Android Studio to an external
-Android SDK location that does not have the new Maven repository included with Android Studio
-0.2.x. This new Maven repository is used by the new build system for the Support Library, instead
-of using the Support Library JAR files, so must be present in the SDK.</p>
-
-
-<ol>
- <li>Open the <strong>Android SDK Manager</strong>.</li>
- <li>Expand the <strong>Extras</strong> directory
-and install <strong>Android Support Repository</strong>.</li>
-</ol>
-
-<p>If you've encountered other problems in Android Studio, look at the following page
+<p>If you encounter problems in Android Studio, look at the following page
for possible resolutions to known issues: <a href="http://tools.android.com/knownissues"
>http://tools.android.com/knownissues</a>.</p>
diff --git a/docs/html/sitemap.txt b/docs/html/sitemap.txt
index 9bff5d4..cd87d1c 100644
--- a/docs/html/sitemap.txt
+++ b/docs/html/sitemap.txt
@@ -17,8 +17,8 @@
http://developer.android.com/google/index.html
http://developer.android.com/distribute/googleplay/publish/index.html
http://developer.android.com/distribute/googleplay/promote/index.html
-http://developer.android.com/distribute/googleplay/quality/index.html
-http://developer.android.com/distribute/googleplay/spotlight/index.html
+http://developer.android.com/distribute/essentials/quality/index.html
+http://developer.android.com/distribute/stories/index.html
http://developer.android.com/distribute/open.html
http://developer.android.com/about/versions/jelly-bean.html
http://developer.android.com/support.html
@@ -64,9 +64,9 @@
http://developer.android.com/design/building-blocks/dialogs.html
http://developer.android.com/design/building-blocks/pickers.html
http://developer.android.com/google/play-services/maps.html
-http://developer.android.com/distribute/googleplay/quality/tablet.html
-http://developer.android.com/distribute/googleplay/spotlight/tablets.html
-http://developer.android.com/distribute/googleplay/quality/core.html
+http://developer.android.com/distribute/essentials/quality/tablet.html
+http://developer.android.com/distribute/stories/tablets.html
+http://developer.android.com/distribute/essentials/quality/core.html
http://developer.android.com/guide/topics/ui/notifiers/notifications.html
http://developer.android.com/guide/topics/ui/dialogs.html
http://developer.android.com/downloads/design/Android_Design_Downloads_20120823.zip
@@ -173,13 +173,13 @@
http://developer.android.com/distribute/googleplay/about/visibility.html
http://developer.android.com/distribute/googleplay/about/monetizing.html
http://developer.android.com/distribute/googleplay/about/distribution.html
-http://developer.android.com/distribute/googleplay/publish/register.html
+http://developer.android.com/distribute/googleplay/start.html
http://developer.android.com/distribute/googleplay/publish/console.html
-http://developer.android.com/distribute/googleplay/publish/preparing.html
-http://developer.android.com/distribute/googleplay/promote/linking.html
+http://developer.android.com/distribute/tools/launch-checklist.html
+http://developer.android.com/distribute/tools/promote/linking.html
http://developer.android.com/distribute/googleplay/promote/badges.html
http://developer.android.com/distribute/promote/device-art.html
-http://developer.android.com/distribute/googleplay/promote/brand.html
+http://developer.android.com/distribute/tools/promote/brand.html
http://developer.android.com/distribute/googleplay/strategies/app-quality.html
http://developer.android.com/google/play/billing/index.html
http://developer.android.com/google/play/licensing/index.html
diff --git a/docs/html/support.jd b/docs/html/support.jd
index 63bed30..4271eee 100644
--- a/docs/html/support.jd
+++ b/docs/html/support.jd
@@ -1,6 +1,8 @@
page.title=Developer Support
+page.type=about
fullpage=1
-excludeFromSuggestions=true
+page.metaDescription=Resources available to help you report and resolve issues while you are developing apps for Android.
+page.image=/images/android-support-card.png
@jd:body
<div class="wrap" style="width:940px;">
diff --git a/docs/html/tools/publishing/preparing.jd b/docs/html/tools/publishing/preparing.jd
index 413b56e..7192aa8 100644
--- a/docs/html/tools/publishing/preparing.jd
+++ b/docs/html/tools/publishing/preparing.jd
@@ -22,7 +22,7 @@
<ol>
<li><a href="{@docRoot}tools/publishing/publishing_overview.html">Publishing Overview</a></li>
<li><a href="{@docRoot}tools/publishing/app-signing.html">Signing Your Applications</a></li>
- <li><a href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch Checklist for Google Play</a></li>
+ <li><a href="{@docRoot}distribute/tools/launch-checklist.html">Launch Checklist for Google Play</a></li>
</ol>
</div>
</div>
@@ -44,7 +44,7 @@
<p>This document summarizes the main tasks you need to perform to prepare your application for
release. The tasks that are described in this document apply to all Android applications regardless
how they are released or distributed to users. If you are releasing your application through Google
-Play, you should also read <a href="{@docRoot}distribute/googleplay/publish/preparing.html">Publishing
+Play, you should also read <a href="{@docRoot}distribute/tools/launch-checklist.html">Publishing
Checklist for Google Play</a> to be sure your release-ready application satisfies all Google Play
requirements.</p>
@@ -353,7 +353,7 @@
behaves correctly, you can release your application to users. For more information, see
<a href="{@docRoot}tools/publishing/publishing_overview.html#publishing-release">Releasing Your
Application to Users</a>. If you are publishing your application on Google Play, see
-<a href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch Checklist
+<a href="{@docRoot}distribute/tools/launch-checklist.html">Launch Checklist
for Google Play</a>.</p>
diff --git a/docs/html/tools/publishing/publishing_overview.jd b/docs/html/tools/publishing/publishing_overview.jd
index ea01e20..c4b3bdf 100644
--- a/docs/html/tools/publishing/publishing_overview.jd
+++ b/docs/html/tools/publishing/publishing_overview.jd
@@ -16,7 +16,7 @@
</ol>
<h2>See also</h2>
<ol>
- <li><a href="{@docRoot}distribute/googleplay/publish/preparing.html">Publishing on Google Play</a></li>
+ <li><a href="{@docRoot}distribute/tools/launch-checklist.html">Publishing on Google Play</a></li>
</ol>
</div>
</div>
@@ -35,7 +35,7 @@
</li>
</ul>
-<p>Usually, you release your application through an application marketplace, such as <a href="{@docRoot}distribute/index.html">Google Play</a>.
+<p>Usually, you release your application through an application marketplace, such as <a href="{@docRoot}distribute/googleplay/index.html">Google Play</a>.
However, you can also release applications by sending them directly to users or by letting users
download them from your own website.</p>
@@ -157,7 +157,7 @@
</li>
</ul>
-<p>For information complete information, see <a href="{@docRoot}distribute/index.html">Google Play</a>.</p>
+<p>For information complete information, see <a href="{@docRoot}distribute/googleplay/index.html">Google Play</a>.</p>
<h3 id="publishing-email">Releasing your application through email</h3>
diff --git a/docs/html/tools/publishing/versioning.jd b/docs/html/tools/publishing/versioning.jd
index a1cfb30..6d3ec2f 100644
--- a/docs/html/tools/publishing/versioning.jd
+++ b/docs/html/tools/publishing/versioning.jd
@@ -25,7 +25,7 @@
<ol>
<li><a href="{@docRoot}tools/publishing/preparing.html">Preparing to Publish Your Application</a></li>
-<li><a href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch Checklist for Google Play</a></li>
+<li><a href="{@docRoot}distribute/tools/launch-checklist.html">Launch Checklist for Google Play</a></li>
<li><a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a></li>
</ol>
diff --git a/docs/html/tools/revisions/build-tools.jd b/docs/html/tools/revisions/build-tools.jd
index c3c83ef..d8abab0 100644
--- a/docs/html/tools/revisions/build-tools.jd
+++ b/docs/html/tools/revisions/build-tools.jd
@@ -77,6 +77,26 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>Build Tools, Revision 19.1.0</a> <em>(May 2014)</em>
+ </p>
+ <div class="toggle-content-toggleme">
+
+ <dl>
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Added <code>zipalign</code> to the Build Tools.</li>
+ <li>Modified <code>aapt</code> to ignore XML files that fail to compile.</li>
+ </ul>
+ </dd>
+ </dl>
+
+ </div>
+</div>
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>Build Tools, Revision 19.0.3</a> <em>(March 2014)</em>
</p>
<div class="toggle-content-toggleme">
diff --git a/docs/html/training/basics/intents/sending.jd b/docs/html/training/basics/intents/sending.jd
index 30dc95a..2a4dae7 100644
--- a/docs/html/training/basics/intents/sending.jd
+++ b/docs/html/training/basics/intents/sending.jd
@@ -166,7 +166,7 @@
starts in case you need to disable the feature that uses the intent before the user attempts to use
it. If you know of a specific app that can handle the intent, you can also provide a link for the
user to download the app (see how to <a
-href="{@docRoot}distribute/googleplay/promote/linking.html">link to your product on Google
+href="{@docRoot}distribute/tools/promote/linking.html">link to your product on Google
Play</a>).</p>
diff --git a/docs/html/training/basics/supporting-devices/languages.jd b/docs/html/training/basics/supporting-devices/languages.jd
index 5a1507c..45e2ab2 100644
--- a/docs/html/training/basics/supporting-devices/languages.jd
+++ b/docs/html/training/basics/supporting-devices/languages.jd
@@ -19,7 +19,7 @@
</ol>
<h2>You should also read</h2>
<ul>
- <li><a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a></li>
+ <li><a href="{@docRoot}distribute/tools/localization-checklist.html">Localization Checklist</a></li>
<li><a href="{@docRoot}guide/topics/resources/localization.html">Localization with Resources</a></li>
</ul>
</div>
diff --git a/docs/html/training/basics/supporting-devices/platforms.jd b/docs/html/training/basics/supporting-devices/platforms.jd
index c38101a..60aaf6a 100644
--- a/docs/html/training/basics/supporting-devices/platforms.jd
+++ b/docs/html/training/basics/supporting-devices/platforms.jd
@@ -1,4 +1,5 @@
page.title=Supporting Different Platform Versions
+page.metaDescription=Training on how to declare support for minimum and target API levels.
parent.title=Supporting Different Devices
parent.link=index.html
diff --git a/docs/html/training/design-navigation/multiple-sizes.jd b/docs/html/training/design-navigation/multiple-sizes.jd
index 26a5828..a0ce103 100644
--- a/docs/html/training/design-navigation/multiple-sizes.jd
+++ b/docs/html/training/design-navigation/multiple-sizes.jd
@@ -8,6 +8,10 @@
next.title=Providing Descendant and Lateral Navigation
next.link=descendant-lateral.html
+meta.tags="multiple screens"
+page.metaDescription=Designing an intuitive, effective navigation for tablets and other devices.
+page.image=/images/training/app-navigation-multiple-sizes-strategy-stack.png
+
@jd:body
<div id="tb-wrapper">
diff --git a/docs/html/training/multiscreen/index.jd b/docs/html/training/multiscreen/index.jd
index 45b6161..8eff246 100644
--- a/docs/html/training/multiscreen/index.jd
+++ b/docs/html/training/multiscreen/index.jd
@@ -1,5 +1,6 @@
page.title=Designing for Multiple Screens
-page.tags=tablet,tv,fragments,support
+page.tags="tablet","tv","fragments","support"
+page.metaDescription=Training on how to add intuitive, effective navigation for tablets and other devices.
trainingnavtop=true
startpage=true
diff --git a/docs/html/training/multiscreen/screendensities.jd b/docs/html/training/multiscreen/screendensities.jd
index 7d6ff44..7817830 100644
--- a/docs/html/training/multiscreen/screendensities.jd
+++ b/docs/html/training/multiscreen/screendensities.jd
@@ -1,4 +1,7 @@
page.title=Supporting Different Densities
+page.metaDescription=Providing sets of layouts and drawable resources for specific ranges of device screens.
+meta.tags="multiple screens"
+
parent.title=Designing for Multiple Screens
parent.link=index.html
diff --git a/docs/html/wear/images/notif_summary_framed.png b/docs/html/wear/images/notif_summary_framed.png
new file mode 100644
index 0000000..17b1703
--- /dev/null
+++ b/docs/html/wear/images/notif_summary_framed.png
Binary files differ
diff --git a/docs/html/wear/notifications/stacks.jd b/docs/html/wear/notifications/stacks.jd
index 7f955f6..a2d34ce 100644
--- a/docs/html/wear/notifications/stacks.jd
+++ b/docs/html/wear/notifications/stacks.jd
@@ -2,8 +2,8 @@
@jd:body
-<img src="{@docRoot}wear/images/11_bundles_B.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" />
-<img src="{@docRoot}wear/images/11_bundles_A.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" />
+<img src="{@docRoot}wear/images/11_bundles_B.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" alt="" />
+<img src="{@docRoot}wear/images/11_bundles_A.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" alt="" />
<p>When creating notifications for a handheld device, you should always aggregate similar
notifications into a single summary notification. For example, if your app creates notifications
@@ -29,20 +29,44 @@
<p>To create a stack, call <a
href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)">
-<code>setGroup()</code></a> for each notification you want in the stack, passing the same
-group key. For example:</p>
+<code>setGroup()</code></a> for each notification you want in the stack and specify a
+group key. Then call <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a> to send it to the wearable.</p>
<pre style="clear:right">
final static String GROUP_KEY_EMAILS = "group_key_emails";
+// Build the notification and pass this builder to WearableNotifications.Builder
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
- .setContentTitle("New mail from " + sender)
- .setContentText(subject)
+ .setContentTitle("New mail from " + sender1)
+ .setContentText(subject1)
.setSmallIcon(R.drawable.new_mail);
-Notification notif = new WearableNotifications.Builder(builder)
+Notification notif1 = new WearableNotifications.Builder(builder)
.setGroup(GROUP_KEY_EMAILS)
.build();
+
+// Issue the notification
+NotificationManagerCompat notificationManager =
+ NotificationManagerCompat.from(this);
+notificationManager.notify(notificationId1, notif);
+</pre>
+
+<p>Later on, when you create another notification, specify
+the same group key. When you call <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a>, this notification appears
+in the same stack as the previous notification, instead of as a new card:</p>
+
+<pre style="clear:right">
+builder = new NotificationCompat.Builder(mContext)
+ .setContentTitle("New mail from " + sender2)
+ .setContentText(subject2)
+ .setSmallIcon(R.drawable.new_mail);
+
+// Use the same group as the previous notification
+Notification notif2 = new WearableNotifications.Builder(builder)
+ .setGroup(GROUP_KEY_EMAILS)
+ .build();
+
+notificationManager.notify(notificationId2, notif);
</pre>
<p>By default, notifications appear in the order in which you added them, with the most recent
@@ -54,19 +78,55 @@
<h2 id="AddSummary">Add a Summary Notification</h2>
+<img src="{@docRoot}wear/images/notif_summary_framed.png" height="242" width="330" style="float:right;margin:0 0 20px 40px" alt="" />
+
<p>It's important that you still provide a summary notification that appears on handheld devices.
So in addition to adding each unique notification to the same stack group, also add a summary
notification, but set its order position to be <a
href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.html#GROUP_ORDER_SUMMARY"><code>GROUP_ORDER_SUMMARY</code></a>.</p>
-<pre>
-Notification summaryNotification = new WearableNotifications.Builder(builder)
- .setGroup(GROUP_KEY_EMAILS, WearableNotifications.GROUP_ORDER_SUMMARY)
- .build();
+<p>This notification does not appear in your stack of notifications on the wearable, but
+appears as the only notification on the handheld device.</p>
+
+<pre style="clear:right">
+Bitmap largeIcon = BitmapFactory.decodeResource(getResources(),
+ R.drawable.ic_large_icon);
+
+builder = new NotificationCompat.Builder(this)
+ .setSmallIcon(R.drawable.ic_small_icon)
+ .setLargeIcon(largeIcon);
+
+// Use the same group key and pass this builder to InboxStyle notification
+WearableNotifications.Builder wearableBuilder = new WearableNotifications
+ .Builder(builder)
+ .setGroup(GROUP_KEY_EMAILS,
+ WearableNotifications.GROUP_ORDER_SUMMARY);
+
+// Build the final notification to show on the handset
+Notification summaryNotification = new NotificationCompat.InboxStyle(
+ wearableBuilder.getCompatBuilder())
+ .addLine("Alex Faaborg Check this out")
+ .addLine("Jeff Chang Launch Party")
+ .setBigContentTitle("2 new messages")
+ .setSummaryText("johndoe@gmail.com")
+ .build();
+
+notificationManager.notify(notificationId3, summaryNotification);
</pre>
-<p>This notification will not appear in your stack of notifications on the wearable, but
-appears as the only notification on the handheld device.
+<p>
+This notification uses {@link android.support.v4.app.NotificationCompat.InboxStyle},
+which gives you an easy way to create notifications for email or messaging apps.
+You can use this style, another one defined in {@link android.support.v4.app.NotificationCompat},
+or no style for the summary notification.
+</p>
+<p class="note"><b>Tip:</b>
+To style the text like in the example screenshot, see
+<a href="{@docRoot}guide/topics/resources/string-resource.html#StylingWithHTML">Styling
+with HTML markup</a> and
+<a href="{@docRoot}guide/topics/resources/string-resource.html#StylingWithSpannables">Styling
+with Spannables</a>.
+</p>
</body>
-</html>
+</html>
\ No newline at end of file
diff --git a/graphics/java/android/graphics/CanvasProperty.java b/graphics/java/android/graphics/CanvasProperty.java
index 99ea9b1..be86060 100644
--- a/graphics/java/android/graphics/CanvasProperty.java
+++ b/graphics/java/android/graphics/CanvasProperty.java
@@ -16,12 +16,15 @@
package android.graphics;
+import com.android.internal.util.VirtualRefBasePtr;
+
/**
* TODO: Make public?
* @hide
*/
public final class CanvasProperty<T> {
- private long mNativeContainer;
+
+ private VirtualRefBasePtr mProperty;
public static CanvasProperty<Float> createFloat(float initialValue) {
return new CanvasProperty<Float>(nCreateFloat(initialValue));
@@ -32,25 +35,14 @@
}
private CanvasProperty(long nativeContainer) {
- mNativeContainer = nativeContainer;
+ mProperty = new VirtualRefBasePtr(nativeContainer);
}
/** @hide */
public long getNativeContainer() {
- return mNativeContainer;
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- nUnref(mNativeContainer);
- mNativeContainer = 0;
- } finally {
- super.finalize();
- }
+ return mProperty.get();
}
private static native long nCreateFloat(float initialValue);
private static native long nCreatePaint(long initialValuePaintPtr);
- private static native void nUnref(long ptr);
}
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
new file mode 100644
index 0000000..a759a79
--- /dev/null
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import java.io.File;
+
+/**
+ * A family of typefaces with different styles.
+ *
+ * @hide
+ */
+public class FontFamily {
+ /**
+ * @hide
+ */
+ public long mNativePtr;
+
+ public FontFamily() {
+ mNativePtr = nCreateFamily();
+ mNativePtr = nCreateFamily();
+ if (mNativePtr == 0) {
+ throw new RuntimeException();
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ nUnrefFamily(mNativePtr);
+ } finally {
+ super.finalize();
+ }
+ }
+
+ public boolean addFont(File path) {
+ return nAddFont(mNativePtr, path.getAbsolutePath());
+ }
+
+ static native long nCreateFamily();
+ static native void nUnrefFamily(long nativePtr);
+ static native boolean nAddFont(long nativeFamily, String path);
+}
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
new file mode 100644
index 0000000..f304f4e
--- /dev/null
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Parser for font config files.
+ *
+ * @hide
+ */
+public class FontListParser {
+
+ public static class Family {
+ public Family(List<String> names, List<String> fontFiles) {
+ this.names = names;
+ this.fontFiles = fontFiles;
+ }
+
+ public List<String> names;
+ // todo: need attributes for font files
+ public List<String> fontFiles;
+ }
+
+ /* Parse fallback list (no names) */
+ public static List<Family> parse(InputStream in) throws XmlPullParserException, IOException {
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+ parser.nextTag();
+ return readFamilies(parser);
+ } finally {
+ in.close();
+ }
+ }
+
+ private static List<Family> readFamilies(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ List<Family> families = new ArrayList<Family>();
+ parser.require(XmlPullParser.START_TAG, null, "familyset");
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) continue;
+ if (parser.getName().equals("family")) {
+ families.add(readFamily(parser));
+ } else {
+ skip(parser);
+ }
+ }
+ return families;
+ }
+
+ private static Family readFamily(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ List<String> names = null;
+ List<String> fontFiles = new ArrayList<String>();
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) continue;
+ String tag = parser.getName();
+ if (tag.equals("fileset")) {
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) continue;
+ if (parser.getName().equals("file")) {
+ String filename = parser.nextText();
+ String fullFilename = "/system/fonts/" + filename;
+ fontFiles.add(fullFilename);
+ }
+ }
+ } else if (tag.equals("nameset")) {
+ names = new ArrayList<String>();
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) continue;
+ if (parser.getName().equals("name")) {
+ String name = parser.nextText();
+ names.add(name);
+ }
+ }
+ }
+ }
+ return new Family(names, fontFiles);
+ }
+
+ private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
+ int depth = 1;
+ while (depth > 0) {
+ switch (parser.next()) {
+ case XmlPullParser.START_TAG:
+ depth++;
+ break;
+ case XmlPullParser.END_TAG:
+ depth--;
+ break;
+ }
+ }
+ }
+}
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index 062acaf..fe53a17 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -272,6 +272,7 @@
case NV16:
case YUY2:
case YV12:
+ case JPEG:
case NV21:
case YUV_420_888:
case RAW_SENSOR:
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
index 66bf75c..b4e6bab 100644
--- a/graphics/java/android/graphics/Matrix.java
+++ b/graphics/java/android/graphics/Matrix.java
@@ -245,6 +245,16 @@
}
/**
+ * Gets whether this matrix is affine. An affine matrix preserves
+ * straight lines and has no perspective.
+ *
+ * @return Whether the matrix is affine.
+ */
+ public boolean isAffine() {
+ return native_isAffine(native_instance);
+ }
+
+ /**
* Returns true if will map a rectangle to another rectangle. This can be
* true if the matrix is identity, scale-only, or rotates a multiple of 90
* degrees.
@@ -828,6 +838,7 @@
private static native long native_create(long native_src_or_zero);
private static native boolean native_isIdentity(long native_object);
+ private static native boolean native_isAffine(long native_object);
private static native boolean native_rectStaysRect(long native_object);
private static native void native_reset(long native_object);
private static native void native_set(long native_object,
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index d96484e..92cfd6b 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1661,12 +1661,12 @@
return 0;
}
if (!mHasCompatScaling) {
- return native_getTextWidths(mNativePaint, text, index, count, mBidiFlags, widths);
+ return native_getTextWidths(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags, widths);
}
final float oldSize = getTextSize();
setTextSize(oldSize*mCompatScaling);
- int res = native_getTextWidths(mNativePaint, text, index, count, mBidiFlags, widths);
+ int res = native_getTextWidths(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags, widths);
setTextSize(oldSize);
for (int i=0; i<res; i++) {
widths[i] *= mInvCompatScaling;
@@ -1743,12 +1743,12 @@
return 0;
}
if (!mHasCompatScaling) {
- return native_getTextWidths(mNativePaint, text, start, end, mBidiFlags, widths);
+ return native_getTextWidths(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, widths);
}
final float oldSize = getTextSize();
setTextSize(oldSize*mCompatScaling);
- int res = native_getTextWidths(mNativePaint, text, start, end, mBidiFlags, widths);
+ int res = native_getTextWidths(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, widths);
setTextSize(oldSize);
for (int i=0; i<res; i++) {
widths[i] *= mInvCompatScaling;
@@ -1838,13 +1838,13 @@
return 0f;
}
if (!mHasCompatScaling) {
- return native_getTextRunAdvances(mNativePaint, chars, index, count,
+ return native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count,
contextIndex, contextCount, flags, advances, advancesIndex);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
- float res = native_getTextRunAdvances(mNativePaint, chars, index, count,
+ float res = native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count,
contextIndex, contextCount, flags, advances, advancesIndex);
setTextSize(oldSize);
@@ -1969,13 +1969,13 @@
}
if (!mHasCompatScaling) {
- return native_getTextRunAdvances(mNativePaint, text, start, end,
+ return native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end,
contextStart, contextEnd, flags, advances, advancesIndex);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
- float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end,
+ float totalAdvance = native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end,
contextStart, contextEnd, flags, advances, advancesIndex);
setTextSize(oldSize);
@@ -2240,19 +2240,19 @@
private static native void native_setTextLocale(long native_object,
String locale);
- private static native int native_getTextWidths(long native_object,
+ private static native int native_getTextWidths(long native_object, long native_typeface,
char[] text, int index, int count, int bidiFlags, float[] widths);
- private static native int native_getTextWidths(long native_object,
+ private static native int native_getTextWidths(long native_object, long native_typeface,
String text, int start, int end, int bidiFlags, float[] widths);
private static native int native_getTextGlyphs(long native_object,
String text, int start, int end, int contextStart, int contextEnd,
int flags, char[] glyphs);
- private static native float native_getTextRunAdvances(long native_object,
+ private static native float native_getTextRunAdvances(long native_object, long native_typeface,
char[] text, int index, int count, int contextIndex, int contextCount,
int flags, float[] advances, int advancesIndex);
- private static native float native_getTextRunAdvances(long native_object,
+ private static native float native_getTextRunAdvances(long native_object, long native_typeface,
String text, int start, int end, int contextStart, int contextEnd,
int flags, float[] advances, int advancesIndex);
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 8b5609f..437d2f4 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -36,9 +36,21 @@
public int right;
public int bottom;
- private static final Pattern FLATTENED_PATTERN = Pattern.compile(
+ /**
+ * A helper class for flattened rectange pattern recognition. A separate
+ * class to avoid an initialization dependency on a regular expression
+ * causing Rect to not be initializable with an ahead-of-time compilation
+ * scheme.
+ */
+ private static final class UnflattenHelper {
+ private static final Pattern FLATTENED_PATTERN = Pattern.compile(
"(-?\\d+) (-?\\d+) (-?\\d+) (-?\\d+)");
+ static Matcher getMatcher(String str) {
+ return FLATTENED_PATTERN.matcher(str);
+ }
+ }
+
/**
* Create a new empty Rect. All coordinates are initialized to 0.
*/
@@ -152,7 +164,7 @@
* or null if the string is not of that form.
*/
public static Rect unflattenFromString(String str) {
- Matcher matcher = FLATTENED_PATTERN.matcher(str);
+ Matcher matcher = UnflattenHelper.getMatcher(str);
if (!matcher.matches()) {
return null;
}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 73e0e8d..64451c4 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -17,10 +17,21 @@
package android.graphics;
import android.content.res.AssetManager;
-import android.util.SparseArray;
+import android.graphics.FontListParser.Family;
+import android.util.Log;
import android.util.LongSparseArray;
+import android.util.SparseArray;
+
+import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
/**
* The Typeface class specifies the typeface and intrinsic style of a font.
@@ -30,6 +41,8 @@
*/
public class Typeface {
+ private static String TAG = "Typeface";
+
/** The default NORMAL typeface object */
public static final Typeface DEFAULT;
/**
@@ -49,6 +62,10 @@
private static final LongSparseArray<SparseArray<Typeface>> sTypefaceCache =
new LongSparseArray<SparseArray<Typeface>>(3);
+ static Typeface sDefaultTypeface;
+ static Map<String, Typeface> sSystemFontMap;
+ static FontFamily[] sFallbackFonts;
+
/**
* @hide
*/
@@ -62,6 +79,11 @@
private int mStyle = 0;
+ private static void setDefault(Typeface t) {
+ sDefaultTypeface = t;
+ nativeSetDefault(t.native_instance);
+ }
+
/** Returns the typeface's intrinsic style attributes */
public int getStyle() {
return mStyle;
@@ -89,6 +111,9 @@
* @return The best matching typeface.
*/
public static Typeface create(String familyName, int style) {
+ if (sSystemFontMap != null) {
+ return create(sSystemFontMap.get(familyName), style);
+ }
return new Typeface(nativeCreate(familyName, style));
}
@@ -142,7 +167,7 @@
public static Typeface defaultFromStyle(int style) {
return sDefaults[style];
}
-
+
/**
* Create a new typeface from the specified font data.
* @param mgr The application's asset manager
@@ -156,7 +181,7 @@
/**
* Create a new typeface from the specified font file.
*
- * @param path The path to the font data.
+ * @param path The path to the font data.
* @return The new typeface.
*/
public static Typeface createFromFile(File path) {
@@ -166,13 +191,45 @@
/**
* Create a new typeface from the specified font file.
*
- * @param path The full path to the font data.
+ * @param path The full path to the font data.
* @return The new typeface.
*/
public static Typeface createFromFile(String path) {
return new Typeface(nativeCreateFromFile(path));
}
+ /**
+ * Create a new typeface from an array of font families.
+ *
+ * @param families array of font families
+ * @hide
+ */
+ public static Typeface createFromFamilies(FontFamily[] families) {
+ long[] ptrArray = new long[families.length];
+ for (int i = 0; i < families.length; i++) {
+ ptrArray[i] = families[i].mNativePtr;
+ }
+ return new Typeface(nativeCreateFromArray(ptrArray));
+ }
+
+ /**
+ * Create a new typeface from an array of font families, including
+ * also the font families in the fallback list.
+ *
+ * @param families array of font families
+ * @hide
+ */
+ public static Typeface createFromFamiliesWithDefault(FontFamily[] families) {
+ long[] ptrArray = new long[families.length + sFallbackFonts.length];
+ for (int i = 0; i < families.length; i++) {
+ ptrArray[i] = families[i].mNativePtr;
+ }
+ for (int i = 0; i < sFallbackFonts.length; i++) {
+ ptrArray[i + families.length] = sFallbackFonts[i].mNativePtr;
+ }
+ return new Typeface(nativeCreateFromArray(ptrArray));
+ }
+
// don't allow clients to call this directly
private Typeface(long ni) {
if (ni == 0) {
@@ -182,14 +239,76 @@
native_instance = ni;
mStyle = nativeGetStyle(ni);
}
-
+
+ private static FontFamily makeFamilyFromParsed(FontListParser.Family family) {
+ // TODO: expand to handle attributes like lang and variant
+ FontFamily fontFamily = new FontFamily();
+ for (String fontFile : family.fontFiles) {
+ fontFamily.addFont(new File(fontFile));
+ }
+ return fontFamily;
+ }
+
static {
+ // Load font config and initialize Minikin state
+ String systemConfigFilename = "/system/etc/system_fonts.xml";
+ String configFilename = "/system/etc/fallback_fonts.xml";
+ try {
+ // TODO: throws an exception non-Minikin builds, to fail early;
+ // remove when Minikin-only
+ new FontFamily();
+
+ FileInputStream systemIn = new FileInputStream(systemConfigFilename);
+ List<FontListParser.Family> systemFontConfig = FontListParser.parse(systemIn);
+
+ FileInputStream fallbackIn = new FileInputStream(configFilename);
+ List<FontFamily> familyList = new ArrayList<FontFamily>();
+ // Note that the default typeface is always present in the fallback list;
+ // this is an enhancement from pre-Minikin behavior.
+ familyList.add(makeFamilyFromParsed(systemFontConfig.get(0)));
+ for (Family f : FontListParser.parse(fallbackIn)) {
+ familyList.add(makeFamilyFromParsed(f));
+ }
+ sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]);
+ setDefault(Typeface.createFromFamilies(sFallbackFonts));
+
+ Map<String, Typeface> systemFonts = new HashMap<String, Typeface>();
+ for (int i = 0; i < systemFontConfig.size(); i++) {
+ Typeface typeface;
+ Family f = systemFontConfig.get(i);
+ if (i == 0) {
+ // The first entry is the default typeface; no sense in duplicating
+ // the corresponding FontFamily.
+ typeface = sDefaultTypeface;
+ } else {
+ FontFamily fontFamily = makeFamilyFromParsed(f);
+ FontFamily[] families = { fontFamily };
+ typeface = Typeface.createFromFamiliesWithDefault(families);
+ }
+ for (String name : f.names) {
+ systemFonts.put(name, typeface);
+ }
+ }
+ sSystemFontMap = systemFonts;
+
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)");
+ // TODO: normal in non-Minikin case, remove or make error when Minikin-only
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "Error opening " + configFilename);
+ } catch (IOException e) {
+ Log.e(TAG, "Error reading " + configFilename);
+ } catch (XmlPullParserException e) {
+ Log.e(TAG, "XML parse exception for " + configFilename);
+ }
+
+ // Set up defaults and typefaces exposed in public API
DEFAULT = create((String) null, 0);
DEFAULT_BOLD = create((String) null, Typeface.BOLD);
SANS_SERIF = create("sans-serif", 0);
SERIF = create("serif", 0);
MONOSPACE = create("monospace", 0);
-
+
sDefaults = new Typeface[] {
DEFAULT,
DEFAULT_BOLD,
@@ -198,6 +317,7 @@
};
}
+ @Override
protected void finalize() throws Throwable {
try {
nativeUnref(native_instance);
@@ -234,4 +354,6 @@
private static native int nativeGetStyle(long native_instance);
private static native long nativeCreateFromAsset(AssetManager mgr, String path);
private static native long nativeCreateFromFile(String path);
+ private static native long nativeCreateFromArray(long[] familyArray);
+ private static native void nativeSetDefault(long native_instance);
}
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
new file mode 100644
index 0000000..46e3401
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.drawable;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.LongSparseLongArray;
+import android.util.SparseIntArray;
+import android.util.StateSet;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * Drawable containing a set of Drawable keyframes where the currently displayed
+ * keyframe is chosen based on the current state set. Animations between
+ * keyframes may optionally be defined using transition elements.
+ * <p>
+ * This drawable can be defined in an XML file with the <code>
+ * <animated-selector></code> element. Each keyframe Drawable is defined in a
+ * nested <code><item></code> element. Transitions are defined in a nested
+ * <code><transition></code> element.
+ *
+ * @attr ref android.R.styleable#DrawableStates_state_focused
+ * @attr ref android.R.styleable#DrawableStates_state_window_focused
+ * @attr ref android.R.styleable#DrawableStates_state_enabled
+ * @attr ref android.R.styleable#DrawableStates_state_checkable
+ * @attr ref android.R.styleable#DrawableStates_state_checked
+ * @attr ref android.R.styleable#DrawableStates_state_selected
+ * @attr ref android.R.styleable#DrawableStates_state_activated
+ * @attr ref android.R.styleable#DrawableStates_state_active
+ * @attr ref android.R.styleable#DrawableStates_state_single
+ * @attr ref android.R.styleable#DrawableStates_state_first
+ * @attr ref android.R.styleable#DrawableStates_state_middle
+ * @attr ref android.R.styleable#DrawableStates_state_last
+ * @attr ref android.R.styleable#DrawableStates_state_pressed
+ */
+public class AnimatedStateListDrawable extends StateListDrawable {
+ private static final String ELEMENT_TRANSITION = "transition";
+ private static final String ELEMENT_ITEM = "item";
+
+ private AnimatedStateListState mState;
+
+ /** The currently running animation, if any. */
+ private ObjectAnimator mAnim;
+
+ /** Index to be set after the animation ends. */
+ private int mAnimToIndex = -1;
+
+ /** Index away from which we are animating. */
+ private int mAnimFromIndex = -1;
+
+ private boolean mMutated;
+
+ public AnimatedStateListDrawable() {
+ this(null, null);
+ }
+
+ /**
+ * Add a new drawable to the set of keyframes.
+ *
+ * @param stateSet An array of resource IDs to associate with the keyframe
+ * @param drawable The drawable to show when in the specified state
+ * @param id The unique identifier for the keyframe
+ */
+ public void addState(int[] stateSet, Drawable drawable, int id) {
+ if (drawable != null) {
+ mState.addStateSet(stateSet, drawable, id);
+ onStateChange(getState());
+ }
+ }
+
+ /**
+ * Adds a new transition between keyframes.
+ *
+ * @param fromId Unique identifier of the starting keyframe
+ * @param toId Unique identifier of the ending keyframe
+ * @param anim An AnimationDrawable to use as a transition
+ * @param reversible Whether the transition can be reversed
+ */
+ public void addTransition(int fromId, int toId, AnimationDrawable anim, boolean reversible) {
+ mState.addTransition(fromId, toId, anim, reversible);
+ }
+
+ @Override
+ public boolean isStateful() {
+ return true;
+ }
+
+ @Override
+ protected boolean onStateChange(int[] stateSet) {
+ final int keyframeIndex = mState.indexOfKeyframe(stateSet);
+ if (keyframeIndex == getCurrentIndex()) {
+ return false;
+ }
+
+ if (selectTransition(keyframeIndex)) {
+ return true;
+ }
+
+ if (selectDrawable(keyframeIndex)) {
+ return true;
+ }
+
+ return super.onStateChange(stateSet);
+ }
+
+ private boolean selectTransition(int toIndex) {
+ if (mAnim != null) {
+ if (toIndex == mAnimToIndex) {
+ // Already animating to that keyframe.
+ return true;
+ } else if (toIndex == mAnimFromIndex) {
+ // Reverse the current animation.
+ mAnim.reverse();
+ mAnimFromIndex = mAnimToIndex;
+ mAnimToIndex = toIndex;
+ return true;
+ }
+
+ // Changing animation, end the current animation.
+ mAnim.end();
+ }
+
+ final AnimatedStateListState state = mState;
+ final int fromIndex = getCurrentIndex();
+ final int fromId = state.getKeyframeIdAt(fromIndex);
+ final int toId = state.getKeyframeIdAt(toIndex);
+
+ if (toId == 0 || fromId == 0) {
+ // Missing a keyframe ID.
+ return false;
+ }
+
+ final int transitionIndex = state.indexOfTransition(fromId, toId);
+ if (transitionIndex < 0 || !selectDrawable(transitionIndex)) {
+ // Couldn't select a transition.
+ return false;
+ }
+
+ final Drawable d = getCurrent();
+ if (!(d instanceof AnimationDrawable)) {
+ // Transition isn't an animation.
+ return false;
+ }
+
+ final AnimationDrawable ad = (AnimationDrawable) d;
+ final boolean reversed = mState.isTransitionReversed(fromId, toId);
+ final int frameCount = ad.getNumberOfFrames();
+ final int fromFrame = reversed ? frameCount - 1 : 0;
+ final int toFrame = reversed ? 0 : frameCount - 1;
+
+ final FrameInterpolator interp = new FrameInterpolator(ad, reversed);
+ final ObjectAnimator anim = ObjectAnimator.ofInt(ad, "currentIndex", fromFrame, toFrame);
+ anim.setAutoCancel(true);
+ anim.setDuration(interp.getTotalDuration());
+ anim.addListener(mAnimListener);
+ anim.setInterpolator(interp);
+ anim.start();
+
+ mAnim = anim;
+ mAnimFromIndex = fromIndex;
+ mAnimToIndex = toIndex;
+ return true;
+ }
+
+ @Override
+ public void jumpToCurrentState() {
+ super.jumpToCurrentState();
+
+ if (mAnim != null) {
+ mAnim.end();
+ }
+ }
+
+ @Override
+ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+ throws XmlPullParserException, IOException {
+ final TypedArray a = r.obtainAttributes(attrs, R.styleable.AnimatedStateListDrawable);
+
+ super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedStateListDrawable_visible);
+
+ final StateListState stateListState = getStateListState();
+ stateListState.setVariablePadding(a.getBoolean(
+ R.styleable.AnimatedStateListDrawable_variablePadding, false));
+ stateListState.setConstantSize(a.getBoolean(
+ R.styleable.AnimatedStateListDrawable_constantSize, false));
+ stateListState.setEnterFadeDuration(a.getInt(
+ R.styleable.AnimatedStateListDrawable_enterFadeDuration, 0));
+ stateListState.setExitFadeDuration(a.getInt(
+ R.styleable.AnimatedStateListDrawable_exitFadeDuration, 0));
+
+ setDither(a.getBoolean(R.styleable.AnimatedStateListDrawable_dither, true));
+ setAutoMirrored(a.getBoolean(R.styleable.AnimatedStateListDrawable_autoMirrored, false));
+
+ a.recycle();
+
+ int type;
+
+ final int innerDepth = parser.getDepth() + 1;
+ int depth;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && ((depth = parser.getDepth()) >= innerDepth
+ || type != XmlPullParser.END_TAG)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ if (depth > innerDepth) {
+ continue;
+ }
+
+ if (parser.getName().equals(ELEMENT_ITEM)) {
+ parseItem(r, parser, attrs, theme);
+ } else if (parser.getName().equals(ELEMENT_TRANSITION)) {
+ parseTransition(r, parser, attrs, theme);
+ }
+ }
+
+ onStateChange(getState());
+ }
+
+ private int parseTransition(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+ throws XmlPullParserException, IOException {
+ int drawableRes = 0;
+ int fromId = 0;
+ int toId = 0;
+ boolean reversible = false;
+
+ final int numAttrs = attrs.getAttributeCount();
+ for (int i = 0; i < numAttrs; i++) {
+ final int stateResId = attrs.getAttributeNameResource(i);
+ switch (stateResId) {
+ case 0:
+ break;
+ case R.attr.fromId:
+ fromId = attrs.getAttributeResourceValue(i, 0);
+ break;
+ case R.attr.toId:
+ toId = attrs.getAttributeResourceValue(i, 0);
+ break;
+ case R.attr.drawable:
+ drawableRes = attrs.getAttributeResourceValue(i, 0);
+ break;
+ case R.attr.reversible:
+ reversible = attrs.getAttributeBooleanValue(i, false);
+ break;
+ }
+ }
+
+ final Drawable dr;
+ if (drawableRes != 0) {
+ dr = r.getDrawable(drawableRes);
+ } else {
+ int type;
+ while ((type = parser.next()) == XmlPullParser.TEXT) {
+ }
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException(
+ parser.getPositionDescription()
+ + ": <item> tag requires a 'drawable' attribute or "
+ + "child tag defining a drawable");
+ }
+ dr = Drawable.createFromXmlInnerThemed(r, parser, attrs, theme);
+ }
+
+ final AnimationDrawable anim;
+ if (dr instanceof AnimationDrawable) {
+ anim = (AnimationDrawable) dr;
+ } else {
+ throw new XmlPullParserException(parser.getPositionDescription()
+ + ": <transition> tag requires a 'drawable' attribute or "
+ + "child tag defining a drawable of type <animation>");
+ }
+
+ return mState.addTransition(fromId, toId, anim, reversible);
+ }
+
+ private int parseItem(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+ throws XmlPullParserException, IOException {
+ int drawableRes = 0;
+ int keyframeId = 0;
+
+ int j = 0;
+ final int numAttrs = attrs.getAttributeCount();
+ int[] states = new int[numAttrs];
+ for (int i = 0; i < numAttrs; i++) {
+ final int stateResId = attrs.getAttributeNameResource(i);
+ switch (stateResId) {
+ case 0:
+ break;
+ case R.attr.id:
+ keyframeId = attrs.getAttributeResourceValue(i, 0);
+ break;
+ case R.attr.drawable:
+ drawableRes = attrs.getAttributeResourceValue(i, 0);
+ break;
+ default:
+ final boolean hasState = attrs.getAttributeBooleanValue(i, false);
+ states[j++] = hasState ? stateResId : -stateResId;
+ }
+ }
+ states = StateSet.trimStateSet(states, j);
+
+ final Drawable dr;
+ if (drawableRes != 0) {
+ dr = r.getDrawable(drawableRes);
+ } else {
+ int type;
+ while ((type = parser.next()) == XmlPullParser.TEXT) {
+ }
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException(
+ parser.getPositionDescription()
+ + ": <item> tag requires a 'drawable' attribute or "
+ + "child tag defining a drawable");
+ }
+ dr = Drawable.createFromXmlInnerThemed(r, parser, attrs, theme);
+ }
+
+ return mState.addStateSet(states, dr, keyframeId);
+ }
+
+ @Override
+ public Drawable mutate() {
+ if (!mMutated) {
+ final AnimatedStateListState newState = new AnimatedStateListState(mState, this, null);
+ setConstantState(newState);
+ mMutated = true;
+ }
+
+ return this;
+ }
+
+ private final AnimatorListenerAdapter mAnimListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator anim) {
+ selectDrawable(mAnimToIndex);
+
+ mAnimToIndex = -1;
+ mAnimFromIndex = -1;
+ mAnim = null;
+ }
+ };
+
+ static class AnimatedStateListState extends StateListState {
+ private static final int REVERSE_SHIFT = 32;
+ private static final int REVERSE_MASK = 0x1;
+
+ final LongSparseLongArray mTransitions;
+ final SparseIntArray mStateIds;
+
+ AnimatedStateListState(AnimatedStateListState orig, AnimatedStateListDrawable owner,
+ Resources res) {
+ super(orig, owner, res);
+
+ if (orig != null) {
+ mTransitions = orig.mTransitions.clone();
+ mStateIds = orig.mStateIds.clone();
+ } else {
+ mTransitions = new LongSparseLongArray();
+ mStateIds = new SparseIntArray();
+ }
+ }
+
+ int addTransition(int fromId, int toId, AnimationDrawable anim, boolean reversible) {
+ final int pos = super.addChild(anim);
+ final long keyFromTo = generateTransitionKey(fromId, toId);
+ mTransitions.append(keyFromTo, pos);
+
+ if (reversible) {
+ final long keyToFrom = generateTransitionKey(toId, fromId);
+ mTransitions.append(keyToFrom, pos | (1L << REVERSE_SHIFT));
+ }
+
+ return addChild(anim);
+ }
+
+ int addStateSet(int[] stateSet, Drawable drawable, int id) {
+ final int index = super.addStateSet(stateSet, drawable);
+ mStateIds.put(index, id);
+ return index;
+ }
+
+ int indexOfKeyframe(int[] stateSet) {
+ final int index = super.indexOfStateSet(stateSet);
+ if (index >= 0) {
+ return index;
+ }
+
+ return super.indexOfStateSet(StateSet.WILD_CARD);
+ }
+
+ int getKeyframeIdAt(int index) {
+ return index < 0 ? 0 : mStateIds.get(index, 0);
+ }
+
+ int indexOfTransition(int fromId, int toId) {
+ final long keyFromTo = generateTransitionKey(fromId, toId);
+ return (int) mTransitions.get(keyFromTo, -1);
+ }
+
+ boolean isTransitionReversed(int fromId, int toId) {
+ final long keyFromTo = generateTransitionKey(fromId, toId);
+ return (mTransitions.get(keyFromTo, -1) >> REVERSE_SHIFT & REVERSE_MASK) == 1;
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new AnimatedStateListDrawable(this, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new AnimatedStateListDrawable(this, res);
+ }
+
+ private static long generateTransitionKey(int fromId, int toId) {
+ return (long) fromId << 32 | toId;
+ }
+ }
+
+ void setConstantState(AnimatedStateListState state) {
+ super.setConstantState(state);
+
+ mState = state;
+ }
+
+ private AnimatedStateListDrawable(AnimatedStateListState state, Resources res) {
+ super(null);
+
+ final AnimatedStateListState newState = new AnimatedStateListState(state, this, res);
+ setConstantState(newState);
+ onStateChange(getState());
+ jumpToCurrentState();
+ }
+
+ /**
+ * Interpolates between frames with respect to their individual durations.
+ */
+ private static class FrameInterpolator implements TimeInterpolator {
+ private int[] mFrameTimes;
+ private int mFrames;
+ private int mTotalDuration;
+
+ public FrameInterpolator(AnimationDrawable d, boolean reversed) {
+ updateFrames(d, reversed);
+ }
+
+ public int updateFrames(AnimationDrawable d, boolean reversed) {
+ final int N = d.getNumberOfFrames();
+ mFrames = N;
+
+ if (mFrameTimes == null || mFrameTimes.length < N) {
+ mFrameTimes = new int[N];
+ }
+
+ final int[] frameTimes = mFrameTimes;
+ int totalDuration = 0;
+ for (int i = 0; i < N; i++) {
+ final int duration = d.getDuration(reversed ? N - i - 1 : i);
+ frameTimes[i] = duration;
+ totalDuration += duration;
+ }
+
+ mTotalDuration = totalDuration;
+ return totalDuration;
+ }
+
+ public int getTotalDuration() {
+ return mTotalDuration;
+ }
+
+ @Override
+ public float getInterpolation(float input) {
+ final int elapsed = (int) (input * mTotalDuration + 0.5f);
+ final int N = mFrames;
+ final int[] frameTimes = mFrameTimes;
+
+ // Find the current frame and remaining time within that frame.
+ int remaining = elapsed;
+ int i = 0;
+ while (i < N && remaining >= frameTimes[i]) {
+ remaining -= frameTimes[i];
+ i++;
+ }
+
+ // Remaining time is relative of total duration.
+ final float frameElapsed;
+ if (i < N) {
+ frameElapsed = remaining / (float) mTotalDuration;
+ } else {
+ frameElapsed = 0;
+ }
+
+ return i / (float) N + frameElapsed;
+ }
+ }
+}
+
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 3f94e26..da4bc10 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -94,7 +94,7 @@
boolean changed = super.setVisible(visible, restart);
if (visible) {
if (changed || restart) {
- setFrame(0, true, true);
+ setFrame(0, true, mCurFrame >= 0);
}
} else {
unscheduleSelf(this);
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index b9d5e19..b939636 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1039,6 +1039,8 @@
final String name = parser.getName();
if (name.equals("selector")) {
drawable = new StateListDrawable();
+ } else if (name.equals("animated-selector")) {
+ drawable = new AnimatedStateListDrawable();
} else if (name.equals("level-list")) {
drawable = new LevelListDrawable();
} else if (name.equals("layer-list")) {
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 1f8b51d..08fc99d 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -359,6 +359,16 @@
mDrawableContainerState.getOpacity();
}
+ /** @hide */
+ public void setCurrentIndex(int index) {
+ selectDrawable(index);
+ }
+
+ /** @hide */
+ public int getCurrentIndex() {
+ return mCurIndex;
+ }
+
public boolean selectDrawable(int idx) {
if (idx == mCurIndex) {
return false;
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 271af2b..f22a063 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -55,8 +55,9 @@
* @attr ref android.R.styleable#DrawableStates_state_pressed
*/
public class StateListDrawable extends DrawableContainer {
+ private static final String TAG = StateListDrawable.class.getSimpleName();
+
private static final boolean DEBUG = false;
- private static final String TAG = "StateListDrawable";
/**
* To be proper, we should have a getter for dither (and alpha, etc.)
@@ -69,7 +70,8 @@
* to improve the quality at negligible cost.
*/
private static final boolean DEFAULT_DITHER = true;
- private final StateListState mStateListState;
+
+ private StateListState mStateListState;
private boolean mMutated;
public StateListDrawable() {
@@ -274,7 +276,7 @@
mStateListState.setLayoutDirection(layoutDirection);
}
- static final class StateListState extends DrawableContainerState {
+ static class StateListState extends DrawableContainerState {
int[][] mStateSets;
StateListState(StateListState orig, StateListDrawable owner, Resources res) {
@@ -293,7 +295,7 @@
return pos;
}
- private int indexOfStateSet(int[] stateSet) {
+ int indexOfStateSet(int[] stateSet) {
final int[][] stateSets = mStateSets;
final int N = getChildCount();
for (int i = 0; i < N; i++) {
@@ -323,11 +325,26 @@
}
}
+ void setConstantState(StateListState state) {
+ super.setConstantState(state);
+
+ mStateListState = state;
+ }
+
private StateListDrawable(StateListState state, Resources res) {
- StateListState as = new StateListState(state, this, res);
- mStateListState = as;
- setConstantState(as);
+ final StateListState newState = new StateListState(state, this, res);
+ setConstantState(newState);
onStateChange(getState());
}
+
+ /**
+ * This constructor exists so subclasses can avoid calling the default
+ * constructor and setting up a StateListDrawable-specific constant state.
+ */
+ StateListDrawable(StateListState state) {
+ if (state != null) {
+ setConstantState(state);
+ }
+ }
}
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index ff4ab98..2da86154 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -46,7 +46,7 @@
* This lets you create a drawable based on an XML vector graphic It can be
* defined in an XML file with the <code><vector></code> element.
* <p/>
- * The vector drawable has 6 elements:
+ * The vector drawable has the following elements:
* <p/>
* <dl>
* <dt><code><vector></code></dt>
@@ -59,15 +59,15 @@
* <dd>Used to defined the size of the virtual canvas the paths are drawn on.
* The size is defined using the attributes <code>android:viewportHeight</code>
* <code>android:viewportWidth</code></dd>
- * <dt><code><group></code></dt>
- * <dd>Defines the static 2D image.</dd>
* <dt><code><path></code></dt>
- * <dd>Defines paths to be drawn. The path elements must be within a group
+ * <dd>Defines paths to be drawn. Multiple paths can be defined in one xml file.
+ * The paths are drawn in the order of their definition order.
* <dl>
* <dt><code>android:name</code>
* <dd>Defines the name of the path.</dd></dt>
* <dt><code>android:pathData</code>
- * <dd>Defines path string.</dd></dt>
+ * <dd>Defines path string. This is using exactly same format as "d" attribute
+ * in the SVG's path data</dd></dt>
* <dt><code>android:fill</code>
* <dd>Defines the color to fill the path (none if not present).</dd></dt>
* <dt><code>android:stroke</code>
@@ -108,7 +108,6 @@
private static final String SHAPE_SIZE = "size";
private static final String SHAPE_VIEWPORT = "viewport";
- private static final String SHAPE_GROUP = "group";
private static final String SHAPE_PATH = "path";
private static final String SHAPE_VECTOR = "vector";
@@ -266,10 +265,9 @@
boolean noSizeTag = true;
boolean noViewportTag = true;
- boolean noGroupTag = true;
boolean noPathTag = true;
- VGroup currentGroup = null;
+ VGroup currentGroup = new VGroup();
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
@@ -286,10 +284,6 @@
} else if (SHAPE_VIEWPORT.equals(tagName)) {
pathRenderer.parseViewport(res, attrs);
noViewportTag = false;
- } else if (SHAPE_GROUP.equals(tagName)) {
- currentGroup = new VGroup();
- pathRenderer.mGroupList.add(currentGroup);
- noGroupTag = false;
} else if (SHAPE_VECTOR.equals(tagName)) {
final TypedArray a = res.obtainAttributes(attrs, R.styleable.VectorDrawable);
@@ -310,7 +304,7 @@
eventType = parser.next();
}
- if (noSizeTag || noViewportTag || noGroupTag || noPathTag) {
+ if (noSizeTag || noViewportTag || noPathTag) {
final StringBuffer tag = new StringBuffer();
if (noSizeTag) {
@@ -324,13 +318,6 @@
tag.append(SHAPE_SIZE);
}
- if (noGroupTag) {
- if (tag.length() > 0) {
- tag.append(" & ");
- }
- tag.append(SHAPE_GROUP);
- }
-
if (noPathTag) {
if (tag.length() > 0) {
tag.append(" or ");
@@ -341,6 +328,7 @@
throw new XmlPullParserException("no " + tag + " defined");
}
+ pathRenderer.mCurrentGroup = currentGroup;
// post parse cleanup
pathRenderer.parseFinish();
return pathRenderer;
@@ -394,7 +382,7 @@
private Paint mFillPaint;
private PathMeasure mPathMeasure;
- final ArrayList<VGroup> mGroupList = new ArrayList<VGroup>();
+ private VGroup mCurrentGroup = new VGroup();
float mBaseWidth = 1;
float mBaseHeight = 1;
@@ -405,7 +393,7 @@
}
public VPathRenderer(VPathRenderer copy) {
- mGroupList.addAll(copy.mGroupList);
+ mCurrentGroup = copy.mCurrentGroup;
if (copy.mCurrentPaths != null) {
mCurrentPaths = new VPath[copy.mCurrentPaths.length];
for (int i = 0; i < mCurrentPaths.length; i++) {
@@ -420,32 +408,24 @@
}
public boolean canApplyTheme() {
- final ArrayList<VGroup> groups = mGroupList;
- for (int i = groups.size() - 1; i >= 0; i--) {
- final ArrayList<VPath> paths = groups.get(i).mVGList;
- for (int j = paths.size() - 1; j >= 0; j--) {
- final VPath path = paths.get(j);
- if (path.canApplyTheme()) {
- return true;
- }
+ final ArrayList<VPath> paths = mCurrentGroup.mVGList;
+ for (int j = paths.size() - 1; j >= 0; j--) {
+ final VPath path = paths.get(j);
+ if (path.canApplyTheme()) {
+ return true;
}
}
-
return false;
}
public void applyTheme(Theme t) {
- final ArrayList<VGroup> groups = mGroupList;
- for (int i = groups.size() - 1; i >= 0; i--) {
- final ArrayList<VPath> paths = groups.get(i).mVGList;
- for (int j = paths.size() - 1; j >= 0; j--) {
- final VPath path = paths.get(j);
- if (path.canApplyTheme()) {
- path.applyTheme(t);
- }
+ final ArrayList<VPath> paths = mCurrentGroup.mVGList;
+ for (int j = paths.size() - 1; j >= 0; j--) {
+ final VPath path = paths.get(j);
+ if (path.canApplyTheme()) {
+ path.applyTheme(t);
}
}
-
}
public void draw(Canvas canvas, int w, int h) {
@@ -537,11 +517,11 @@
}
/**
- * Build the "current" path based on the first group
+ * Build the "current" path based on the current group
* TODO: improve memory use & performance or move to C++
*/
public void parseFinish() {
- final Collection<VPath> paths = mGroupList.get(0).getPaths();
+ final Collection<VPath> paths = mCurrentGroup.getPaths();
mCurrentPaths = paths.toArray(new VPath[paths.size()]);
for (int i = 0; i < mCurrentPaths.length; i++) {
mCurrentPaths[i] = new VPath(mCurrentPaths[i]);
diff --git a/graphics/java/android/graphics/pdf/PdfDocument.java b/graphics/java/android/graphics/pdf/PdfDocument.java
index f5b07c1..d603436 100644
--- a/graphics/java/android/graphics/pdf/PdfDocument.java
+++ b/graphics/java/android/graphics/pdf/PdfDocument.java
@@ -32,7 +32,7 @@
/**
* <p>
* This class enables generating a PDF document from native Android content. You
- * open a new document and then for every page you want to add you start a page,
+ * create a new document and then for every page you want to add you start a page,
* write content to the page, and finish the page. After you are done with all
* pages, you write the document to an output stream and close the document.
* After a document is closed you should not use it anymore. Note that pages are
@@ -64,7 +64,7 @@
* // write the document content
* document.writeTo(getOutputStream());
*
- * //close the document
+ * // close the document
* document.close();
* </pre>
*/
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
new file mode 100644
index 0000000..3fa3b9f
--- /dev/null
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.pdf;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.OsConstants;
+import dalvik.system.CloseGuard;
+import libcore.io.Libcore;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * <p>
+ * This class enables rendering a PDF document. This class is not thread safe.
+ * </p>
+ * <p>
+ * If you want to render a PDF, you create a renderer and for every page you want
+ * to render, you open the page, render it, and close the page. After you are done
+ * with rendering, you close the renderer. After the renderer is closed it should not
+ * be used anymore. Note that the pages are rendered one by one, i.e. you can have
+ * only a single page opened at any given time.
+ * </p>
+ * <p>
+ * A typical use of the APIs to render a PDF looks like this:
+ * </p>
+ * <pre>
+ * // create a new renderer
+ * PdfRenderer renderer = new PdfRenderer(getSeekableFileDescriptor());
+ *
+ * // let us just render all pages
+ * final int pageCount = renderer.getPageCount();
+ * for (int i = 0; i < pageCount; i++) {
+ * Page page = renderer.openPage(i);
+ * Bitmap bitmap = getBitmapReuseIfPossible(page);
+ *
+ * // say we render for showing on the screen
+ * page.render(bitmap, getContentBoundsInBitmap(),
+ * getDesiredTransformation(), Page.RENDER_MODE_FOR_DISPLAY);
+ *
+ * // do stuff with the bitmap
+ *
+ * renderer.closePage(page);
+ * }
+ *
+ * // close the renderer
+ * renderer.close();
+ * </pre>
+ *
+ * @see #close()
+ */
+public final class PdfRenderer implements AutoCloseable {
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ private final Point mTempPoint = new Point();
+
+ private final long mNativeDocument;
+
+ private final int mPageCount;
+
+ private ParcelFileDescriptor mInput;
+
+ private Page mCurrentPage;
+
+ /** @hide */
+ @IntDef({
+ Page.RENDER_MODE_FOR_DISPLAY,
+ Page.RENDER_MODE_FOR_PRINT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RenderMode {}
+
+ /**
+ * Creates a new instance.
+ * <p>
+ * <strong>Note:</strong> The provided file descriptor must be <strong>seekable</strong>,
+ * i.e. its data being randomly accessed, e.g. pointing to a file.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> This class takes ownership of the passed in file descriptor
+ * and is responsible for closing it when the renderer is closed.
+ * </p>
+ *
+ * @param input Seekable file descriptor to read from.
+ */
+ public PdfRenderer(@NonNull ParcelFileDescriptor input) throws IOException {
+ if (input == null) {
+ throw new NullPointerException("input cannot be null");
+ }
+
+ final long size;
+ try {
+ Libcore.os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET);
+ size = Libcore.os.fstat(input.getFileDescriptor()).st_size;
+ } catch (ErrnoException ee) {
+ throw new IllegalArgumentException("file descriptor not seekable");
+ }
+
+ mInput = input;
+ mNativeDocument = nativeCreate(mInput.getFd(), size);
+ mPageCount = nativeGetPageCount(mNativeDocument);
+ mCloseGuard.open("close");
+ }
+
+ /**
+ * Closes this renderer. You should not use this instance
+ * after this method is called.
+ */
+ public void close() {
+ throwIfClosed();
+ throwIfPageOpened();
+ doClose();
+ }
+
+ /**
+ * Gets the number of pages in the document.
+ *
+ * @return The page count.
+ */
+ public int getPageCount() {
+ throwIfClosed();
+ return mPageCount;
+ }
+
+ /**
+ * Gets whether the document prefers to be scaled for printing.
+ * You should take this info account if the document is rendered
+ * for printing and the target media size differs from the page
+ * size.
+ *
+ * @return If to scale the document.
+ */
+ public boolean shouldScaleForPrinting() {
+ throwIfClosed();
+ return nativeScaleForPrinting(mNativeDocument);
+ }
+
+ /**
+ * Opens a page for rendering.
+ *
+ * @param index The page index.
+ * @return A page that can be rendered.
+ *
+ * @see #closePage(PdfRenderer.Page)
+ */
+ public Page openPage(int index) {
+ throwIfClosed();
+ throwIfPageOpened();
+ mCurrentPage = new Page(index);
+ return mCurrentPage;
+ }
+
+ /**
+ * Closes a page opened for rendering.
+ *
+ * @param page The page to close.
+ *
+ * @see #openPage(int)
+ */
+ public void closePage(@NonNull Page page) {
+ throwIfClosed();
+ throwIfNotCurrentPage(page);
+ throwIfCurrentPageClosed();
+ mCurrentPage.close();
+ mCurrentPage = null;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ mCloseGuard.warnIfOpen();
+ if (mInput != null) {
+ doClose();
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private void doClose() {
+ if (mCurrentPage != null) {
+ mCurrentPage.close();
+ mCurrentPage = null;
+ }
+ nativeClose(mNativeDocument);
+ try {
+ mInput.close();
+ } catch (IOException ioe) {
+ /* ignore - best effort */
+ }
+ mInput = null;
+ mCloseGuard.close();
+ }
+
+ private void throwIfClosed() {
+ if (mInput == null) {
+ throw new IllegalStateException("Already closed");
+ }
+ }
+
+ private void throwIfPageOpened() {
+ if (mCurrentPage != null) {
+ throw new IllegalStateException("Current page not closed");
+ }
+ }
+
+ private void throwIfCurrentPageClosed() {
+ if (mCurrentPage == null) {
+ throw new IllegalStateException("Already closed");
+ }
+ }
+
+ private void throwIfNotCurrentPage(Page page) {
+ if (page != mCurrentPage) {
+ throw new IllegalArgumentException("Page not from document");
+ }
+ }
+
+ /**
+ * This class represents a PDF document page for rendering.
+ */
+ public final class Page {
+
+ /**
+ * Mode to render the content for display on a screen.
+ */
+ public static final int RENDER_MODE_FOR_DISPLAY = 1;
+
+ /**
+ * Mode to render the content for printing.
+ */
+ public static final int RENDER_MODE_FOR_PRINT = 2;
+
+ private final int mIndex;
+ private final int mWidth;
+ private final int mHeight;
+
+ private long mNativePage;
+
+ private Page(int index) {
+ Point size = mTempPoint;
+ mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size);
+ mIndex = index;
+ mWidth = size.x;
+ mHeight = size.y;
+ }
+
+ /**
+ * Gets the page index.
+ *
+ * @return The index.
+ */
+ public int getIndex() {
+ return mIndex;
+ }
+
+ /**
+ * Gets the page width in points (1/72").
+ *
+ * @return The width in points.
+ */
+ public int getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * Gets the page height in points (1/72").
+ *
+ * @return The height in points.
+ */
+ public int getHeight() {
+ return mHeight;
+ }
+
+ /**
+ * Renders a page to a bitmap.
+ * <p>
+ * You may optionally specify a rectangular clip in the bitmap bounds. No rendering
+ * outside the clip will be performed, hence it is your responsibility to initialize
+ * the bitmap outside the clip.
+ * </p>
+ * <p>
+ * You may optionally specify a matrix to transform the content from page coordinates
+ * which are in points (1/72") to bitmap coordintates which are in pixels. If this
+ * matrix is not provided this method will apply a transformation that will fit the
+ * whole page to the destination clip if profided or the destination bitmap if no
+ * clip is provided.
+ * </p>
+ * <p>
+ * The clip and transformation are useful for implementing tile rendering where the
+ * destination bitmap contains a portion of the image, for example when zooming.
+ * Another useful application is for printing where the size of the bitmap holding
+ * the page is too large and a client can render the page in stripes.
+ * </p>
+ * <p>
+ * <strong>Note: </strong> The destination bitmap format must be
+ * {@link Config#ARGB_8888 ARGB}.
+ * </p>
+ * <p>
+ * <strong>Note: </strong> The optional transformation matrix must be affine as per
+ * {@link android.graphics.Matrix#isAffine()}. Hence, you can specify rotation, scaling,
+ * translation but not a perspective transformation.
+ * </p>
+ *
+ * @param destination Destination bitmap to which to render.
+ * @param destClip Optional clip in the bitmap bounds.
+ * @param transform Optional transformation to apply when rendering.
+ * @param renderMode The render mode.
+ *
+ * @see #RENDER_MODE_FOR_DISPLAY
+ * @see #RENDER_MODE_FOR_PRINT
+ */
+ public void render(@NonNull Bitmap destination, @Nullable Rect destClip,
+ @Nullable Matrix transform, @RenderMode int renderMode) {
+ if (destination.getConfig() != Config.ARGB_8888) {
+ throw new IllegalArgumentException("Unsupported pixel format");
+ }
+
+ if (destClip != null) {
+ if (destClip.left < 0 || destClip.top < 0
+ || destClip.right > destination.getWidth()
+ || destClip.bottom > destination.getHeight()) {
+ throw new IllegalArgumentException("destBounds not in destination");
+ }
+ }
+
+ if (transform != null && !transform.isAffine()) {
+ throw new IllegalArgumentException("transform not affine");
+ }
+
+ if (renderMode != RENDER_MODE_FOR_PRINT && renderMode != RENDER_MODE_FOR_DISPLAY) {
+ throw new IllegalArgumentException("Unsupported render mode");
+ }
+
+ if (renderMode == RENDER_MODE_FOR_PRINT && renderMode == RENDER_MODE_FOR_DISPLAY) {
+ throw new IllegalArgumentException("Only single render mode supported");
+ }
+
+ final int contentLeft = (destClip != null) ? destClip.left : 0;
+ final int contentTop = (destClip != null) ? destClip.top : 0;
+ final int contentRight = (destClip != null) ? destClip.right
+ : destination.getWidth();
+ final int contentBottom = (destClip != null) ? destClip.bottom
+ : destination.getHeight();
+
+ final long transformPtr = (transform != null) ? transform.native_instance : 0;
+
+ nativeRenderPage(mNativeDocument, mNativePage, destination.mNativeBitmap, contentLeft,
+ contentTop, contentRight, contentBottom, transformPtr, renderMode);
+ }
+
+ void close() {
+ nativeClosePage(mNativePage);
+ mNativePage = 0;
+ }
+ }
+
+ private static native long nativeCreate(int fd, long size);
+ private static native void nativeClose(long documentPtr);
+ private static native int nativeGetPageCount(long documentPtr);
+ private static native boolean nativeScaleForPrinting(long documentPtr);
+ private static native void nativeRenderPage(long documentPtr, long pagePtr, long destPtr,
+ int destLeft, int destTop, int destRight, int destBottom, long matrixPtr, int renderMode);
+ private static native long nativeOpenPageAndGetSize(long documentPtr, int pageIndex,
+ Point outSize);
+ private static native void nativeClosePage(long pagePtr);
+}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 098753b..7d4da01 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -102,7 +102,7 @@
if (headerSize >= minSize) {
if (headerSize <= size) {
if (((headerSize|size)&0x3) == 0) {
- if ((ssize_t)size <= (dataEnd-((const uint8_t*)chunk))) {
+ if ((size_t)size <= (size_t)(dataEnd-((const uint8_t*)chunk))) {
return NO_ERROR;
}
ALOGW("%s data size 0x%x extends beyond resource end %p.",
@@ -2452,15 +2452,19 @@
if (mcc != 0) {
if (res.size() > 0) res.append("-");
- res.appendFormat("%dmcc", dtohs(mcc));
+ res.appendFormat("mcc%d", dtohs(mcc));
}
if (mnc != 0) {
if (res.size() > 0) res.append("-");
- res.appendFormat("%dmnc", dtohs(mnc));
+ res.appendFormat("mnc%d", dtohs(mnc));
}
+
char localeStr[RESTABLE_MAX_LOCALE_LEN];
getBcp47Locale(localeStr);
- res.append(localeStr);
+ if (strlen(localeStr) > 0) {
+ if (res.size() > 0) res.append("-");
+ res.append(localeStr);
+ }
if ((screenLayout&MASK_LAYOUTDIR) != 0) {
if (res.size() > 0) res.append("-");
@@ -2627,6 +2631,20 @@
break;
}
}
+ if ((inputFlags&MASK_KEYSHIDDEN) != 0) {
+ if (res.size() > 0) res.append("-");
+ switch (inputFlags&MASK_KEYSHIDDEN) {
+ case ResTable_config::KEYSHIDDEN_NO:
+ res.append("keysexposed");
+ break;
+ case ResTable_config::KEYSHIDDEN_YES:
+ res.append("keyshidden");
+ break;
+ case ResTable_config::KEYSHIDDEN_SOFT:
+ res.append("keyssoft");
+ break;
+ }
+ }
if (keyboard != KEYBOARD_ANY) {
if (res.size() > 0) res.append("-");
switch (keyboard) {
@@ -2644,17 +2662,18 @@
break;
}
}
- if ((inputFlags&MASK_KEYSHIDDEN) != 0) {
+ if ((inputFlags&MASK_NAVHIDDEN) != 0) {
if (res.size() > 0) res.append("-");
- switch (inputFlags&MASK_KEYSHIDDEN) {
- case ResTable_config::KEYSHIDDEN_NO:
- res.append("keysexposed");
+ switch (inputFlags&MASK_NAVHIDDEN) {
+ case ResTable_config::NAVHIDDEN_NO:
+ res.append("navexposed");
break;
- case ResTable_config::KEYSHIDDEN_YES:
- res.append("keyshidden");
+ case ResTable_config::NAVHIDDEN_YES:
+ res.append("navhidden");
break;
- case ResTable_config::KEYSHIDDEN_SOFT:
- res.append("keyssoft");
+ default:
+ res.appendFormat("inputFlagsNavHidden=%d",
+ dtohs(inputFlags&MASK_NAVHIDDEN));
break;
}
}
@@ -2678,21 +2697,6 @@
break;
}
}
- if ((inputFlags&MASK_NAVHIDDEN) != 0) {
- if (res.size() > 0) res.append("-");
- switch (inputFlags&MASK_NAVHIDDEN) {
- case ResTable_config::NAVHIDDEN_NO:
- res.append("navsexposed");
- break;
- case ResTable_config::NAVHIDDEN_YES:
- res.append("navhidden");
- break;
- default:
- res.appendFormat("inputFlagsNavHidden=%d",
- dtohs(inputFlags&MASK_NAVHIDDEN));
- break;
- }
- }
if (screenSize != 0) {
if (res.size() > 0) res.append("-");
res.appendFormat("%dx%d", dtohs(screenWidth), dtohs(screenHeight));
@@ -5503,7 +5507,25 @@
if (package == NULL) {
return (mError=NO_MEMORY);
}
-
+
+ if (idmap_id == 0) {
+ err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
+ header->dataEnd-(base+dtohl(pkg->typeStrings)));
+ if (err != NO_ERROR) {
+ delete group;
+ delete package;
+ return (mError=err);
+ }
+
+ err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
+ header->dataEnd-(base+dtohl(pkg->keyStrings)));
+ if (err != NO_ERROR) {
+ delete group;
+ delete package;
+ return (mError=err);
+ }
+ }
+
if (id == 0) {
// This is a library so assign an ID
id = mNextPackageId++;
@@ -5521,21 +5543,6 @@
return (mError=NO_MEMORY);
}
- err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
- header->dataEnd-(base+dtohl(pkg->typeStrings)));
- if (err != NO_ERROR) {
- delete group;
- delete package;
- return (mError=err);
- }
- err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
- header->dataEnd-(base+dtohl(pkg->keyStrings)));
- if (err != NO_ERROR) {
- delete group;
- delete package;
- return (mError=err);
- }
-
//printf("Adding new package id %d at index %d\n", id, idx);
err = mPackageGroups.add(group);
if (err < NO_ERROR) {
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 6a3003e..83eedfb 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -27,31 +27,48 @@
namespace uirenderer {
/************************************************************
- * Base animator
+ * BaseRenderNodeAnimator
************************************************************/
-BaseAnimator::BaseAnimator()
- : mInterpolator(0)
- , mPlayState(PENDING)
+BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
+ : mFinalValue(finalValue)
+ , mDeltaValue(0)
+ , mFromValue(0)
+ , mInterpolator(0)
+ , mPlayState(NEEDS_START)
, mStartTime(0)
- , mDuration(300) {
-
+ , mDuration(300){
}
-BaseAnimator::~BaseAnimator() {
+BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
setInterpolator(NULL);
}
-void BaseAnimator::setInterpolator(Interpolator* interpolator) {
+void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
delete mInterpolator;
mInterpolator = interpolator;
}
-void BaseAnimator::setDuration(nsecs_t duration) {
+void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
mDuration = duration;
}
-bool BaseAnimator::animateFrame(TreeInfo& info) {
+void BaseRenderNodeAnimator::setStartValue(float value) {
+ LOG_ALWAYS_FATAL_IF(mPlayState != NEEDS_START,
+ "Cannot set the start value after the animator has started!");
+ mFromValue = value;
+ mDeltaValue = (mFinalValue - mFromValue);
+ mPlayState = PENDING;
+}
+
+void BaseRenderNodeAnimator::setupStartValueIfNecessary(RenderNode* target, TreeInfo& info) {
+ if (mPlayState == NEEDS_START) {
+ setStartValue(getValue(target));
+ mPlayState = PENDING;
+ }
+}
+
+bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
if (mPlayState == PENDING) {
mPlayState = RUNNING;
mStartTime = info.frameTimeMs;
@@ -59,7 +76,6 @@
if (!mInterpolator) {
setInterpolator(Interpolator::createDefaultInterpolator());
}
- onAnimationStarted();
}
float fraction = 1.0f;
@@ -71,17 +87,16 @@
}
}
fraction = mInterpolator->interpolate(fraction);
- onAnimationUpdated(fraction);
+ setValue(target, mFromValue + (mDeltaValue * fraction));
if (mPlayState == FINISHED) {
- onAnimationFinished();
callOnFinishedListener(info);
return true;
}
return false;
}
-void BaseAnimator::callOnFinishedListener(TreeInfo& info) {
+void BaseRenderNodeAnimator::callOnFinishedListener(TreeInfo& info) {
if (mListener.get()) {
if (!info.animationHook) {
mListener->onAnimationFinished(this);
@@ -92,70 +107,49 @@
}
/************************************************************
- * BaseRenderNodeAnimator
- ************************************************************/
-
-BaseRenderNodeAnimator::BaseRenderNodeAnimator(
- BaseRenderNodeAnimator::DeltaValueType deltaType, float delta)
- : mTarget(0)
- , mDeltaValueType(deltaType)
- , mDeltaValue(delta)
- , mFromValue(-1) {
-}
-
-bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
- mTarget = target;
- bool finished = animateFrame(info);
- mTarget = NULL;
- return finished;
-}
-
-void BaseRenderNodeAnimator::onAnimationStarted() {
- mFromValue = getValue();
-
- if (mDeltaValueType == BaseRenderNodeAnimator::ABSOLUTE) {
- mDeltaValue = (mDeltaValue - mFromValue);
- mDeltaValueType = BaseRenderNodeAnimator::DELTA;
- }
-}
-
-void BaseRenderNodeAnimator::onAnimationUpdated(float fraction) {
- float value = mFromValue + (mDeltaValue * fraction);
- setValue(value);
-}
-
-/************************************************************
* RenderPropertyAnimator
************************************************************/
-// Maps RenderProperty enum to accessors
-const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = {
- {&RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
- {&RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
- {&RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
- {&RenderProperties::getScaleX, &RenderProperties::setScaleX },
- {&RenderProperties::getScaleY, &RenderProperties::setScaleY },
- {&RenderProperties::getRotation, &RenderProperties::setRotation },
- {&RenderProperties::getRotationX, &RenderProperties::setRotationX },
- {&RenderProperties::getRotationY, &RenderProperties::setRotationY },
- {&RenderProperties::getX, &RenderProperties::setX },
- {&RenderProperties::getY, &RenderProperties::setY },
- {&RenderProperties::getZ, &RenderProperties::setZ },
- {&RenderProperties::getAlpha, &RenderProperties::setAlpha },
+struct RenderPropertyAnimator::PropertyAccessors {
+ RenderNode::DirtyPropertyMask dirtyMask;
+ GetFloatProperty getter;
+ SetFloatProperty setter;
};
-RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property,
- DeltaValueType deltaType, float deltaValue)
- : BaseRenderNodeAnimator(deltaType, deltaValue)
- , mPropertyAccess(PROPERTY_ACCESSOR_LUT[property]) {
+// Maps RenderProperty enum to accessors
+const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = {
+ {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
+ {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
+ {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
+ {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX },
+ {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY },
+ {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation },
+ {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX },
+ {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY },
+ {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX },
+ {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY },
+ {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ },
+ {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha },
+};
+
+RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue)
+ : BaseRenderNodeAnimator(finalValue)
+ , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {
}
-float RenderPropertyAnimator::getValue() const {
- return (target()->animatorProperties().*mPropertyAccess.getter)();
+void RenderPropertyAnimator::onAttached(RenderNode* target) {
+ if (target->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
+ setStartValue((target->stagingProperties().*mPropertyAccess->getter)());
+ }
+ (target->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
}
-void RenderPropertyAnimator::setValue(float value) {
- (target()->animatorProperties().*mPropertyAccess.setter)(value);
+float RenderPropertyAnimator::getValue(RenderNode* target) const {
+ return (target->properties().*mPropertyAccess->getter)();
+}
+
+void RenderPropertyAnimator::setValue(RenderNode* target, float value) {
+ (target->animatorProperties().*mPropertyAccess->setter)(value);
}
/************************************************************
@@ -163,16 +157,16 @@
************************************************************/
CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(
- CanvasPropertyPrimitive* property, DeltaValueType deltaType, float deltaValue)
- : BaseRenderNodeAnimator(deltaType, deltaValue)
+ CanvasPropertyPrimitive* property, float finalValue)
+ : BaseRenderNodeAnimator(finalValue)
, mProperty(property) {
}
-float CanvasPropertyPrimitiveAnimator::getValue() const {
+float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const {
return mProperty->value;
}
-void CanvasPropertyPrimitiveAnimator::setValue(float value) {
+void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) {
mProperty->value = value;
}
@@ -181,14 +175,13 @@
************************************************************/
CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
- CanvasPropertyPaint* property, PaintField field,
- DeltaValueType deltaType, float deltaValue)
- : BaseRenderNodeAnimator(deltaType, deltaValue)
+ CanvasPropertyPaint* property, PaintField field, float finalValue)
+ : BaseRenderNodeAnimator(finalValue)
, mProperty(property)
, mField(field) {
}
-float CanvasPropertyPaintAnimator::getValue() const {
+float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const {
switch (mField) {
case STROKE_WIDTH:
return mProperty->value.getStrokeWidth();
@@ -199,13 +192,18 @@
return -1;
}
-void CanvasPropertyPaintAnimator::setValue(float value) {
+static uint8_t to_uint8(float value) {
+ int c = (int) (value + .5f);
+ return static_cast<uint8_t>( c < 0 ? 0 : c > 255 ? 255 : c );
+}
+
+void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) {
switch (mField) {
case STROKE_WIDTH:
mProperty->value.setStrokeWidth(value);
return;
case ALPHA:
- mProperty->value.setAlpha(value);
+ mProperty->value.setAlpha(to_uint8(value));
return;
}
LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index 0b074cc..fe88cbf 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -17,13 +17,13 @@
#define ANIMATOR_H
#include <cutils/compiler.h>
+#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
#include "CanvasProperty.h"
#include "Interpolator.h"
#include "TreeInfo.h"
#include "utils/Macros.h"
-#include "utils/VirtualLightRefBase.h"
namespace android {
namespace uirenderer {
@@ -33,47 +33,53 @@
class AnimationListener : public VirtualLightRefBase {
public:
- ANDROID_API virtual void onAnimationFinished(BaseAnimator*) = 0;
+ ANDROID_API virtual void onAnimationFinished(BaseRenderNodeAnimator*) = 0;
protected:
ANDROID_API virtual ~AnimationListener() {}
};
-// Helper class to contain generic animator helpers
-class BaseAnimator : public VirtualLightRefBase {
- PREVENT_COPY_AND_ASSIGN(BaseAnimator);
+class BaseRenderNodeAnimator : public VirtualLightRefBase {
+ PREVENT_COPY_AND_ASSIGN(BaseRenderNodeAnimator);
public:
-
ANDROID_API void setInterpolator(Interpolator* interpolator);
ANDROID_API void setDuration(nsecs_t durationInMs);
+ ANDROID_API nsecs_t duration() { return mDuration; }
ANDROID_API void setListener(AnimationListener* listener) {
mListener = listener;
}
+ ANDROID_API virtual void onAttached(RenderNode* target) {}
+
+ // Guaranteed to happen before the staging push
+ void setupStartValueIfNecessary(RenderNode* target, TreeInfo& info);
+
+ bool animate(RenderNode* target, TreeInfo& info);
+
bool isFinished() { return mPlayState == FINISHED; }
+ float finalValue() { return mFinalValue; }
protected:
- BaseAnimator();
- virtual ~BaseAnimator();
+ BaseRenderNodeAnimator(float finalValue);
+ virtual ~BaseRenderNodeAnimator();
- // This is the main animation entrypoint that subclasses should call
- // to generate the onAnimation* lifecycle events
- // Returns true if the animation has finished, false otherwise
- bool animateFrame(TreeInfo& info);
-
- // Called when PlayState switches from PENDING to RUNNING
- virtual void onAnimationStarted() {}
- virtual void onAnimationUpdated(float fraction) = 0;
- virtual void onAnimationFinished() {}
+ void setStartValue(float value);
+ virtual float getValue(RenderNode* target) const = 0;
+ virtual void setValue(RenderNode* target, float value) = 0;
private:
void callOnFinishedListener(TreeInfo& info);
enum PlayState {
+ NEEDS_START,
PENDING,
RUNNING,
FINISHED,
};
+ float mFinalValue;
+ float mDeltaValue;
+ float mFromValue;
+
Interpolator* mInterpolator;
PlayState mPlayState;
long mStartTime;
@@ -82,42 +88,6 @@
sp<AnimationListener> mListener;
};
-class BaseRenderNodeAnimator : public BaseAnimator {
-public:
- // Since the UI thread doesn't necessarily know what the current values
- // actually are and thus can't do the calculations, this is used to inform
- // the animator how to lazy-resolve the input value
- enum DeltaValueType {
- // The delta value represents an absolute value endpoint
- // mDeltaValue needs to be recalculated to be mDelta = (mDelta - fromValue)
- // in onAnimationStarted()
- ABSOLUTE = 0,
- // The final value represents an offset from the current value
- // No recalculation is needed
- DELTA,
- };
-
- bool animate(RenderNode* target, TreeInfo& info);
-
-protected:
- BaseRenderNodeAnimator(DeltaValueType deltaType, float deltaValue);
-
- RenderNode* target() const { return mTarget; }
- virtual float getValue() const = 0;
- virtual void setValue(float value) = 0;
-
-private:
- virtual void onAnimationStarted();
- virtual void onAnimationUpdated(float fraction);
-
- // mTarget is only valid inside animate()
- RenderNode* mTarget;
-
- BaseRenderNodeAnimator::DeltaValueType mDeltaValueType;
- float mDeltaValue;
- float mFromValue;
-};
-
class RenderPropertyAnimator : public BaseRenderNodeAnimator {
public:
enum RenderProperty {
@@ -135,23 +105,20 @@
ALPHA,
};
- ANDROID_API RenderPropertyAnimator(RenderProperty property,
- DeltaValueType deltaType, float deltaValue);
+ ANDROID_API RenderPropertyAnimator(RenderProperty property, float finalValue);
+
+ ANDROID_API virtual void onAttached(RenderNode* target);
protected:
- ANDROID_API virtual float getValue() const;
- ANDROID_API virtual void setValue(float value);
+ virtual float getValue(RenderNode* target) const;
+ virtual void setValue(RenderNode* target, float value);
private:
typedef void (RenderProperties::*SetFloatProperty)(float value);
typedef float (RenderProperties::*GetFloatProperty)() const;
- struct PropertyAccessors {
- GetFloatProperty getter;
- SetFloatProperty setter;
- };
-
- PropertyAccessors mPropertyAccess;
+ struct PropertyAccessors;
+ const PropertyAccessors* mPropertyAccess;
static const PropertyAccessors PROPERTY_ACCESSOR_LUT[];
};
@@ -159,10 +126,10 @@
class CanvasPropertyPrimitiveAnimator : public BaseRenderNodeAnimator {
public:
ANDROID_API CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
- DeltaValueType deltaType, float deltaValue);
+ float finalValue);
protected:
- ANDROID_API virtual float getValue() const;
- ANDROID_API virtual void setValue(float value);
+ virtual float getValue(RenderNode* target) const;
+ virtual void setValue(RenderNode* target, float value);
private:
sp<CanvasPropertyPrimitive> mProperty;
};
@@ -175,10 +142,10 @@
};
ANDROID_API CanvasPropertyPaintAnimator(CanvasPropertyPaint* property,
- PaintField field, DeltaValueType deltaType, float deltaValue);
+ PaintField field, float finalValue);
protected:
- ANDROID_API virtual float getValue() const;
- ANDROID_API virtual void setValue(float value);
+ virtual float getValue(RenderNode* target) const;
+ virtual void setValue(RenderNode* target, float value);
private:
sp<CanvasPropertyPaint> mProperty;
PaintField mField;
diff --git a/libs/hwui/CanvasProperty.h b/libs/hwui/CanvasProperty.h
index 2e1d176..6074394 100644
--- a/libs/hwui/CanvasProperty.h
+++ b/libs/hwui/CanvasProperty.h
@@ -16,8 +16,9 @@
#ifndef CANVASPROPERTY_H
#define CANVASPROPERTY_H
+#include <utils/RefBase.h>
+
#include "utils/Macros.h"
-#include "utils/VirtualLightRefBase.h"
#include <SkPaint.h>
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index eaeb772..b2ead5b 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -41,7 +41,6 @@
#include "Matrix.h"
#include "DeferredDisplayList.h"
#include "RenderProperties.h"
-#include "utils/VirtualLightRefBase.h"
class SkBitmap;
class SkPaint;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index c2ce6ed..a4bce3a 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -57,9 +57,6 @@
}
void DisplayListRenderer::setViewport(int width, int height) {
- // TODO: DisplayListRenderer shouldn't have a projection matrix, as it should never be used
- mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1);
-
initializeViewport(width, height);
}
diff --git a/libs/hwui/Interpolator.cpp b/libs/hwui/Interpolator.cpp
index 004ddf5..1f84b86 100644
--- a/libs/hwui/Interpolator.cpp
+++ b/libs/hwui/Interpolator.cpp
@@ -13,9 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+#define LOG_TAG "Interpolator"
+
#include "Interpolator.h"
-#include <math.h>
+#include <cmath>
+#include <cutils/log.h>
+
+#include "utils/MathUtils.h"
namespace android {
namespace uirenderer {
@@ -28,5 +34,90 @@
return (float)(cosf((input + 1) * M_PI) / 2.0f) + 0.5f;
}
+float AccelerateInterpolator::interpolate(float input) {
+ if (mFactor == 1.0f) {
+ return input * input;
+ } else {
+ return pow(input, mDoubleFactor);
+ }
+}
+
+float AnticipateInterpolator::interpolate(float t) {
+ return t * t * ((mTension + 1) * t - mTension);
+}
+
+static float a(float t, float s) {
+ return t * t * ((s + 1) * t - s);
+}
+
+static float o(float t, float s) {
+ return t * t * ((s + 1) * t + s);
+}
+
+float AnticipateOvershootInterpolator::interpolate(float t) {
+ if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension);
+ else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);
+}
+
+static float bounce(float t) {
+ return t * t * 8.0f;
+}
+
+float BounceInterpolator::interpolate(float t) {
+ t *= 1.1226f;
+ if (t < 0.3535f) return bounce(t);
+ else if (t < 0.7408f) return bounce(t - 0.54719f) + 0.7f;
+ else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f;
+ else return bounce(t - 1.0435f) + 0.95f;
+}
+
+float CycleInterpolator::interpolate(float input) {
+ return sinf(2 * mCycles * M_PI * input);
+}
+
+float DecelerateInterpolator::interpolate(float input) {
+ float result;
+ if (mFactor == 1.0f) {
+ result = 1.0f - (1.0f - input) * (1.0f - input);
+ } else {
+ result = 1.0f - pow((1.0f - input), 2 * mFactor);
+ }
+ return result;
+}
+
+float OvershootInterpolator::interpolate(float t) {
+ t -= 1.0f;
+ return t * t * ((mTension + 1) * t + mTension) + 1.0f;
+}
+
+LUTInterpolator::LUTInterpolator(float* values, size_t size) {
+ mValues = values;
+ mSize = size;
+}
+
+LUTInterpolator::~LUTInterpolator() {
+ delete mValues;
+ mValues = 0;
+}
+
+float LUTInterpolator::interpolate(float input) {
+ float lutpos = input * mSize;
+ if (lutpos >= (mSize - 1)) {
+ return mValues[mSize - 1];
+ }
+
+ float ipart, weight;
+ weight = modff(lutpos, &ipart);
+
+ int i1 = (int) ipart;
+ int i2 = MathUtils::min(i1 + 1, mSize - 1);
+
+ float v1 = mValues[i1];
+ float v2 = mValues[i2];
+
+ return MathUtils::lerp(v1, v2, weight);
+}
+
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/Interpolator.h b/libs/hwui/Interpolator.h
index 2cfb60c..dfa0a85 100644
--- a/libs/hwui/Interpolator.h
+++ b/libs/hwui/Interpolator.h
@@ -16,6 +16,10 @@
#ifndef INTERPOLATOR_H
#define INTERPOLATOR_H
+#include <stddef.h>
+
+#include <cutils/compiler.h>
+
namespace android {
namespace uirenderer {
@@ -31,12 +35,80 @@
Interpolator() {}
};
-class AccelerateDecelerateInterpolator : public Interpolator {
+class ANDROID_API AccelerateDecelerateInterpolator : public Interpolator {
public:
- AccelerateDecelerateInterpolator() {}
- virtual ~AccelerateDecelerateInterpolator() {}
+ virtual float interpolate(float input);
+};
+
+class ANDROID_API AccelerateInterpolator : public Interpolator {
+public:
+ AccelerateInterpolator(float factor) : mFactor(factor), mDoubleFactor(factor*2) {}
+ virtual float interpolate(float input);
+private:
+ const float mFactor;
+ const float mDoubleFactor;
+};
+
+class ANDROID_API AnticipateInterpolator : public Interpolator {
+public:
+ AnticipateInterpolator(float tension) : mTension(tension) {}
+ virtual float interpolate(float input);
+private:
+ const float mTension;
+};
+
+class ANDROID_API AnticipateOvershootInterpolator : public Interpolator {
+public:
+ AnticipateOvershootInterpolator(float tension) : mTension(tension) {}
+ virtual float interpolate(float input);
+private:
+ const float mTension;
+};
+
+class ANDROID_API BounceInterpolator : public Interpolator {
+public:
+ virtual float interpolate(float input);
+};
+
+class ANDROID_API CycleInterpolator : public Interpolator {
+public:
+ CycleInterpolator(float cycles) : mCycles(cycles) {}
+ virtual float interpolate(float input);
+private:
+ const float mCycles;
+};
+
+class ANDROID_API DecelerateInterpolator : public Interpolator {
+public:
+ DecelerateInterpolator(float factor) : mFactor(factor) {}
+ virtual float interpolate(float input);
+private:
+ const float mFactor;
+};
+
+class ANDROID_API LinearInterpolator : public Interpolator {
+public:
+ virtual float interpolate(float input) { return input; }
+};
+
+class ANDROID_API OvershootInterpolator : public Interpolator {
+public:
+ OvershootInterpolator(float tension) : mTension(tension) {}
+ virtual float interpolate(float input);
+private:
+ const float mTension;
+};
+
+class ANDROID_API LUTInterpolator : public Interpolator {
+public:
+ LUTInterpolator(float* values, size_t size);
+ ~LUTInterpolator();
virtual float interpolate(float input);
+
+private:
+ float* mValues;
+ size_t mSize;
};
} /* namespace uirenderer */
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 9606e58..de2fcf4 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -214,7 +214,7 @@
DeferStateStruct deferredState(*deferredList, *renderer,
RenderNode::kReplayFlag_ClipChildren);
- renderer->initViewport(width, height);
+ renderer->initializeViewport(width, height);
renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
dirtyRect.right, dirtyRect.bottom, !isBlend());
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e0ac2ba..c82197c 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -40,7 +40,7 @@
}
void LayerRenderer::setViewport(int width, int height) {
- initViewport(width, height);
+ initializeViewport(width, height);
}
status_t LayerRenderer::prepareDirty(float left, float top, float right, float bottom,
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 5a977c8..4df97e6 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -162,7 +162,7 @@
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::setViewport(int width, int height) {
- initViewport(width, height);
+ initializeViewport(width, height);
glDisable(GL_DITHER);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -170,12 +170,6 @@
glEnableVertexAttribArray(Program::kBindingPosition);
}
-void OpenGLRenderer::initViewport(int width, int height) {
- mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1);
-
- initializeViewport(width, height);
-}
-
void OpenGLRenderer::setupFrameState(float left, float top,
float right, float bottom, bool opaque) {
mCaches.clearGarbage();
@@ -244,7 +238,7 @@
status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
if (!opaque || mCountOverdraw) {
mCaches.enableScissor();
- mCaches.setScissor(left, currentSnapshot()->height - bottom, right - left, bottom - top);
+ mCaches.setScissor(left, getViewportHeight() - bottom, right - left, bottom - top);
glClear(GL_COLOR_BUFFER_BIT);
return DrawGlInfo::kStatusDrew;
}
@@ -270,7 +264,7 @@
clip = &(snapshot->layer->clipRect);
}
- startTiling(*clip, snapshot->height, opaque);
+ startTiling(*clip, getViewportHeight(), opaque);
}
}
@@ -333,7 +327,7 @@
void OpenGLRenderer::resume() {
const Snapshot* snapshot = currentSnapshot();
- glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
+ glViewport(0, 0, getViewportWidth(), getViewportHeight());
glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
debugOverdraw(true, false);
@@ -354,9 +348,8 @@
}
void OpenGLRenderer::resumeAfterLayer() {
- const Snapshot* snapshot = currentSnapshot();
- glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
- glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
+ glViewport(0, 0, getViewportWidth(), getViewportHeight());
+ glBindFramebuffer(GL_FRAMEBUFFER, currentSnapshot()->fbo);
debugOverdraw(true, false);
mCaches.resetScissor();
@@ -381,8 +374,8 @@
info.clipRight = clip.right;
info.clipBottom = clip.bottom;
info.isLayer = hasLayer();
- info.width = currentSnapshot()->viewport.getWidth();
- info.height = currentSnapshot()->height;
+ info.width = getViewportWidth();
+ info.height = getViewportHeight();
currentTransform()->copyTo(&info.transform[0]);
bool dirtyClip = mDirtyClip;
@@ -437,7 +430,7 @@
const Rect* clip = &mTilingClip;
mCaches.enableScissor();
- mCaches.setScissor(clip->left, firstSnapshot()->height - clip->bottom,
+ mCaches.setScissor(clip->left, firstSnapshot()->getViewportHeight() - clip->bottom,
clip->right - clip->left, clip->bottom - clip->top);
// 1x overdraw
@@ -621,14 +614,12 @@
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
- bool restoreOrtho = removed.flags & Snapshot::kFlagDirtyOrtho;
+ bool restoreViewport = removed.flags & Snapshot::kFlagIsFboLayer;
bool restoreClip = removed.flags & Snapshot::kFlagClipSet;
bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer;
- if (restoreOrtho) {
- const Rect& r = restored.viewport;
- glViewport(r.left, r.top, r.right, r.bottom);
- mViewProjMatrix.load(removed.orthoMatrix); // TODO: should ortho be stored in 'restored'?
+ if (restoreViewport) {
+ glViewport(0, 0, getViewportWidth(), getViewportHeight());
}
if (restoreClip) {
@@ -671,7 +662,7 @@
// When the layer is not an FBO, we may use glCopyTexImage so we
// need to make sure the layer does not extend outside the bounds
// of the framebuffer
- if (!bounds.intersect(currentSnapshot()->previous->viewport)) {
+ if (!bounds.intersect(Rect(0, 0, getViewportWidth(), getViewportHeight()))) {
bounds.setEmpty();
} else if (fboLayer) {
clip.set(bounds);
@@ -719,7 +710,7 @@
if (!currentSnapshot()->isIgnored()) {
mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
- mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
+ mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
}
}
@@ -831,8 +822,9 @@
layer->setEmpty(false);
}
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
- mSnapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
+ bounds.left, getViewportHeight() - bounds.bottom,
+ bounds.getWidth(), bounds.getHeight());
// Enqueue the buffer coordinates to clear the corresponding region later
mLayers.push(new Rect(bounds));
@@ -847,14 +839,11 @@
layer->setFbo(mCaches.fboCache.get());
mSnapshot->region = &mSnapshot->layer->region;
- mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer |
- Snapshot::kFlagDirtyOrtho;
+ mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
mSnapshot->fbo = layer->getFbo();
mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
- mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
- mSnapshot->height = bounds.getHeight();
- mSnapshot->orthoMatrix.load(mViewProjMatrix);
+ mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
endTiling();
debugOverdraw(false, false);
@@ -884,8 +873,6 @@
// Change the ortho projection
glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
- // TODO: determine best way to support 3d drawing within HW layers
- mViewProjMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
return true;
}
@@ -1420,7 +1407,7 @@
Rect clip(*currentClipRect());
clip.snapToPixelBoundaries();
- if (mCaches.setScissor(clip.left, currentSnapshot()->height - clip.bottom,
+ if (mCaches.setScissor(clip.left, getViewportHeight() - clip.bottom,
clip.getWidth(), clip.getHeight())) {
mDirtyClip = false;
}
@@ -1689,18 +1676,20 @@
void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
float left, float top, float right, float bottom, bool ignoreTransform) {
- mModelView.loadTranslate(left, top, 0.0f);
+ mModelViewMatrix.loadTranslate(left, top, 0.0f);
if (mode == kModelViewMode_TranslateAndScale) {
- mModelView.scale(right - left, bottom - top, 1.0f);
+ mModelViewMatrix.scale(right - left, bottom - top, 1.0f);
}
bool dirty = right - left > 0.0f && bottom - top > 0.0f;
- if (!ignoreTransform) {
- mCaches.currentProgram->set(mViewProjMatrix, mModelView, *currentTransform(), offset);
- if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, *currentTransform());
- } else {
- mCaches.currentProgram->set(mViewProjMatrix, mModelView, mat4::identity(), offset);
- if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom);
+ const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
+ mCaches.currentProgram->set(mSnapshot->getOrthoMatrix(), mModelViewMatrix, transformMatrix, offset);
+ if (dirty && mTrackDirtyRegions) {
+ if (!ignoreTransform) {
+ dirtyLayer(left, top, right, bottom, *currentTransform());
+ } else {
+ dirtyLayer(left, top, right, bottom);
+ }
}
}
@@ -1724,11 +1713,11 @@
// compensate.
mat4 modelViewWithoutTransform;
modelViewWithoutTransform.loadInverse(*currentTransform());
- modelViewWithoutTransform.multiply(mModelView);
- mModelView.load(modelViewWithoutTransform);
+ modelViewWithoutTransform.multiply(mModelViewMatrix);
+ mModelViewMatrix.load(modelViewWithoutTransform);
}
mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
- mModelView, *mSnapshot, &mTextureUnit);
+ mModelViewMatrix, *mSnapshot, &mTextureUnit);
}
}
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 1d46945..b58b817 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -254,8 +254,8 @@
return mSnapshot->clipRegion->isEmpty();
}
- int getViewportWidth() { return currentSnapshot()->viewport.getWidth(); }
- int getViewportHeight() { return currentSnapshot()->viewport.getHeight(); }
+ int getViewportWidth() { return currentSnapshot()->getViewportWidth(); }
+ int getViewportHeight() { return currentSnapshot()->getViewportHeight(); }
/**
* Scales the alpha on the current snapshot. This alpha value will be modulated
@@ -354,12 +354,6 @@
protected:
/**
- * Computes the projection matrix, initialize the first snapshot
- * and stores the dimensions of the render target.
- */
- void initViewport(int width, int height);
-
- /**
* Perform the setup specific to a frame. This method does not
* issue any OpenGL commands.
*/
@@ -930,24 +924,21 @@
*/
Texture* getTexture(const SkBitmap* bitmap);
- // Matrix used for view/projection in shaders
- mat4 mViewProjMatrix;
-
/**
* Model-view matrix used to position/size objects
*
* Stores operation-local modifications to the draw matrix that aren't incorporated into the
* currentTransform().
*
- * If generated with kModelViewMode_Translate, the mModelView will reflect an x/y offset,
+ * If generated with kModelViewMode_Translate, mModelViewMatrix will reflect an x/y offset,
* e.g. the offset in drawLayer(). If generated with kModelViewMode_TranslateAndScale,
- * mModelView will reflect a translation and scale, e.g. the translation and scale required to
- * make VBO 0 (a rect of (0,0,1,1)) scaled to match the x,y offset, and width/height of a
- * bitmap.
+ * mModelViewMatrix will reflect a translation and scale, e.g. the translation and scale
+ * required to make VBO 0 (a rect of (0,0,1,1)) scaled to match the x,y offset, and width/height
+ * of a bitmap.
*
* Used as input to SkiaShader transformation.
*/
- mat4 mModelView;
+ mat4 mModelViewMatrix;
// State used to define the clipping region
Rect mTilingClip;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 9902ff1..d4ff4a3 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -53,7 +53,7 @@
}
RenderNode::RenderNode()
- : mNeedsPropertiesSync(false)
+ : mDirtyPropertyFields(0)
, mNeedsDisplayListDataSync(false)
, mDisplayListData(0)
, mStagingDisplayListData(0)
@@ -109,23 +109,37 @@
prepareSubTree(info, mDisplayListData);
}
-static bool is_finished(const sp<BaseRenderNodeAnimator>& animator) {
- return animator->isFinished();
-}
+class PushAnimatorsFunctor {
+public:
+ PushAnimatorsFunctor(RenderNode* target, TreeInfo& info)
+ : mTarget(target), mInfo(info) {}
+
+ bool operator() (const sp<BaseRenderNodeAnimator>& animator) {
+ animator->setupStartValueIfNecessary(mTarget, mInfo);
+ return animator->isFinished();
+ }
+private:
+ RenderNode* mTarget;
+ TreeInfo& mInfo;
+};
void RenderNode::pushStagingChanges(TreeInfo& info) {
- if (mNeedsPropertiesSync) {
- mNeedsPropertiesSync = false;
- mProperties = mStagingProperties;
- }
+ // Push the animators first so that setupStartValueIfNecessary() is called
+ // before properties() is trampled by stagingProperties(), as they are
+ // required by some animators.
if (mNeedsAnimatorsSync) {
mAnimators.resize(mStagingAnimators.size());
std::vector< sp<BaseRenderNodeAnimator> >::iterator it;
+ PushAnimatorsFunctor functor(this, info);
// hint: this means copy_if_not()
it = std::remove_copy_if(mStagingAnimators.begin(), mStagingAnimators.end(),
- mAnimators.begin(), is_finished);
+ mAnimators.begin(), functor);
mAnimators.resize(std::distance(mAnimators.begin(), it));
}
+ if (mDirtyPropertyFields) {
+ mDirtyPropertyFields = 0;
+ mProperties = mStagingProperties;
+ }
if (mNeedsDisplayListDataSync) {
mNeedsDisplayListDataSync = false;
// Do a push pass on the old tree to handle freeing DisplayListData
@@ -144,7 +158,7 @@
AnimateFunctor(RenderNode* target, TreeInfo& info)
: mTarget(target), mInfo(info) {}
- bool operator() (sp<BaseRenderNodeAnimator>& animator) {
+ bool operator() (const sp<BaseRenderNodeAnimator>& animator) {
return animator->animate(mTarget, mInfo);
}
private:
@@ -238,9 +252,8 @@
}
if (CC_UNLIKELY(properties().hasClippingPath())) {
- // TODO: optimize for round rect/circle clipping
- const SkPath* path = properties().getClippingPath();
- ClipPathOp* op = new (handler.allocator()) ClipPathOp(path, SkRegion::kIntersect_Op);
+ ClipPathOp* op = new (handler.allocator()) ClipPathOp(
+ properties().getClippingPath(), properties().getClippingPathOp());
handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
}
}
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 159903c..1811a7b 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -45,7 +45,6 @@
#include "DisplayList.h"
#include "RenderProperties.h"
#include "TreeInfo.h"
-#include "utils/VirtualLightRefBase.h"
class SkBitmap;
class SkPaint;
@@ -83,6 +82,22 @@
*/
class RenderNode : public VirtualLightRefBase {
public:
+ enum DirtyPropertyMask {
+ GENERIC = 1 << 1,
+ TRANSLATION_X = 1 << 2,
+ TRANSLATION_Y = 1 << 3,
+ TRANSLATION_Z = 1 << 4,
+ SCALE_X = 1 << 5,
+ SCALE_Y = 1 << 6,
+ ROTATION = 1 << 7,
+ ROTATION_X = 1 << 8,
+ ROTATION_Y = 1 << 9,
+ X = 1 << 10,
+ Y = 1 << 11,
+ Z = 1 << 12,
+ ALPHA = 1 << 13,
+ };
+
ANDROID_API RenderNode();
ANDROID_API virtual ~RenderNode();
@@ -124,6 +139,14 @@
}
}
+ bool isPropertyFieldDirty(DirtyPropertyMask field) const {
+ return mDirtyPropertyFields & field;
+ }
+
+ void setPropertyFieldsDirty(uint32_t fields) {
+ mDirtyPropertyFields |= fields;
+ }
+
const RenderProperties& properties() {
return mProperties;
}
@@ -137,7 +160,6 @@
}
RenderProperties& mutateStagingProperties() {
- mNeedsPropertiesSync = true;
return mStagingProperties;
}
@@ -153,6 +175,7 @@
// UI thread only!
ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
+ animator->onAttached(this);
mStagingAnimators.insert(animator);
mNeedsAnimatorsSync = true;
}
@@ -228,7 +251,7 @@
String8 mName;
- bool mNeedsPropertiesSync;
+ uint32_t mDirtyPropertyFields;
RenderProperties mProperties;
RenderProperties mStagingProperties;
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 99de1fc..5f7d4e3 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -50,14 +50,11 @@
}
RenderProperties::ComputedFields::ComputedFields()
- : mTransformMatrix(NULL)
- , mClipPath(NULL)
- , mClipPathOp(SkRegion::kIntersect_Op) {
+ : mTransformMatrix(NULL) {
}
RenderProperties::ComputedFields::~ComputedFields() {
delete mTransformMatrix;
- delete mClipPath;
}
RenderProperties::RenderProperties()
@@ -77,9 +74,6 @@
setAnimationMatrix(other.getAnimationMatrix());
setCameraDistance(other.getCameraDistance());
- // Update the computed clip path
- updateClipPath();
-
// Force recalculation of the matrix, since other's dirty bit may be clear
mPrimitiveFields.mMatrixOrPivotDirty = true;
updateMatrix();
@@ -166,39 +160,5 @@
}
}
-void RenderProperties::updateClipPath() {
- const SkPath* outlineClipPath = mPrimitiveFields.mOutline.willClip()
- ? mPrimitiveFields.mOutline.getPath() : NULL;
- const SkPath* revealClipPath = mPrimitiveFields.mRevealClip.getPath();
-
- if (!outlineClipPath && !revealClipPath) {
- // mComputedFields.mClipPath doesn't need to be updated, since it won't be used
- return;
- }
-
- if (mComputedFields.mClipPath == NULL) {
- mComputedFields.mClipPath = new SkPath();
- }
- SkPath* clipPath = mComputedFields.mClipPath;
- mComputedFields.mClipPathOp = SkRegion::kIntersect_Op;
-
- if (outlineClipPath && revealClipPath) {
- SkPathOp op = kIntersect_PathOp;
- if (mPrimitiveFields.mRevealClip.isInverseClip()) {
- op = kDifference_PathOp; // apply difference step in the Op below, instead of draw time
- }
-
- Op(*outlineClipPath, *revealClipPath, op, clipPath);
- } else if (outlineClipPath) {
- *clipPath = *outlineClipPath;
- } else {
- *clipPath = *revealClipPath;
- if (mPrimitiveFields.mRevealClip.isInverseClip()) {
- // apply difference step at draw time
- mComputedFields.mClipPathOp = SkRegion::kDifference_Op;
- }
- }
-}
-
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 6fc8bce..c0e3ce7 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -437,19 +437,17 @@
ANDROID_API void updateMatrix();
- ANDROID_API void updateClipPath();
-
- // signals that mComputedFields.mClipPath is up to date, and should be used for clipping
bool hasClippingPath() const {
- return mPrimitiveFields.mOutline.willClip() || mPrimitiveFields.mRevealClip.willClip();
+ return mPrimitiveFields.mRevealClip.willClip();
}
const SkPath* getClippingPath() const {
- return hasClippingPath() ? mComputedFields.mClipPath : NULL;
+ return mPrimitiveFields.mRevealClip.getPath();
}
SkRegion::Op getClippingPathOp() const {
- return mComputedFields.mClipPathOp;
+ return mPrimitiveFields.mRevealClip.isInverseClip()
+ ? SkRegion::kDifference_Op : SkRegion::kIntersect_Op;
}
Outline& mutableOutline() {
@@ -505,8 +503,6 @@
SkMatrix* mTransformMatrix;
Sk3DView mTransformCamera;
- SkPath* mClipPath; // TODO: remove this, create new ops for efficient/special case clipping
- SkRegion::Op mClipPathOp;
} mComputedFields;
};
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index be49aed..55b82e4 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -196,6 +196,10 @@
* @param len the number of points of the polygon
*/
bool ShadowTessellator::isClockwise(const Vector2* polygon, int len) {
+ if (len < 2 || polygon == NULL) {
+ ALOGW("Invalid polygon %p, length is %d @ isClockwise()", polygon, len);
+ return true;
+ }
double sum = 0;
double p1x = polygon[len - 1].x;
double p1y = polygon[len - 1].y;
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 6bfa203..029b56d 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -34,7 +34,6 @@
, fbo(0)
, invisible(false)
, empty(false)
- , height(0)
, alpha(1.0f) {
transform = &mTransformRoot;
clipRect = &mClipRectRoot;
@@ -53,9 +52,8 @@
, fbo(s->fbo)
, invisible(s->invisible)
, empty(false)
- , viewport(s->viewport)
- , height(s->height)
- , alpha(s->alpha) {
+ , alpha(s->alpha)
+ , mViewportData(s->mViewportData) {
if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
mTransformRoot.load(*s->transform);
@@ -215,7 +213,7 @@
void Snapshot::dump() const {
ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
- this, flags, previous.get(), height, isIgnored(), clipRegion && !clipRegion->isEmpty());
+ this, flags, previous.get(), getViewportHeight(), isIgnored(), clipRegion && !clipRegion->isEmpty());
ALOGD(" ClipRect (at %p) %.1f %.1f %.1f %.1f",
clipRect, clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
ALOGD(" Transform (at %p):", transform);
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 038aea8..e9ab1ff 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -65,17 +65,16 @@
* Indicates that this snapshot is a special type of layer
* backed by an FBO. This flag only makes sense when the
* flag kFlagIsLayer is also set.
+ *
+ * Viewport has been modified to fit the new Fbo, and must be
+ * restored when this snapshot is restored.
*/
kFlagIsFboLayer = 0x4,
/**
- * Indicates that this snapshot has changed the ortho matrix.
- */
- kFlagDirtyOrtho = 0x8,
- /**
* Indicates that this snapshot or an ancestor snapshot is
* an FBO layer.
*/
- kFlagFboTarget = 0x10
+ kFlagFboTarget = 0x8,
};
/**
@@ -125,6 +124,14 @@
*/
void resetTransform(float x, float y, float z);
+ void initializeViewport(int width, int height) {
+ mViewportData.initialize(width, height);
+ }
+
+ int getViewportWidth() const { return mViewportData.mWidth; }
+ int getViewportHeight() const { return mViewportData.mHeight; }
+ const Matrix4& getOrthoMatrix() const { return mViewportData.mOrthoMatrix; }
+
/**
* Indicates whether this snapshot should be ignored. A snapshot
* is typicalled ignored if its layer is invisible or empty.
@@ -173,21 +180,6 @@
bool empty;
/**
- * Current viewport.
- */
- Rect viewport;
-
- /**
- * Height of the framebuffer the snapshot is rendering into.
- */
- int height;
-
- /**
- * Contains the previous ortho matrix.
- */
- mat4 orthoMatrix;
-
- /**
* Local transformation. Holds the current translation, scale and
* rotation values.
*
@@ -236,6 +228,27 @@
void dump() const;
private:
+ struct ViewportData {
+ ViewportData() : mWidth(0), mHeight() {}
+ void initialize(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
+ }
+
+ /*
+ * Width and height of current viewport.
+ *
+ * The viewport is always defined to be (0, 0, width, height).
+ */
+ int mWidth;
+ int mHeight;
+ /**
+ * Contains the current orthographic, projection matrix.
+ */
+ mat4 mOrthoMatrix;
+ };
+
void ensureClipRegion();
void copyClipRectFromRegion();
@@ -246,6 +259,7 @@
Rect mLocalClip; // don't use directly, call getLocalClip() which initializes this
SkRegion mClipRegionRoot;
+ ViewportData mViewportData;
}; // class Snapshot
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp
index 05f6cf8..aa83e20 100644
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ b/libs/hwui/StatefulBaseRenderer.cpp
@@ -38,9 +38,7 @@
void StatefulBaseRenderer::initializeViewport(int width, int height) {
mWidth = width;
mHeight = height;
-
- mFirstSnapshot->height = height;
- mFirstSnapshot->viewport.set(0, 0, width, height);
+ mFirstSnapshot->initializeViewport(width, height);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h
index 64354ac..9fbf2ca 100644
--- a/libs/hwui/StatefulBaseRenderer.h
+++ b/libs/hwui/StatefulBaseRenderer.h
@@ -46,6 +46,11 @@
virtual status_t prepare(bool opaque) {
return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
}
+
+ /**
+ * Initialize the first snapshot, computing the projection matrix,
+ * and stores the dimensions of the render target.
+ */
void initializeViewport(int width, int height);
void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom);
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index fc5994c..d4a23b8 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -21,12 +21,12 @@
namespace android {
namespace uirenderer {
-class BaseAnimator;
+class BaseRenderNodeAnimator;
class AnimationListener;
class AnimationHook {
public:
- virtual void callOnFinished(BaseAnimator* animator, AnimationListener* listener) = 0;
+ virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) = 0;
protected:
~AnimationHook() {}
};
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index d22cb8a..08e9a1a 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -214,18 +214,28 @@
int dstY = y + glyph->mBitmapTop;
CacheTexture* cacheTexture = glyph->mCacheTexture;
-
- uint32_t cacheWidth = cacheTexture->getWidth();
- uint32_t startY = glyph->mStartY * cacheWidth;
- uint32_t endY = startY + (glyph->mBitmapHeight * cacheWidth);
-
PixelBuffer* pixelBuffer = cacheTexture->getPixelBuffer();
+
+ uint32_t formatSize = PixelBuffer::formatSize(pixelBuffer->getFormat());
+ uint32_t cacheWidth = cacheTexture->getWidth();
+ uint32_t srcStride = formatSize * cacheWidth;
+ uint32_t startY = glyph->mStartY * srcStride;
+ uint32_t endY = startY + (glyph->mBitmapHeight * srcStride);
+
const uint8_t* cacheBuffer = pixelBuffer->map();
for (uint32_t cacheY = startY, bitmapY = dstY * bitmapWidth; cacheY < endY;
- cacheY += cacheWidth, bitmapY += bitmapWidth) {
- memcpy(&bitmap[bitmapY + dstX], &cacheBuffer[cacheY + glyph->mStartX], glyph->mBitmapWidth);
+ cacheY += srcStride, bitmapY += bitmapWidth) {
+
+ if (formatSize == 1) {
+ memcpy(&bitmap[bitmapY + dstX], &cacheBuffer[cacheY + glyph->mStartX], glyph->mBitmapWidth);
+ } else {
+ for (uint32_t i = 0; i < glyph->mBitmapWidth; ++i) {
+ bitmap[bitmapY + dstX + i] = cacheBuffer[cacheY + (glyph->mStartX + i)*formatSize];
+ }
+ }
}
+
}
void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset,
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 5a23158..48cd8fc 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -31,11 +31,10 @@
#define PROPERTY_RENDER_DIRTY_REGIONS "debug.hwui.render_dirty_regions"
#define GLES_VERSION 2
+#define USE_TEXTURE_ATLAS false
-#ifdef USE_OPENGL_RENDERER
// Android-specific addition that is used to show when frames began in systrace
EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
-#endif
namespace android {
namespace uirenderer {
@@ -98,6 +97,8 @@
bool enableDirtyRegions(EGLSurface surface);
+ void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize);
+
private:
GlobalContext();
// GlobalContext is never destroyed, method is purposely not implemented
@@ -118,6 +119,10 @@
bool mCanSetDirtyRegions;
EGLSurface mCurrentSurface;
+
+ sp<GraphicBuffer> mAtlasBuffer;
+ int64_t* mAtlasMap;
+ size_t mAtlasMapSize;
};
GlobalContext* GlobalContext::sContext = 0;
@@ -135,7 +140,9 @@
, mEglContext(EGL_NO_CONTEXT)
, mPBufferSurface(EGL_NO_SURFACE)
, mRequestDirtyRegions(load_dirty_regions_property())
- , mCurrentSurface(EGL_NO_SURFACE) {
+ , mCurrentSurface(EGL_NO_SURFACE)
+ , mAtlasMap(NULL)
+ , mAtlasMapSize(0) {
mCanSetDirtyRegions = mRequestDirtyRegions;
ALOGD("Render dirty regions requested: %s", mRequestDirtyRegions ? "true" : "false");
}
@@ -201,9 +208,30 @@
"Failed to create context, error = %s", egl_error_str());
}
+void GlobalContext::setTextureAtlas(const sp<GraphicBuffer>& buffer,
+ int64_t* map, size_t mapSize) {
+
+ // Already initialized
+ if (mAtlasBuffer.get()) {
+ ALOGW("Multiple calls to setTextureAtlas!");
+ delete map;
+ return;
+ }
+
+ mAtlasBuffer = buffer;
+ mAtlasMap = map;
+ mAtlasMapSize = mapSize;
+
+ if (hasContext()) {
+ usePBufferSurface();
+ initAtlas();
+ }
+}
+
void GlobalContext::initAtlas() {
- // TODO implement
- // For now just run without an atlas
+ if (USE_TEXTURE_ATLAS) {
+ Caches::getInstance().assetAtlas.init(mAtlasBuffer, mAtlasMap, mAtlasMapSize);
+ }
}
void GlobalContext::usePBufferSurface() {
@@ -533,6 +561,11 @@
}
}
+void CanvasContext::setTextureAtlas(const sp<GraphicBuffer>& buffer,
+ int64_t* map, size_t mapSize) {
+ GlobalContext::get()->setTextureAtlas(buffer, map, mapSize);
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index dcb9858..a793d42 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -70,6 +70,9 @@
Layer* createRenderLayer(int width, int height);
Layer* createTextureLayer();
+ ANDROID_API static void setTextureAtlas(const sp<GraphicBuffer>& buffer,
+ int64_t* map, size_t mapSize);
+
private:
void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
void prepareTree(TreeInfo& info);
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
index 8ba44dc..1a7082b 100644
--- a/libs/hwui/utils/MathUtils.h
+++ b/libs/hwui/utils/MathUtils.h
@@ -33,6 +33,14 @@
inline static bool isPositive(float value) {
return value >= gNonZeroEpsilon;
}
+
+ inline static int min(int a, int b) {
+ return a < b ? a : b;
+ }
+
+ inline static float lerp(float v1, float v2, float t) {
+ return v1 + ((v2 - v1) * t);
+ }
}; // class MathUtils
} /* namespace uirenderer */
diff --git a/libs/hwui/utils/VirtualLightRefBase.h b/libs/hwui/utils/VirtualLightRefBase.h
deleted file mode 100644
index b545aab..0000000
--- a/libs/hwui/utils/VirtualLightRefBase.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef VIRTUALLIGHTREFBASE_H
-#define VIRTUALLIGHTREFBASE_H
-
-#include <utils/RefBase.h>
-
-namespace android {
-namespace uirenderer {
-
-// This is a wrapper around LightRefBase that simply enforces a virtual
-// destructor to eliminate the template requirement of LightRefBase
-class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> {
-public:
- virtual ~VirtualLightRefBase() {}
-};
-
-} /* namespace uirenderer */
-} /* namespace android */
-
-#endif /* VIRTUALLIGHTREFBASE_H */
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
new file mode 100644
index 0000000..bb23a36
--- /dev/null
+++ b/media/java/android/media/AudioAttributes.java
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.IntDef;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A class to encapsulate a collection of attributes describing information about an audio
+ * player or recorder.
+ */
+public final class AudioAttributes {
+ private final static String TAG = "AudioAttributes";
+
+ /**
+ * Content type value to use when the content type is unknown, or other than the ones defined.
+ */
+ public final static int CONTENT_TYPE_UNKNOWN = 0;
+ /**
+ * Content type value to use when the content type is speech.
+ */
+ public final static int CONTENT_TYPE_SPEECH = 1;
+ /**
+ * Content type value to use when the content type is music.
+ */
+ public final static int CONTENT_TYPE_MUSIC = 2;
+ /**
+ * Content type value to use when the content type is a soundtrack, typically accompanying
+ * a movie or TV program.
+ */
+ public final static int CONTENT_TYPE_MOVIE = 3;
+ /**
+ * Content type value to use when the content type is a sound used to accompany a user
+ * action, such as a beep or sound effect expressing a key click, or event, such as the
+ * type of a sound for a bonus being received in a game. These sounds are mostly synthesized
+ * or short Foley sounds.
+ */
+ public final static int CONTENT_TYPE_SONIFICATION = 4;
+
+ /**
+ * Usage value to use when the usage is unknown.
+ */
+ public final static int USAGE_UNKNOWN = 0;
+ /**
+ * Usage value to use when the usage is media, such as music, or movie
+ * soundtracks.
+ */
+ public final static int USAGE_MEDIA = 1;
+ /**
+ * Usage value to use when the usage is voice communications, such as telephony
+ * or VoIP.
+ */
+ public final static int USAGE_VOICE_COMMUNICATION = 2;
+ /**
+ * Usage value to use when the usage is in-call signalling, such as with
+ * a "busy" beep, or DTMF tones.
+ */
+ public final static int USAGE_VOICE_COMMUNICATION_SIGNALLING = 3;
+ /**
+ * Usage value to use when the usage is an alarm (e.g. wake-up alarm).
+ */
+ public final static int USAGE_ALARM = 4;
+ /**
+ * Usage value to use when the usage is notification. See other
+ * notification usages for more specialized uses.
+ */
+ public final static int USAGE_NOTIFICATION = 5;
+ /**
+ * Usage value to use when the usage is telephony ringtone.
+ */
+ public final static int USAGE_NOTIFICATION_TELEPHONY_RINGTONE = 6;
+ /**
+ * Usage value to use when the usage is a request to enter/end a
+ * communication, such as a VoIP communication or video-conference.
+ */
+ public final static int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7;
+ /**
+ * Usage value to use when the usage is notification for an "instant"
+ * communication such as a chat, or SMS.
+ */
+ public final static int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8;
+ /**
+ * Usage value to use when the usage is notification for a
+ * non-immediate type of communication such as e-mail.
+ */
+ public final static int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9;
+ /**
+ * Usage value to use when the usage is to attract the user's attention,
+ * such as a reminder or low battery warning.
+ */
+ public final static int USAGE_NOTIFICATION_EVENT = 10;
+ /**
+ * Usage value to use when the usage is for accessibility, such as with
+ * a screen reader.
+ */
+ public final static int USAGE_ASSISTANCE_ACCESSIBILITY = 11;
+ /**
+ * Usage value to use when the usage is driving or navigation directions.
+ */
+ public final static int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12;
+ /**
+ * Usage value to use when the usage is sonification, such as with user
+ * interface sounds.
+ */
+ public final static int USAGE_ASSISTANCE_SONIFICATION = 13;
+ /**
+ * Usage value to use when the usage is for game audio.
+ */
+ public final static int USAGE_GAME = 14;
+
+ /**
+ * Flag defining a behavior where the audibility of the sound will be ensured by the system.
+ */
+ public final static int FLAG_AUDIBILITY_ENFORCED = 0x1 << 0;
+ /**
+ * @hide
+ * Flag defining a behavior where the playback of the sound is ensured without
+ * degradation only when going to a secure sink.
+ */
+ // FIXME not guaranteed yet
+ // TODO add OR to getFlags() when supported and in public API
+ public final static int FLAG_SECURE = 0x1 << 1;
+ /**
+ * @hide
+ * Flag to enable when the stream is associated with SCO usage.
+ * Internal use only for dealing with legacy STREAM_BLUETOOTH_SCO
+ */
+ public final static int FLAG_SCO = 0x1 << 2;
+
+
+ private int mUsage = USAGE_UNKNOWN;
+ private int mContentType = CONTENT_TYPE_UNKNOWN;
+ private int mFlags = 0x0;
+ private HashSet<String> mTags;
+
+ private AudioAttributes() {
+ }
+
+ /**
+ * Return the content type.
+ * @return one of the values that can be set in {@link Builder#setContentType(int)}
+ */
+ public int getContentType() {
+ return mContentType;
+ }
+
+ /**
+ * Return the usage.
+ * @return one of the values that can be set in {@link Builder#setUsage(int)}
+ */
+ public int getUsage() {
+ return mUsage;
+ }
+
+ /**
+ * Return the flags.
+ * @return a combined mask of all flags
+ */
+ public int getFlags() {
+ // only return the flags that are public
+ return (mFlags & (FLAG_AUDIBILITY_ENFORCED));
+ }
+
+ /**
+ * @hide
+ * Return all the flags, even the non-public ones.
+ * Internal use only
+ * @return a combined mask of all flags
+ */
+ public int getAllFlags() {
+ return mFlags;
+ }
+
+ /**
+ * Return the set of tags.
+ * @return a read-only set of all tags stored as strings.
+ */
+ public Set<String> getTags() {
+ return Collections.unmodifiableSet(mTags);
+ }
+
+ /**
+ * Builder class for {@link AudioAttributes} objects.
+ */
+ public static class Builder {
+ private int mUsage = USAGE_UNKNOWN;
+ private int mContentType = CONTENT_TYPE_UNKNOWN;
+ private int mFlags = 0x0;
+ private HashSet<String> mTags = new HashSet<String>();
+
+ /**
+ * Constructs a new Builder with the defaults.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Constructs a new Builder from a given AudioAttributes
+ * @param aa the AudioAttributes object whose data will be reused in the new Builder.
+ */
+ @SuppressWarnings("unchecked") // for cloning of mTags
+ public Builder(AudioAttributes aa) {
+ mUsage = aa.mUsage;
+ mContentType = aa.mContentType;
+ mFlags = aa.mFlags;
+ mTags = (HashSet<String>) aa.mTags.clone();
+ }
+
+ /**
+ * Combines all of the attributes that have been set and return a new
+ * {@link AudioAttributes} object.
+ * @return a new {@link AudioAttributes} object
+ */
+ @SuppressWarnings("unchecked") // for cloning of mTags
+ public AudioAttributes build() {
+ AudioAttributes aa = new AudioAttributes();
+ aa.mContentType = mContentType;
+ aa.mUsage = mUsage;
+ aa.mFlags = mFlags;
+ aa.mTags = (HashSet<String>) mTags.clone();
+ return aa;
+ }
+
+ /**
+ * Sets the attribute describing what is the intended use of the the audio signal,
+ * such as alarm or ringtone.
+ * @param usage one of {@link AudioAttributes#USAGE_UNKNOWN},
+ * {@link AudioAttributes#USAGE_MEDIA},
+ * {@link AudioAttributes#USAGE_VOICE_COMMUNICATION},
+ * {@link AudioAttributes#USAGE_VOICE_COMMUNICATION_SIGNALLING},
+ * {@link AudioAttributes#USAGE_ALARM}, {@link AudioAttributes#USAGE_NOTIFICATION},
+ * {@link AudioAttributes#USAGE_NOTIFICATION_TELEPHONY_RINGTONE},
+ * {@link AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_REQUEST},
+ * {@link AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_INSTANT},
+ * {@link AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_DELAYED},
+ * {@link AudioAttributes#USAGE_NOTIFICATION_EVENT},
+ * {@link AudioAttributes#USAGE_ASSISTANCE_ACCESSIBILITY},
+ * {@link AudioAttributes#USAGE_ASSISTANCE_NAVIGATION_GUIDANCE},
+ * {@link AudioAttributes#USAGE_ASSISTANCE_SONIFICATION},
+ * {@link AudioAttributes#USAGE_GAME}.
+ * @return the same Builder instance.
+ */
+ public Builder setUsage(@AttributeUsage int usage) {
+ switch (usage) {
+ case USAGE_UNKNOWN:
+ case USAGE_MEDIA:
+ case USAGE_VOICE_COMMUNICATION:
+ case USAGE_VOICE_COMMUNICATION_SIGNALLING:
+ case USAGE_ALARM:
+ case USAGE_NOTIFICATION:
+ case USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
+ case USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
+ case USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
+ case USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
+ case USAGE_NOTIFICATION_EVENT:
+ case USAGE_ASSISTANCE_ACCESSIBILITY:
+ case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
+ case USAGE_ASSISTANCE_SONIFICATION:
+ case USAGE_GAME:
+ mUsage = usage;
+ break;
+ default:
+ mUsage = USAGE_UNKNOWN;
+ }
+ return this;
+ }
+
+ /**
+ * Sets the attribute describing the content type of the audio signal, such as speech,
+ * or music.
+ * @param contentType the content type values, one of
+ * {@link AudioAttributes#CONTENT_TYPE_MOVIE},
+ * {@link AudioAttributes#CONTENT_TYPE_MUSIC},
+ * {@link AudioAttributes#CONTENT_TYPE_SONIFICATION},
+ * {@link AudioAttributes#CONTENT_TYPE_SPEECH},
+ * {@link AudioAttributes#CONTENT_TYPE_UNKNOWN}.
+ * @return the same Builder instance.
+ */
+ public Builder setContentType(@AttributeContentType int contentType) {
+ switch (contentType) {
+ case CONTENT_TYPE_UNKNOWN:
+ case CONTENT_TYPE_MOVIE:
+ case CONTENT_TYPE_MUSIC:
+ case CONTENT_TYPE_SONIFICATION:
+ case CONTENT_TYPE_SPEECH:
+ mContentType = contentType;
+ break;
+ default:
+ mUsage = CONTENT_TYPE_UNKNOWN;
+ }
+ return this;
+ }
+
+ /**
+ * Sets the combination of flags.
+ * @param flags the {@link AudioAttributes#FLAG_AUDIBILITY_ENFORCED} flag.
+ * @return the same Builder instance.
+ */
+ public Builder setFlags(int flags) {
+ flags &= (AudioAttributes.FLAG_AUDIBILITY_ENFORCED | AudioAttributes.FLAG_SCO
+ | AudioAttributes.FLAG_SECURE);
+ mFlags |= flags;
+ return this;
+ }
+
+ /**
+ * Add a custom tag stored as a string
+ * @param tag
+ * @return the same Builder instance.
+ */
+ public Builder addTag(String tag) {
+ mTags.add(tag);
+ return this;
+ }
+
+ /**
+ * Adds attributes inferred from the legacy stream types.
+ * @param streamType one of {@link AudioManager#STREAM_VOICE_CALL},
+ * {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING},
+ * {@link AudioManager#STREAM_MUSIC}, {@link AudioManager#STREAM_ALARM},
+ * or {@link AudioManager#STREAM_NOTIFICATION}.
+ * @return the same Builder instance.
+ */
+ public Builder setLegacyStreamType(int streamType) {
+ return setInternalLegacyStreamType(streamType);
+ }
+
+ /**
+ * @hide
+ * For internal framework use only, enables building from hidden stream types.
+ * @param streamType
+ * @return the same Builder instance.
+ */
+ public Builder setInternalLegacyStreamType(int streamType) {
+ switch(streamType) {
+ case AudioSystem.STREAM_VOICE_CALL:
+ mContentType = CONTENT_TYPE_SPEECH;
+ mUsage = USAGE_VOICE_COMMUNICATION;
+ break;
+ case AudioSystem.STREAM_SYSTEM_ENFORCED:
+ mFlags |= FLAG_AUDIBILITY_ENFORCED;
+ // intended fall through, attributes in common with STREAM_SYSTEM
+ case AudioSystem.STREAM_SYSTEM:
+ mContentType = CONTENT_TYPE_SONIFICATION;
+ mUsage = USAGE_ASSISTANCE_SONIFICATION;
+ break;
+ case AudioSystem.STREAM_RING:
+ mContentType = CONTENT_TYPE_SONIFICATION;
+ mUsage = USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+ break;
+ case AudioSystem.STREAM_MUSIC:
+ mContentType = CONTENT_TYPE_MUSIC;
+ mUsage = USAGE_MEDIA;
+ break;
+ case AudioSystem.STREAM_ALARM:
+ mContentType = CONTENT_TYPE_SONIFICATION;
+ mUsage = USAGE_ALARM;
+ break;
+ case AudioSystem.STREAM_NOTIFICATION:
+ mContentType = CONTENT_TYPE_SONIFICATION;
+ mUsage = USAGE_NOTIFICATION;
+ break;
+ case AudioSystem.STREAM_BLUETOOTH_SCO:
+ mContentType = CONTENT_TYPE_SPEECH;
+ mUsage = USAGE_VOICE_COMMUNICATION;
+ mFlags |= FLAG_SCO;
+ break;
+ case AudioSystem.STREAM_DTMF:
+ mContentType = CONTENT_TYPE_SONIFICATION;
+ mUsage = USAGE_VOICE_COMMUNICATION_SIGNALLING;
+ break;
+ case AudioSystem.STREAM_TTS:
+ mContentType = CONTENT_TYPE_SPEECH;
+ mUsage = USAGE_ASSISTANCE_ACCESSIBILITY;
+ break;
+ default:
+ Log.e(TAG, "Invalid stream type " + streamType + " in for AudioAttributes");
+ }
+ return this;
+ }
+ };
+
+ /** @hide */
+ @Override
+ public String toString () {
+ return new String("AudioAttributes:"
+ + " usage=" + mUsage
+ + " content=" + mContentType
+ + " flags=0x" + Integer.toHexString(mFlags)
+ + " tags=" + mTags);
+ }
+
+ /** @hide */
+ @IntDef({
+ USAGE_UNKNOWN,
+ USAGE_MEDIA,
+ USAGE_VOICE_COMMUNICATION,
+ USAGE_VOICE_COMMUNICATION_SIGNALLING,
+ USAGE_ALARM,
+ USAGE_NOTIFICATION,
+ USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+ USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+ USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+ USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+ USAGE_NOTIFICATION_EVENT,
+ USAGE_ASSISTANCE_ACCESSIBILITY,
+ USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ USAGE_ASSISTANCE_SONIFICATION,
+ USAGE_GAME
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AttributeUsage {}
+
+ /** @hide */
+ @IntDef({
+ CONTENT_TYPE_UNKNOWN,
+ CONTENT_TYPE_SPEECH,
+ CONTENT_TYPE_MUSIC,
+ CONTENT_TYPE_MOVIE,
+ CONTENT_TYPE_SONIFICATION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AttributeContentType {}
+}
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 6b2a247..57274ee 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -37,7 +37,7 @@
public static final int ENCODING_PCM_16BIT = 2;
/** Audio data format: PCM 8 bit per sample. Not guaranteed to be supported by devices. */
public static final int ENCODING_PCM_8BIT = 3;
- /** @hide Candidate for public API */
+ /** Audio data format: single-precision floating-point per sample */
public static final int ENCODING_PCM_FLOAT = 4;
/** Invalid audio channel configuration */
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index dab6eed..1a64cff 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -42,7 +42,8 @@
* The AudioTrack class manages and plays a single audio resource for Java applications.
* It allows streaming of PCM audio buffers to the audio sink for playback. This is
* achieved by "pushing" the data to the AudioTrack object using one of the
- * {@link #write(byte[], int, int)} and {@link #write(short[], int, int)} methods.
+ * {@link #write(byte[], int, int)}, {@link #write(short[], int, int)},
+ * and {@link #write(float[], int, int, int)} methods.
*
* <p>An AudioTrack instance can operate under two modes: static or streaming.<br>
* In Streaming mode, the application writes a continuous stream of data to the AudioTrack, using
@@ -72,7 +73,6 @@
*
* AudioTrack is not final and thus permits subclasses, but such use is not recommended.
*/
-// add {@link #write(float[], int, int)} when @hide removed
public class AudioTrack
{
//---------------------------------------------------------
@@ -245,8 +245,8 @@
* The encoding of the audio samples.
* @see AudioFormat#ENCODING_PCM_8BIT
* @see AudioFormat#ENCODING_PCM_16BIT
+ * @see AudioFormat#ENCODING_PCM_FLOAT
*/
- // add @see AudioFormat#ENCODING_PCM_FLOAT when @hide removed
private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
/**
* Audio session ID
@@ -287,8 +287,9 @@
* See {@link AudioFormat#CHANNEL_OUT_MONO} and
* {@link AudioFormat#CHANNEL_OUT_STEREO}
* @param audioFormat the format in which the audio data is represented.
- * See {@link AudioFormat#ENCODING_PCM_16BIT} and
- * {@link AudioFormat#ENCODING_PCM_8BIT}
+ * See {@link AudioFormat#ENCODING_PCM_16BIT},
+ * {@link AudioFormat#ENCODING_PCM_8BIT},
+ * and {@link AudioFormat#ENCODING_PCM_FLOAT}.
* @param bufferSizeInBytes the total size (in bytes) of the internal buffer where audio data is
* read from for playback.
* If track's creation mode is {@link #MODE_STREAM}, you can write data into
@@ -302,7 +303,6 @@
* @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM}
* @throws java.lang.IllegalArgumentException
*/
- // add {@link AudioFormat#ENCODING_PCM_FLOAT} to audioFormat section above, when @hide removed
public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
int bufferSizeInBytes, int mode)
throws IllegalArgumentException {
@@ -332,7 +332,8 @@
* {@link AudioFormat#CHANNEL_OUT_STEREO}
* @param audioFormat the format in which the audio data is represented.
* See {@link AudioFormat#ENCODING_PCM_16BIT} and
- * {@link AudioFormat#ENCODING_PCM_8BIT}
+ * {@link AudioFormat#ENCODING_PCM_8BIT},
+ * and {@link AudioFormat#ENCODING_PCM_FLOAT}.
* @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is read
* from for playback. If using the AudioTrack in streaming mode, you can write data into
* this buffer in smaller chunks than this size. If using the AudioTrack in static mode,
@@ -344,7 +345,6 @@
* @param sessionId Id of audio session the AudioTrack must be attached to
* @throws java.lang.IllegalArgumentException
*/
- // add {@link AudioFormat#ENCODING_PCM_FLOAT} to audioFormat section above, when @hide removed
public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
int bufferSizeInBytes, int mode, int sessionId)
throws IllegalArgumentException {
@@ -469,7 +469,7 @@
default:
throw new IllegalArgumentException("Unsupported sample encoding."
+ " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT"
- // + " or ENCODING_PCM_FLOAT" when @hide removed
+ + " or ENCODING_PCM_FLOAT"
+ ".");
}
@@ -730,12 +730,12 @@
* {@link AudioFormat#CHANNEL_OUT_STEREO}
* @param audioFormat the format in which the audio data is represented.
* See {@link AudioFormat#ENCODING_PCM_16BIT} and
- * {@link AudioFormat#ENCODING_PCM_8BIT}
+ * {@link AudioFormat#ENCODING_PCM_8BIT},
+ * and {@link AudioFormat#ENCODING_PCM_FLOAT}.
* @return {@link #ERROR_BAD_VALUE} if an invalid parameter was passed,
* or {@link #ERROR} if unable to query for output properties,
* or the minimum buffer size expressed in bytes.
*/
- // add {@link AudioFormat#ENCODING_PCM_FLOAT} to audioFormat section above, when @hide removed
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
int channelCount = 0;
switch(channelConfig) {
@@ -1259,7 +1259,6 @@
* @return the number of floats that were written, or {@link #ERROR_INVALID_OPERATION}
* if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
* the parameters don't resolve to valid data and indexes.
- * @hide candidate for public API
*/
public int write(float[] audioData, int offsetInFloats, int sizeInFloats,
@WriteMode int writeMode) {
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 115786c..34c55202 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -585,11 +585,63 @@
* the codec. If you previously specified a surface when configuring this
* video decoder you can optionally render the buffer.
* @param index The index of a client-owned output buffer previously returned
- * in a call to {@link #dequeueOutputBuffer}.
+ * from a call to {@link #dequeueOutputBuffer}.
* @param render If a valid surface was specified when configuring the codec,
* passing true renders this output buffer to the surface.
*/
- public native final void releaseOutputBuffer(int index, boolean render);
+ public final void releaseOutputBuffer(int index, boolean render) {
+ releaseOutputBuffer(index, render, false /* updatePTS */, 0 /* dummy */);
+ }
+
+ /**
+ * If you are done with a buffer, use this call to update its surface timestamp
+ * and return it to the codec to render it on the output surface. If you
+ * have not specified an output surface when configuring this video codec,
+ * this call will simply return the buffer to the codec.<p>
+ *
+ * The timestamp may have special meaning depending on the destination surface.
+ *
+ * <table>
+ * <tr><th>SurfaceView specifics</th></tr>
+ * <tr><td>
+ * If you render your buffer on a {@link android.view.SurfaceView},
+ * you can use the timestamp to render the buffer at a specific time (at the
+ * VSYNC at or after the buffer timestamp). For this to work, the timestamp
+ * needs to be <i>reasonably close</i> to the current {@link System#nanoTime}.
+ * Currently, this is set as within one (1) second. A few notes:
+ *
+ * <ul>
+ * <li>the buffer will not be returned to the codec until the timestamp
+ * has passed and the buffer is no longer used by the {@link android.view.Surface}.
+ * <li>buffers are processed sequentially, so you may block subsequent buffers to
+ * be displayed on the {@link android.view.Surface}. This is important if you
+ * want to react to user action, e.g. stop the video or seek.
+ * <li>if multiple buffers are sent to the {@link android.view.Surface} to be
+ * rendered at the same VSYNC, the last one will be shown, and the other ones
+ * will be dropped.
+ * <li>if the timestamp is <em>not</em> "reasonably close" to the current system
+ * time, the {@link android.view.Surface} will ignore the timestamp, and
+ * display the buffer at the earliest feasible time. In this mode it will not
+ * drop frames.
+ * <li>for best performance and quality, call this method when you are about
+ * two VSYNCs' time before the desired render time. For 60Hz displays, this is
+ * about 33 msec.
+ * </ul>
+ * </td></tr>
+ * </table>
+ *
+ * @param index The index of a client-owned output buffer previously returned
+ * from a call to {@link #dequeueOutputBuffer}.
+ * @param renderTimestampNs The timestamp to associate with this buffer when
+ * it is sent to the Surface.
+ */
+ public final void releaseOutputBuffer(int index, long renderTimestampNs) {
+ releaseOutputBuffer(
+ index, true /* render */, true /* updatePTS */, renderTimestampNs);
+ }
+
+ private native final void releaseOutputBuffer(
+ int index, boolean render, boolean updatePTS, long timeNs);
/**
* Signals end-of-stream on input. Equivalent to submitting an empty buffer with
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 7a8c22e..e341647 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -25,6 +25,6 @@
* @hide
*/
interface ISessionManager {
- ISession createSession(String packageName, in ISessionCallback cb, String tag);
- List<IBinder> getSessions(in ComponentName compName);
+ ISession createSession(String packageName, in ISessionCallback cb, String tag, int userId);
+ List<IBinder> getSessions(in ComponentName compName, int userId);
}
\ No newline at end of file
diff --git a/media/java/android/media/session/SessionManager.java b/media/java/android/media/session/SessionManager.java
index fd022fc..1eb3b7a 100644
--- a/media/java/android/media/session/SessionManager.java
+++ b/media/java/android/media/session/SessionManager.java
@@ -22,6 +22,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.util.Log;
@@ -65,10 +66,25 @@
* @return a {@link Session} for the new session
*/
public Session createSession(String tag) {
+ return createSessionAsUser(tag, UserHandle.myUserId());
+ }
+
+ /**
+ * Creates a new session as the specified user. To create a session as a
+ * user other than your own you must hold the
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}
+ * permission.
+ *
+ * @param tag A short name for debugging purposes
+ * @param userId The user id to create the session as.
+ * @return a {@link Session} for the new session
+ * @hide
+ */
+ public Session createSessionAsUser(String tag, int userId) {
try {
Session.CallbackStub cbStub = new Session.CallbackStub();
Session session = new Session(mService
- .createSession(mContext.getPackageName(), cbStub, tag), cbStub);
+ .createSession(mContext.getPackageName(), cbStub, tag, userId), cbStub);
cbStub.setMediaSession(session);
return session;
@@ -91,9 +107,27 @@
* @return A list of controllers for ongoing sessions
*/
public List<SessionController> getActiveSessions(ComponentName notificationListener) {
+ return getActiveSessionsForUser(notificationListener, UserHandle.myUserId());
+ }
+
+ /**
+ * Get active sessions for a specific user. To retrieve actions for a user
+ * other than your own you must hold the
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission
+ * in addition to any other requirements. If you are an enabled notification
+ * listener you may only get sessions for the users you are enabled for.
+ *
+ * @param notificationListener The enabled notification listener component.
+ * May be null.
+ * @param userId The user id to fetch sessions for.
+ * @return A list of controllers for ongoing sessions.
+ * @hide
+ */
+ public List<SessionController> getActiveSessionsForUser(ComponentName notificationListener,
+ int userId) {
ArrayList<SessionController> controllers = new ArrayList<SessionController>();
try {
- List<IBinder> binders = mService.getSessions(notificationListener);
+ List<IBinder> binders = mService.getSessions(notificationListener, userId);
for (int i = binders.size() - 1; i >= 0; i--) {
SessionController controller = SessionController.fromBinder(ISessionController.Stub
.asInterface(binders.get(i)));
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index a710c03..4a7c096 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -260,7 +260,11 @@
return OK;
}
-status_t JMediaCodec::releaseOutputBuffer(size_t index, bool render) {
+status_t JMediaCodec::releaseOutputBuffer(
+ size_t index, bool render, bool updatePTS, int64_t timestampNs) {
+ if (updatePTS) {
+ return mCodec->renderOutputBufferAndRelease(index, timestampNs);
+ }
return render
? mCodec->renderOutputBufferAndRelease(index)
: mCodec->releaseOutputBuffer(index);
@@ -873,7 +877,8 @@
}
static void android_media_MediaCodec_releaseOutputBuffer(
- JNIEnv *env, jobject thiz, jint index, jboolean render) {
+ JNIEnv *env, jobject thiz,
+ jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
@@ -883,7 +888,7 @@
return;
}
- status_t err = codec->releaseOutputBuffer(index, render);
+ status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
throwExceptionAsNecessary(env, err);
}
@@ -1138,7 +1143,7 @@
{ "dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
(void *)android_media_MediaCodec_dequeueOutputBuffer },
- { "releaseOutputBuffer", "(IZ)V",
+ { "releaseOutputBuffer", "(IZZJ)V",
(void *)android_media_MediaCodec_releaseOutputBuffer },
{ "signalEndOfInputStream", "()V",
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 2f2ea96..bf9f4ea 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -79,7 +79,8 @@
status_t dequeueOutputBuffer(
JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs);
- status_t releaseOutputBuffer(size_t index, bool render);
+ status_t releaseOutputBuffer(
+ size_t index, bool render, bool updatePTS, int64_t timestampNs);
status_t signalEndOfInputStream();
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
index 1e6b2e7..42da48d 100644
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ b/media/tests/MediaFrameworkTest/Android.mk
@@ -7,7 +7,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := easymocklib mockito-target
+LOCAL_STATIC_JAVA_LIBRARIES := easymocklib mockito-target core-tests android-support-test
LOCAL_PACKAGE_NAME := mediaframeworktest
diff --git a/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml
index 91ee2c6..c62199f 100644
--- a/media/tests/MediaFrameworkTest/AndroidManifest.xml
+++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml
@@ -76,4 +76,8 @@
android:label="MediaFramework integration tests InstrumentationRunner">
</instrumentation>
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.mediaframeworktest"
+ android:label="media framework tests"/>
+
</manifest>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
index 64b12b7..11d9070 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
@@ -63,6 +63,7 @@
suite.addTestSuite(CameraUtilsRuntimeExceptionTest.class);
suite.addTestSuite(CameraUtilsUncheckedThrowTest.class);
suite.addTestSuite(CameraUtilsBinderDecoratorTest.class);
+ suite.addTestSuite(CameraUtilsTypeReferenceTest.class);
suite.addTestSuite(CameraMetadataTest.class);
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ByteArrayHelpers.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ByteArrayHelpers.java
new file mode 100644
index 0000000..6f31480
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ByteArrayHelpers.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mediaframeworktest.unit;
+
+import android.util.Log;
+
+import java.lang.reflect.Array;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
+public class ByteArrayHelpers {
+
+ private static final String TAG = "ByteArrayHelpers";
+ private static boolean VERBOSE = false;
+
+ /**
+ * Convert an array of byte primitives to a {@code byte[]} using native endian order.
+ *
+ * <p>This function is a pass-through; it's here only to provide overloads for
+ * every single type of primitive arrays.
+ *
+ * @param array array of primitives
+ * @return array
+ */
+ public static byte[] toByteArray(byte[] array) {
+ return array;
+ }
+
+ /**
+ * Convert an array of shorts to a {@code byte[]} using native endian order.
+ *
+ * @param array array of shorts
+ * @return array converted into byte array using native endian order
+ */
+ public static byte[] toByteArray(short[] array) {
+ return toByteArray(array, Short.SIZE);
+ }
+
+ /**
+ * Convert an array of chars to a {@code byte[]} using native endian order.
+ *
+ * @param array array of chars
+ * @return array converted into byte array using native endian order
+ */
+ public static byte[] toByteArray(char[] array) {
+ return toByteArray(array, Character.SIZE);
+ }
+ /**
+ * Convert an array of ints to a {@code byte[]} using native endian order.
+ *
+ * @param array array of ints
+ * @return array converted into byte array using native endian order
+ */
+ public static byte[] toByteArray(int[] array) {
+ return toByteArray(array, Integer.SIZE);
+ }
+ /**
+ * Convert an array of longs to a {@code byte[]} using native endian order.
+ *
+ * @param array array of longs
+ * @return array converted into byte array using native endian order
+ */
+ public static byte[] toByteArray(long[] array) {
+ return toByteArray(array, Long.SIZE);
+ }
+ /**
+ * Convert an array of floats to a {@code byte[]} using native endian order.
+ *
+ * @param array array of floats
+ * @return array converted into byte array using native endian order
+ */
+ public static byte[] toByteArray(float[] array) {
+ return toByteArray(array, Float.SIZE);
+ }
+ /**
+ * Convert an array of doubles to a {@code byte[]} using native endian order.
+ *
+ * @param array array of doubles
+ * @return array converted into byte array using native endian order
+ */
+ public static byte[] toByteArray(double[] array) {
+ return toByteArray(array, Double.SIZE);
+ }
+
+ /**
+ * Convert an array of primitives to a {@code byte[]} using native endian order.
+ *
+ * <p>Arguments other than arrays are not supported. The array component must be primitive,
+ * the wrapper class is not allowed (e.g. {@code int[]} is ok, but {@code Integer[]} is not.</p>
+ *
+ * @param array array of primitives
+ * @return array converted into byte array using native endian order
+ *
+ * @throws IllegalArgumentException if {@code array} was not an array of primitives
+ */
+ public static <T> byte[] toByteArray(T array) {
+ @SuppressWarnings("unchecked")
+ Class<T> klass = (Class<T>) array.getClass();
+
+ if (!klass.isArray()) {
+ throw new IllegalArgumentException("array class must be an array");
+ }
+
+ Class<?> componentClass = klass.getComponentType();
+
+ if (!componentClass.isPrimitive()) {
+ throw new IllegalArgumentException("array's component must be a primitive");
+ }
+
+ int sizeInBits;
+ if (klass == int.class) {
+ sizeInBits = Integer.SIZE;
+ } else if (klass == float.class) {
+ sizeInBits = Float.SIZE;
+ } else if (klass == double.class) {
+ sizeInBits = Double.SIZE;
+ } else if (klass == short.class) {
+ sizeInBits = Short.SIZE;
+ } else if (klass == char.class) {
+ sizeInBits = Character.SIZE;
+ } else if (klass == long.class) {
+ sizeInBits = Long.SIZE;
+ } else if (klass == byte.class) {
+ sizeInBits = Byte.SIZE;
+ } else {
+ throw new AssertionError();
+ }
+
+ return toByteArray(array, sizeInBits);
+ }
+
+ /**
+ * Convert a variadic list of {@code Number}s into a byte array using native endian order.
+ *
+ * <p>Each {@link Number} must be an instance of a primitive wrapper class
+ * (e.g. {@link Integer} is OK, since it wraps {@code int}, but {@code BigInteger} is not.</p>
+ *
+ * @param numbers variadic list of numeric values
+ * @return array converted into byte array using native endian order
+ *
+ * @throws IllegalArgumentException
+ * if {@code numbers} contained a class that wasn't a primitive wrapper
+ */
+ public static byte[] toByteArray(Number... numbers) {
+ if (numbers.length == 0) {
+ throw new IllegalArgumentException("too few numbers");
+ }
+
+ if (VERBOSE) Log.v(TAG, "toByteArray - input: " + Arrays.toString(numbers));
+
+ // Have a large enough capacity to fit in every number as a double
+ ByteBuffer byteBuffer = ByteBuffer.allocate(numbers.length * (Double.SIZE / Byte.SIZE))
+ .order(ByteOrder.nativeOrder());
+
+ for (int i = 0; i < numbers.length; ++i) {
+ Number value = numbers[i];
+ Class<? extends Number> klass = value.getClass();
+
+ if (VERBOSE) Log.v(TAG, "toByteArray - number " + i + ", class " + klass);
+
+ if (klass == Integer.class) {
+ byteBuffer.putInt((Integer)value);
+ } else if (klass == Float.class) {
+ byteBuffer.putFloat((Float)value);
+ } else if (klass == Double.class) {
+ byteBuffer.putDouble((Double)value);
+ } else if (klass == Short.class) {
+ byteBuffer.putShort((Short)value);
+ } else if (klass == Long.class) {
+ byteBuffer.putLong((Long)value);
+ } else if (klass == Byte.class) {
+ byteBuffer.put((Byte)value);
+ } else {
+ throw new IllegalArgumentException(
+ "number class invalid; must be wrapper around primitive class");
+ }
+ }
+
+ if (VERBOSE) Log.v(TAG, "toByteArray - end of loop");
+
+ // Each number written is at least 1 byte, so the position should be at least length
+ if (numbers.length != 0 && byteBuffer.position() < numbers.length) {
+ throw new AssertionError(String.format(
+ "Had %d numbers, but byte buffer position was only %d",
+ numbers.length, byteBuffer.position()));
+ }
+
+ byteBuffer.flip();
+
+ byte[] bytes = new byte[byteBuffer.limit()];
+ byteBuffer.get(bytes);
+
+ if (VERBOSE) Log.v(TAG, "toByteArray - output: " + Arrays.toString(bytes));
+
+ return bytes;
+ }
+
+ private static <T> byte[] toByteArray(T array, int sizeOfTBits) {
+ @SuppressWarnings("unchecked")
+ Class<T> klass = (Class<T>) array.getClass();
+
+ if (!klass.isArray()) {
+ throw new IllegalArgumentException("array class must be an array");
+ }
+
+ int sizeOfT = sizeOfTBits / Byte.SIZE;
+ int byteLength = Array.getLength(array) * sizeOfT;
+
+ if (klass == byte[].class) {
+ // Always return a copy
+ return Arrays.copyOf((byte[])array, byteLength);
+ }
+
+ ByteBuffer byteBuffer = ByteBuffer.allocate(byteLength).order(ByteOrder.nativeOrder());
+
+ if (klass == int[].class) {
+ byteBuffer.asIntBuffer().put((int[])array);
+ } else if (klass == float[].class) {
+ byteBuffer.asFloatBuffer().put((float[])array);
+ } else if (klass == double[].class) {
+ byteBuffer.asDoubleBuffer().put((double[])array);
+ } else if (klass == short[].class) {
+ byteBuffer.asShortBuffer().put((short[])array);
+ } else if (klass == char[].class) {
+ byteBuffer.asCharBuffer().put((char[])array);
+ } else if (klass == long[].class) {
+ byteBuffer.asLongBuffer().put((long[])array);
+ } else {
+ throw new IllegalArgumentException("array class invalid; must be a primitive array");
+ }
+
+ return byteBuffer.array();
+ }
+
+ private ByteArrayHelpers() {
+ throw new AssertionError();
+ }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index 45df065..5ab586f 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -16,18 +16,32 @@
package com.android.mediaframeworktest.unit;
-import android.os.Parcel;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Range;
+import android.util.SizeF;
+import android.graphics.ImageFormat;
import android.graphics.Point;
+import android.graphics.PointF;
import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.ColorSpaceTransform;
import android.hardware.camera2.Face;
+import android.hardware.camera2.MeteringRectangle;
import android.hardware.camera2.Rational;
+import android.hardware.camera2.RggbChannelVector;
import android.hardware.camera2.Size;
import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
+import android.hardware.camera2.params.ReprocessFormatsMap;
+import android.hardware.camera2.params.StreamConfiguration;
+import android.hardware.camera2.params.StreamConfigurationDuration;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.hardware.camera2.utils.TypeReference;
import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static com.android.mediaframeworktest.unit.ByteArrayHelpers.*;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
@@ -43,7 +57,6 @@
public class CameraMetadataTest extends junit.framework.TestCase {
CameraMetadataNative mMetadata;
- Parcel mParcel;
// Sections
static final int ANDROID_COLOR_CORRECTION = 0;
@@ -61,18 +74,17 @@
static final int ANDROID_CONTROL_AE_ANTIBANDING_MODE = ANDROID_CONTROL_START;
static final int ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION = ANDROID_CONTROL_START + 1;
+ // From graphics.h
+ private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
+
@Override
public void setUp() {
mMetadata = new CameraMetadataNative();
- mParcel = Parcel.obtain();
}
@Override
public void tearDown() throws Exception {
mMetadata = null;
-
- mParcel.recycle();
- mParcel = null;
}
@SmallTest
@@ -130,10 +142,14 @@
@SmallTest
public void testGetTypeFromTag() {
- assertEquals(TYPE_BYTE, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_MODE));
- assertEquals(TYPE_RATIONAL, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_TRANSFORM));
- assertEquals(TYPE_FLOAT, CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_GAINS));
- assertEquals(TYPE_BYTE, CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_ANTIBANDING_MODE));
+ assertEquals(TYPE_BYTE,
+ CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_MODE));
+ assertEquals(TYPE_RATIONAL,
+ CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_TRANSFORM));
+ assertEquals(TYPE_FLOAT,
+ CameraMetadataNative.getNativeType(ANDROID_COLOR_CORRECTION_GAINS));
+ assertEquals(TYPE_BYTE,
+ CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_ANTIBANDING_MODE));
assertEquals(TYPE_INT32,
CameraMetadataNative.getNativeType(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION));
@@ -215,35 +231,185 @@
assertEquals(1, mMetadata.getEntryCount());
}
+ /**
+ * Format an array into a string with the {@code badIndex} highlighted with {@code **}.
+ *
+ * <p>Numbers are printed as hexadecimal values.</p>
+ *
+ * <p>Example: {@code "[hello, **world**]"} for a {@code string[]},
+ * or a {@code "[**0xFF**, 0xFF]"} for a {@code int[]}.</p>
+ */
+ private static <T> String formatArray(T array, int badIndex) {
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("[");
+
+ int len = Array.getLength(array);
+ for (int i = 0; i < len; ++i) {
+
+ Object elem = Array.get(array, i);
+
+ if (i == badIndex) {
+ builder.append("**");
+ }
+
+ if (elem instanceof Number) {
+ builder.append(String.format("%x", elem));
+ } else {
+ builder.append(elem);
+ }
+
+ if (i == badIndex) {
+ builder.append("**");
+ }
+
+ if (i != len - 1) {
+ builder.append(", ");
+ }
+ }
+
+ builder.append("]");
+
+ return builder.toString();
+ }
+
private static <T> void assertArrayEquals(T expected, T actual) {
- assertEquals(Array.getLength(expected), Array.getLength(actual));
+ if (!expected.getClass().isArray() || !actual.getClass().isArray()) {
+ throw new IllegalArgumentException("expected, actual must both be arrays");
+ }
+
+ assertEquals("Array lengths must be equal",
+ Array.getLength(expected), Array.getLength(actual));
int len = Array.getLength(expected);
for (int i = 0; i < len; ++i) {
- assertEquals(Array.get(expected, i), Array.get(actual, i));
+
+ Object expectedElement = Array.get(expected, i);
+ Object actualElement = Array.get(actual, i);
+
+ if (!expectedElement.equals(actualElement)) {
+ fail(String.format(
+ "element %d in array was not equal (expected %s, actual %s). "
+ + "Arrays were: (expected %s, actual %s).",
+ i, expectedElement, actualElement,
+ formatArray(expected, i),
+ formatArray(actual, i)));
+ }
}
}
- private <T> void checkKeyGetAndSet(String keyStr, Class<T> type, T value) {
- assertFalse("Use checkKeyGetAndSetArray to compare array Keys", type.isArray());
+ private static <T, T2> void assertArrayContains(T needle, T2 array) {
+ if (!array.getClass().isArray()) {
+ throw new IllegalArgumentException("actual must be array");
+ }
- Key<T> key = new Key<T>(keyStr, type);
+ int len = Array.getLength(array);
+ for (int i = 0; i < len; ++i) {
+
+ Object actualElement = Array.get(array, i);
+
+ if (needle.equals(actualElement)) {
+ return;
+ }
+ }
+
+ fail(String.format(
+ "could not find element in array (needle %s). "
+ + "Array was: %s.",
+ needle,
+ formatArray(array, len)));
+ }
+
+ private <T> void checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected,
+ boolean reuse) {
+ Key<T> key = new Key<T>(keyStr, typeToken);
assertNull(mMetadata.get(key));
mMetadata.set(key, null);
assertNull(mMetadata.get(key));
- mMetadata.set(key, value);
+ mMetadata.set(key, expected);
T actual = mMetadata.get(key);
- assertEquals(value, actual);
+
+ if (typeToken.getRawType().isArray()) {
+ assertArrayEquals(expected, actual);
+ } else {
+ assertEquals(expected, actual);
+ }
+
+ if (reuse) {
+ // reset the key incase we want to use it again
+ mMetadata.set(key, null);
+ }
}
- private <T> void checkKeyGetAndSetArray(String keyStr, Class<T> type, T value) {
- assertTrue(type.isArray());
+ private <T> void checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected) {
+ checkKeyGetAndSet(keyStr, typeToken, expected, /*reuse*/false);
+ }
- Key<T> key = new Key<T>(keyStr, type);
+ private <T> void checkKeyGetAndSet(String keyStr, Class<T> type, T expected) {
+ checkKeyGetAndSet(keyStr, TypeReference.createSpecializedTypeReference(type), expected);
+ }
+
+ /**
+ * Ensure that the data survives a marshal/unmarshal round-trip;
+ * it must also be equal to the {@code expectedNative} byte array.
+ *
+ * <p>As a side-effect, the metadata value corresponding to the key is now set to
+ * {@code expected}.</p>
+ *
+ * @return key created with {@code keyName} and {@code T}
+ */
+ private <T> Key<T> checkKeyMarshal(String keyName, TypeReference<T> typeReference,
+ T expected, byte[] expectedNative) {
+ Key<T> key = new Key<T>(keyName, typeReference);
+
+ mMetadata.set(key, null);
assertNull(mMetadata.get(key));
- mMetadata.set(key, value);
- assertArrayEquals(value, mMetadata.get(key));
+
+ // Write managed value -> make sure native bytes are what we expect
+ mMetadata.set(key, expected);
+
+ byte[] actualValues = mMetadata.readValues(key.getTag());
+ assertArrayEquals(expectedNative, actualValues);
+
+ // Write managed value -> make sure read-out managed value is what we expect
+ T actual = mMetadata.get(key);
+
+ if (typeReference.getRawType().isArray()) {
+ assertArrayEquals(expected, actual);
+ } else {
+ assertEquals(expected, actual);
+ }
+
+ // Write native bytes -> make sure read-out managed value is what we expect
+ mMetadata.writeValues(key.getTag(), expectedNative);
+ actual = mMetadata.get(key);
+
+ if (typeReference.getRawType().isArray()) {
+ assertArrayEquals(expected, actual);
+ } else {
+ assertEquals(expected, actual);
+ }
+
+ return key;
+ }
+
+ /**
+ * Ensure that the data survives a marshal/unmarshal round-trip;
+ * it must also be equal to the {@code expectedNative} byte array.
+ *
+ * <p>As a side-effect,
+ * the metadata value corresponding to the key is now set to {@code expected}.</p>
+ *
+ * @return key created with {@code keyName} and {@code T}
+ */
+ private <T> Key<T> checkKeyMarshal(String keyName, T expected, byte[] expectedNative) {
+ @SuppressWarnings("unchecked")
+ Class<T> expectedClass = (Class<T>) expected.getClass();
+ return checkKeyMarshal(keyName,
+ TypeReference.createSpecializedTypeReference(expectedClass),
+ expected,
+ expectedNative);
}
@SmallTest
@@ -280,36 +446,36 @@
@SmallTest
public void testReadWritePrimitiveArray() {
// int32 (n)
- checkKeyGetAndSetArray("android.sensor.info.sensitivityRange", int[].class,
+ checkKeyGetAndSet("android.sensor.info.sensitivityRange", int[].class,
new int[] {
0xC0FFEE, 0xDEADF00D
});
// byte (n)
- checkKeyGetAndSetArray("android.statistics.faceScores", byte[].class, new byte[] {
+ checkKeyGetAndSet("android.statistics.faceScores", byte[].class, new byte[] {
1, 2, 3, 4
});
// int64 (n)
- checkKeyGetAndSetArray("android.scaler.availableProcessedMinDurations", long[].class,
+ checkKeyGetAndSet("android.scaler.availableProcessedMinDurations", long[].class,
new long[] {
0xABCD12345678FFFFL, 0x1234ABCD5678FFFFL, 0xFFFF12345678ABCDL
});
// float (n)
- checkKeyGetAndSetArray("android.lens.info.availableApertures", float[].class,
+ checkKeyGetAndSet("android.lens.info.availableApertures", float[].class,
new float[] {
Float.MAX_VALUE, Float.MIN_NORMAL, Float.MIN_VALUE
});
// double (n) -- in particular double x 3
- checkKeyGetAndSetArray("android.jpeg.gpsCoordinates", double[].class,
+ checkKeyGetAndSet("android.jpeg.gpsCoordinates", double[].class,
new double[] {
Double.MAX_VALUE, Double.MIN_NORMAL, Double.MIN_VALUE
});
// rational (n) -- in particular rational x 9
- checkKeyGetAndSetArray("android.sensor.calibrationTransform1", Rational[].class,
+ checkKeyGetAndSet("android.sensor.calibrationTransform1", Rational[].class,
new Rational[] {
new Rational(1, 2), new Rational(3, 4), new Rational(5, 6),
new Rational(7, 8), new Rational(9, 10), new Rational(10, 11),
@@ -321,13 +487,12 @@
*/
// bool (n) -- with TYPE_BYTE
- checkKeyGetAndSetArray("android.control.aeLock", boolean[].class, new boolean[] {
+ checkKeyGetAndSet("android.control.aeLock", boolean[].class, new boolean[] {
true, false, true
});
-
// integer (n) -- with TYPE_BYTE
- checkKeyGetAndSetArray("android.control.aeAvailableModes", int[].class, new int[] {
+ checkKeyGetAndSet("android.control.aeAvailableModes", int[].class, new int[] {
1, 2, 3, 4
});
}
@@ -345,7 +510,6 @@
AUTO
}
- // TODO: special values for the enum.
private enum AvailableFormat {
RAW_SENSOR,
YV12,
@@ -366,7 +530,7 @@
AeAntibandingMode.AUTO);
// byte (n)
- checkKeyGetAndSetArray("android.control.aeAvailableAntibandingModes",
+ checkKeyGetAndSet("android.control.aeAvailableAntibandingModes",
AeAntibandingMode[].class, new AeAntibandingMode[] {
AeAntibandingMode.OFF, AeAntibandingMode._50HZ, AeAntibandingMode._60HZ,
AeAntibandingMode.AUTO
@@ -376,7 +540,7 @@
* Stranger cases that don't use byte enums
*/
// int (n)
- checkKeyGetAndSetArray("android.scaler.availableFormats", AvailableFormat[].class,
+ checkKeyGetAndSet("android.scaler.availableFormats", AvailableFormat[].class,
new AvailableFormat[] {
AvailableFormat.RAW_SENSOR,
AvailableFormat.YV12,
@@ -389,7 +553,7 @@
@SmallTest
public void testReadWriteEnumWithCustomValues() {
- CameraMetadataNative.registerEnumValues(AeAntibandingMode.class, new int[] {
+ MarshalQueryableEnum.registerEnumValues(AeAntibandingMode.class, new int[] {
0,
10,
20,
@@ -401,15 +565,12 @@
AeAntibandingMode.AUTO);
// byte (n)
- checkKeyGetAndSetArray("android.control.aeAvailableAntibandingModes",
+ checkKeyGetAndSet("android.control.aeAvailableAntibandingModes",
AeAntibandingMode[].class, new AeAntibandingMode[] {
AeAntibandingMode.OFF, AeAntibandingMode._50HZ, AeAntibandingMode._60HZ,
AeAntibandingMode.AUTO
});
- Key<AeAntibandingMode[]> aeAntibandingModeKey =
- new Key<AeAntibandingMode[]>("android.control.aeAvailableAntibandingModes",
- AeAntibandingMode[].class);
byte[] aeAntibandingModeValues = mMetadata.readValues(CameraMetadataNative
.getTag("android.control.aeAvailableAntibandingModes"));
byte[] expectedValues = new byte[] { 0, 10, 20, 30 };
@@ -420,7 +581,7 @@
* Stranger cases that don't use byte enums
*/
// int (n)
- CameraMetadataNative.registerEnumValues(AvailableFormat.class, new int[] {
+ MarshalQueryableEnum.registerEnumValues(AvailableFormat.class, new int[] {
0x20,
0x32315659,
0x11,
@@ -429,7 +590,7 @@
0x21,
});
- checkKeyGetAndSetArray("android.scaler.availableFormats", AvailableFormat[].class,
+ checkKeyGetAndSet("android.scaler.availableFormats", AvailableFormat[].class,
new AvailableFormat[] {
AvailableFormat.RAW_SENSOR,
AvailableFormat.YV12,
@@ -466,7 +627,7 @@
checkKeyGetAndSet("android.jpeg.thumbnailSize", Size.class, new Size(123, 456));
// int32 x 2 x n
- checkKeyGetAndSetArray("android.scaler.availableJpegSizes", Size[].class, new Size[] {
+ checkKeyGetAndSet("android.scaler.availableJpegSizes", Size[].class, new Size[] {
new Size(123, 456),
new Size(0xDEAD, 0xF00D),
new Size(0xF00, 0xB00)
@@ -474,16 +635,247 @@
}
@SmallTest
- public void testReadWriteRectangle() {
+ public void testReadWriteRggbChannelVector() {
// int32 x n
- checkKeyGetAndSet("android.scaler.cropRegion", Rect.class, new Rect(10, 11, 1280, 1024));
+ checkKeyMarshal("android.colorCorrection.gains",
+ new RggbChannelVector(1.0f, 2.1f, 3.2f, 4.5f),
+ toByteArray(1.0f, 2.1f, 3.2f, 4.5f));
+
+ // int32 x 2 x n [pretend; actual is not array]
+ checkKeyMarshal("android.colorCorrection.gains",
+ new RggbChannelVector[] {
+ new RggbChannelVector(1.0f, 2.0f, 3.0f, 4.0f),
+ new RggbChannelVector(9.0f, 8.0f, 7.0f, 6.0f),
+ new RggbChannelVector(1.3f, 5.5f, 2.4f, 6.7f),
+ }, toByteArray(
+ 1.0f, 2.0f, 3.0f, 4.0f,
+ 9.0f, 8.0f, 7.0f, 6.0f,
+ 1.3f, 5.5f, 2.4f, 6.7f
+ ));
+ }
+
+ @SmallTest
+ public void testReadWriteSizeF() {
+ // int32 x n
+ checkKeyMarshal("android.sensor.info.physicalSize",
+ new SizeF(123f, 456f),
+ toByteArray(123f, 456f));
// int32 x 2 x n
- checkKeyGetAndSetArray("android.statistics.faceRectangles", Rect[].class, new Rect[] {
+ checkKeyMarshal("android.sensor.info.physicalSize",
+ new SizeF[] {
+ new SizeF(123f, 456f),
+ new SizeF(1.234f, 4.567f),
+ new SizeF(999.0f, 555.0f)
+ },
+ toByteArray(
+ 123f, 456f,
+ 1.234f, 4.567f,
+ 999.0f, 555.0f)
+ );
+ }
+
+ @SmallTest
+ public void testReadWriteRectangle() {
+ // int32 x n
+ checkKeyMarshal("android.scaler.cropRegion",
+ // x1, y1, x2, y2
+ new Rect(10, 11, 1280, 1024),
+ // x, y, width, height
+ toByteArray(10, 11, 1280 - 10, 1024 - 11));
+
+ // int32 x 2 x n [actually not array, but we pretend it is]
+ checkKeyMarshal("android.scaler.cropRegion", new Rect[] {
new Rect(110, 111, 11280, 11024),
new Rect(210, 111, 21280, 21024),
new Rect(310, 111, 31280, 31024)
- });
+ }, toByteArray(
+ 110, 111, 11280 - 110, 11024 - 111,
+ 210, 111, 21280 - 210, 21024 - 111,
+ 310, 111, 31280 - 310, 31024 - 111
+ ));
+ }
+
+ @SmallTest
+ public void testReadWriteMeteringRectangle() {
+ // int32 x 5 x area_count [but we pretend it's a single element]
+ checkKeyMarshal("android.control.aeRegions",
+ new MeteringRectangle(/*x*/1, /*y*/2, /*width*/100, /*height*/200, /*weight*/5),
+ /* xmin, ymin, xmax, ymax, weight */
+ toByteArray(1, 2, 1 + 100, 2 + 200, 5));
+
+ // int32 x 5 x area_count
+ checkKeyMarshal("android.control.afRegions",
+ new MeteringRectangle[] {
+ new MeteringRectangle(/*x*/5, /*y*/6, /*width*/123, /*height*/456, /*weight*/7),
+ new MeteringRectangle(/*x*/7, /*y*/8, /*width*/456, /*height*/999, /*weight*/6),
+ new MeteringRectangle(/*x*/1, /*y*/2, /*width*/100, /*height*/200, /*weight*/5)
+ },
+ toByteArray(
+ 5, 6, 5 + 123, 6 + 456, 7,
+ 7, 8, 7 + 456, 8 + 999, 6,
+ 1, 2, 1 + 100, 2 + 200, 5
+ ));
+ }
+
+ @SmallTest
+ public void testReadWriteColorSpaceTransform() {
+ // rational x 3 x 3
+ checkKeyMarshal("android.colorCorrection.transform",
+ new ColorSpaceTransform(new Rational[] {
+ new Rational(1, 2), new Rational(3, 4), new Rational(5, 6),
+ new Rational(7, 8), new Rational(8, 9), new Rational(10, 11),
+ new Rational(1, 5), new Rational(2, 8), new Rational(3, 9),
+ }),
+ toByteArray(
+ 1, 2, 3, 4, 5, 6,
+ 7, 8, 8, 9, 10, 11,
+ 1, 5, 2, 8, 3, 9));
+ }
+
+ @SmallTest
+ public void testReadWritePoint() {
+ // int32 x 2 [actually 'x n' but pretend it's a single value for now]
+ checkKeyMarshal("android.statistics.hotPixelMap",
+ new Point(1, 2),
+ toByteArray(1, 2));
+
+ // int32 x 2 x samples
+ checkKeyMarshal("android.statistics.hotPixelMap",
+ new Point[] {
+ new Point(1, 2),
+ new Point(3, 4),
+ new Point(5, 6),
+ new Point(7, 8),
+ },
+ toByteArray(
+ 1, 2,
+ 3, 4,
+ 5, 6,
+ 7, 8)
+ );
+ }
+
+ @SmallTest
+ public void testReadWritePointF() {
+ // float x 2 [actually 'x samples' but pretend it's a single value for now]
+ checkKeyMarshal(
+ "android.sensor.profileToneCurve",
+ new PointF(1.0f, 2.0f),
+ toByteArray(1.0f, 2.0f));
+
+ // float x 2 x samples
+ checkKeyMarshal("android.sensor.profileToneCurve",
+ new PointF[] {
+ new PointF(1.0f, 2.0f),
+ new PointF(3.0f, 4.0f),
+ new PointF(5.0f, 6.0f),
+ new PointF(7.0f, 8.0f),
+ },
+ toByteArray(
+ 1.0f, 2.0f,
+ 3.0f, 4.0f,
+ 5.0f, 6.0f,
+ 7.0f, 8.0f));
+ }
+
+ @SmallTest
+ public void testReadWriteRange() {
+ // int32 x 2
+ checkKeyMarshal("android.control.aeTargetFpsRange",
+ new TypeReference<Range<Integer>>() {{ }},
+ Range.create(123, 456),
+ toByteArray(123, 456));
+
+ // int64 x 2
+ checkKeyMarshal("android.sensor.info.exposureTimeRange",
+ new TypeReference<Range<Long>>() {{ }},
+ Range.create(123L, 456L),
+ toByteArray(123L, 456L));
+ }
+
+ @SmallTest
+ public void testReadWriteStreamConfiguration() {
+ // int32 x 4 x n
+ checkKeyMarshal("android.scaler.availableStreamConfigurations",
+ new StreamConfiguration[] {
+ new StreamConfiguration(ImageFormat.YUV_420_888, 640, 480, /*input*/false),
+ new StreamConfiguration(ImageFormat.RGB_565, 320, 240, /*input*/true),
+ },
+ toByteArray(
+ ImageFormat.YUV_420_888, 640, 480, /*input*/0,
+ ImageFormat.RGB_565, 320, 240, /*input*/1)
+ );
+ }
+
+ @SmallTest
+ public void testReadWriteStreamConfigurationDuration() {
+ // Avoid sign extending ints when converting to a long
+ final long MASK_UNSIGNED_INT = 0x00000000ffffffffL;
+
+ // int64 x 4 x n
+ checkKeyMarshal("android.scaler.availableMinFrameDurations",
+ new StreamConfigurationDuration[] {
+ new StreamConfigurationDuration(
+ ImageFormat.YUV_420_888, 640, 480, /*duration*/123L),
+ new StreamConfigurationDuration(
+ ImageFormat.RGB_565, 320, 240, /*duration*/345L),
+ },
+ toByteArray(
+ ImageFormat.YUV_420_888 & MASK_UNSIGNED_INT, 640L, 480L, /*duration*/123L,
+ ImageFormat.RGB_565 & MASK_UNSIGNED_INT, 320L, 240L, /*duration*/345L)
+ );
+ }
+
+
+ @SmallTest
+ public void testReadWriteReprocessFormatsMap() {
+
+ // final int RAW_OPAQUE = 0x24; // TODO: add RAW_OPAQUE to ImageFormat
+ final int RAW16 = ImageFormat.RAW_SENSOR;
+ final int YUV_420_888 = ImageFormat.YUV_420_888;
+ final int BLOB = 0x21;
+
+ // TODO: also test HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED as an output
+ int[] contents = new int[] {
+ YUV_420_888, 3, YUV_420_888, ImageFormat.NV21, BLOB,
+ RAW16, 2, YUV_420_888, BLOB,
+
+ };
+
+ // int32 x n
+ Key<ReprocessFormatsMap> key = new Key<ReprocessFormatsMap>(
+ "android.scaler.availableInputOutputFormatsMap", ReprocessFormatsMap.class);
+ mMetadata.writeValues(key.getTag(), toByteArray(contents));
+
+ ReprocessFormatsMap map = mMetadata.get(key);
+
+ /*
+ * Make sure the inputs/outputs were what we expected.
+ * - Use public image format constants here.
+ */
+
+ int[] expectedInputs = new int[] {
+ YUV_420_888, RAW16
+ };
+ assertArrayEquals(expectedInputs, map.getInputs());
+
+ int[] expectedYuvOutputs = new int[] {
+ YUV_420_888, ImageFormat.NV21, ImageFormat.JPEG,
+ };
+ assertArrayEquals(expectedYuvOutputs, map.getOutputs(ImageFormat.YUV_420_888));
+
+ int[] expectedRaw16Outputs = new int[] {
+ YUV_420_888, ImageFormat.JPEG,
+ };
+ assertArrayEquals(expectedRaw16Outputs, map.getOutputs(ImageFormat.RAW_SENSOR));
+
+ // Finally, do a round-trip check as a sanity
+ checkKeyMarshal(
+ "android.scaler.availableInputOutputFormatsMap",
+ new ReprocessFormatsMap(contents),
+ toByteArray(contents)
+ );
}
@SmallTest
@@ -525,10 +917,6 @@
assertArrayEquals(gpsBytes, actualBytes2);
}
- <T> void compareGeneric(T expected, T actual) {
- assertEquals(expected, actual);
- }
-
@SmallTest
public void testReadWriteOverride() {
//
@@ -558,68 +946,6 @@
expectedIntValues, availableFormatTag);
//
- // android.scaler.availableStreamConfigurations (int x n x 4 array)
- //
- final int OUTPUT = CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT;
- int[] availableStreamConfigs = new int[] {
- 0x20, 3280, 2464, OUTPUT, // RAW16
- 0x23, 3264, 2448, OUTPUT, // YCbCr_420_888
- 0x23, 3200, 2400, OUTPUT, // YCbCr_420_888
- 0x100, 3264, 2448, OUTPUT, // ImageFormat.JPEG
- 0x100, 3200, 2400, OUTPUT, // ImageFormat.JPEG
- 0x100, 2592, 1944, OUTPUT, // ImageFormat.JPEG
- 0x100, 2048, 1536, OUTPUT, // ImageFormat.JPEG
- 0x100, 1920, 1080, OUTPUT // ImageFormat.JPEG
- };
- int[] expectedAvailableStreamConfigs = new int[] {
- 0x20, 3280, 2464, OUTPUT, // RAW16
- 0x23, 3264, 2448, OUTPUT, // YCbCr_420_888
- 0x23, 3200, 2400, OUTPUT, // YCbCr_420_888
- 0x21, 3264, 2448, OUTPUT, // BLOB
- 0x21, 3200, 2400, OUTPUT, // BLOB
- 0x21, 2592, 1944, OUTPUT, // BLOB
- 0x21, 2048, 1536, OUTPUT, // BLOB
- 0x21, 1920, 1080, OUTPUT // BLOB
- };
- int availableStreamConfigTag =
- CameraMetadataNative.getTag("android.scaler.availableStreamConfigurations");
-
- Key<int[]> configKey = CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
- validateArrayMetadataReadWriteOverride(configKey, availableStreamConfigs,
- expectedAvailableStreamConfigs, availableStreamConfigTag);
-
- //
- // android.scaler.availableMinFrameDurations (int x n x 4 array)
-
- //
- long[] availableMinDurations = new long[] {
- 0x20, 3280, 2464, 33333336, // RAW16
- 0x23, 3264, 2448, 33333336, // YCbCr_420_888
- 0x23, 3200, 2400, 33333336, // YCbCr_420_888
- 0x100, 3264, 2448, 33333336, // ImageFormat.JPEG
- 0x100, 3200, 2400, 33333336, // ImageFormat.JPEG
- 0x100, 2592, 1944, 33333336, // ImageFormat.JPEG
- 0x100, 2048, 1536, 33333336, // ImageFormat.JPEG
- 0x100, 1920, 1080, 33333336 // ImageFormat.JPEG
- };
- long[] expectedAvailableMinDurations = new long[] {
- 0x20, 3280, 2464, 33333336, // RAW16
- 0x23, 3264, 2448, 33333336, // YCbCr_420_888
- 0x23, 3200, 2400, 33333336, // YCbCr_420_888
- 0x21, 3264, 2448, 33333336, // BLOB
- 0x21, 3200, 2400, 33333336, // BLOB
- 0x21, 2592, 1944, 33333336, // BLOB
- 0x21, 2048, 1536, 33333336, // BLOB
- 0x21, 1920, 1080, 33333336 // BLOB
- };
- int availableMinDurationsTag =
- CameraMetadataNative.getTag("android.scaler.availableMinFrameDurations");
-
- Key<long[]> durationKey = CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
- validateArrayMetadataReadWriteOverride(durationKey, availableMinDurations,
- expectedAvailableMinDurations, availableMinDurationsTag);
-
- //
// android.statistics.faces (Face x n array)
//
int[] expectedFaceIds = new int[] {1, 2, 3, 4, 5};
@@ -684,14 +1010,238 @@
}
/**
+ * Set the raw native value of the available stream configurations; ensure that
+ * the read-out managed value is consistent with what we write in.
+ */
+ @SmallTest
+ public void testOverrideStreamConfigurationMap() {
+
+ /*
+ * First, write all the raw values:
+ * - availableStreamConfigurations
+ * - availableMinFrameDurations
+ * - availableStallDurations
+ *
+ * Then, read this out as a synthetic multi-key 'streamConfigurationMap'
+ *
+ * Finally, validate that the map was unmarshaled correctly
+ * and is converting the internal formats to public formats properly.
+ */
+
+ //
+ // android.scaler.availableStreamConfigurations (int x n x 4 array)
+ //
+ final int OUTPUT = 0;
+ final int INPUT = 1;
+ int[] rawAvailableStreamConfigs = new int[] {
+ 0x20, 3280, 2464, OUTPUT, // RAW16
+ 0x23, 3264, 2448, OUTPUT, // YCbCr_420_888
+ 0x23, 3200, 2400, OUTPUT, // YCbCr_420_888
+ 0x21, 3264, 2448, OUTPUT, // BLOB
+ 0x21, 3200, 2400, OUTPUT, // BLOB
+ 0x21, 2592, 1944, OUTPUT, // BLOB
+ 0x21, 2048, 1536, OUTPUT, // BLOB
+ 0x21, 1920, 1080, OUTPUT, // BLOB
+ 0x22, 640, 480, OUTPUT, // IMPLEMENTATION_DEFINED
+ 0x20, 320, 240, INPUT, // RAW16
+ };
+ Key<StreamConfiguration[]> configKey =
+ CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
+ mMetadata.writeValues(configKey.getTag(),
+ toByteArray(rawAvailableStreamConfigs));
+
+ //
+ // android.scaler.availableMinFrameDurations (int x n x 4 array)
+ //
+ long[] expectedAvailableMinDurations = new long[] {
+ 0x20, 3280, 2464, 33333331, // RAW16
+ 0x23, 3264, 2448, 33333332, // YCbCr_420_888
+ 0x23, 3200, 2400, 33333333, // YCbCr_420_888
+ 0x100, 3264, 2448, 33333334, // ImageFormat.JPEG
+ 0x100, 3200, 2400, 33333335, // ImageFormat.JPEG
+ 0x100, 2592, 1944, 33333336, // ImageFormat.JPEG
+ 0x100, 2048, 1536, 33333337, // ImageFormat.JPEG
+ 0x100, 1920, 1080, 33333338 // ImageFormat.JPEG
+ };
+ long[] rawAvailableMinDurations = new long[] {
+ 0x20, 3280, 2464, 33333331, // RAW16
+ 0x23, 3264, 2448, 33333332, // YCbCr_420_888
+ 0x23, 3200, 2400, 33333333, // YCbCr_420_888
+ 0x21, 3264, 2448, 33333334, // BLOB
+ 0x21, 3200, 2400, 33333335, // BLOB
+ 0x21, 2592, 1944, 33333336, // BLOB
+ 0x21, 2048, 1536, 33333337, // BLOB
+ 0x21, 1920, 1080, 33333338 // BLOB
+ };
+ Key<StreamConfigurationDuration[]> durationKey =
+ CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
+ mMetadata.writeValues(durationKey.getTag(),
+ toByteArray(rawAvailableMinDurations));
+
+ //
+ // android.scaler.availableStallDurations (int x n x 4 array)
+ //
+ long[] expectedAvailableStallDurations = new long[] {
+ 0x20, 3280, 2464, 0, // RAW16
+ 0x23, 3264, 2448, 0, // YCbCr_420_888
+ 0x23, 3200, 2400, 0, // YCbCr_420_888
+ 0x100, 3264, 2448, 33333334, // ImageFormat.JPEG
+ 0x100, 3200, 2400, 33333335, // ImageFormat.JPEG
+ 0x100, 2592, 1944, 33333336, // ImageFormat.JPEG
+ 0x100, 2048, 1536, 33333337, // ImageFormat.JPEG
+ 0x100, 1920, 1080, 33333338 // ImageFormat.JPEG
+ };
+ // Note: RAW16 and YUV_420_888 omitted intentionally; omitted values should default to 0
+ long[] rawAvailableStallDurations = new long[] {
+ 0x21, 3264, 2448, 33333334, // BLOB
+ 0x21, 3200, 2400, 33333335, // BLOB
+ 0x21, 2592, 1944, 33333336, // BLOB
+ 0x21, 2048, 1536, 33333337, // BLOB
+ 0x21, 1920, 1080, 33333338 // BLOB
+ };
+ Key<StreamConfigurationDuration[]> stallDurationKey =
+ CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS;
+ mMetadata.writeValues(stallDurationKey.getTag(),
+ toByteArray(rawAvailableStallDurations));
+
+ //
+ // android.scaler.streamConfigurationMap (synthetic as StreamConfigurationMap)
+ //
+ StreamConfigurationMap streamConfigMap = mMetadata.get(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+ // Inputs
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, ImageFormat.RAW_SENSOR, 320, 240, /*output*/false);
+
+ // Outputs
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 640, 480, /*output*/true);
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, ImageFormat.JPEG, 1920, 1080, /*output*/true);
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, ImageFormat.JPEG, 2048, 1536, /*output*/true);
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, ImageFormat.JPEG, 2592, 1944, /*output*/true);
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, ImageFormat.JPEG, 3200, 2400, /*output*/true);
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, ImageFormat.YUV_420_888, 3200, 2400, /*output*/true);
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, ImageFormat.YUV_420_888, 3264, 2448, /*output*/true);
+ checkStreamConfigurationMapByFormatSize(
+ streamConfigMap, ImageFormat.RAW_SENSOR, 3280, 2464, /*output*/true);
+
+ // Min Frame Durations
+
+ final int DURATION_TUPLE_SIZE = 4;
+ for (int i = 0; i < expectedAvailableMinDurations.length; i += DURATION_TUPLE_SIZE) {
+ checkStreamConfigurationMapDurationByFormatSize(
+ streamConfigMap,
+ (int)expectedAvailableMinDurations[i],
+ (int)expectedAvailableMinDurations[i+1],
+ (int)expectedAvailableMinDurations[i+2],
+ Duration.MinFrame,
+ expectedAvailableMinDurations[i+3]);
+ }
+
+ // Stall Frame Durations
+
+ for (int i = 0; i < expectedAvailableStallDurations.length; i += DURATION_TUPLE_SIZE) {
+ checkStreamConfigurationMapDurationByFormatSize(
+ streamConfigMap,
+ (int)expectedAvailableStallDurations[i],
+ (int)expectedAvailableStallDurations[i+1],
+ (int)expectedAvailableStallDurations[i+2],
+ Duration.Stall,
+ expectedAvailableStallDurations[i+3]);
+ }
+ }
+
+ private static void checkStreamConfigurationMapByFormatSize(StreamConfigurationMap configMap,
+ int format, int width, int height,
+ boolean output) {
+
+ /** arbitrary class for which StreamConfigurationMap#isOutputSupportedFor(Class) is true */
+ final Class<?> IMPLEMENTATION_DEFINED_OUTPUT_CLASS = SurfaceTexture.class;
+
+ android.util.Size[] sizes;
+ int[] formats;
+
+ if (output) {
+ if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ sizes = configMap.getOutputSizes(IMPLEMENTATION_DEFINED_OUTPUT_CLASS);
+ // in this case the 'is output format supported' is vacuously true
+ formats = new int[] { HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED };
+ } else {
+ sizes = configMap.getOutputSizes(format);
+ formats = configMap.getOutputFormats();
+ assertTrue("Format must be supported by stream configuration map",
+ configMap.isOutputSupportedFor(format));
+ }
+ } else {
+ // NOTE: No function to do input sizes from IMPL_DEFINED, so it would just fail for that
+ sizes = configMap.getInputSizes(format);
+ formats = configMap.getInputFormats();
+ }
+
+ android.util.Size expectedSize = new android.util.Size(width, height);
+
+ assertArrayContains(format, formats);
+ assertArrayContains(expectedSize, sizes);
+ }
+
+ private enum Duration {
+ MinFrame,
+ Stall
+ }
+
+ private static void checkStreamConfigurationMapDurationByFormatSize(
+ StreamConfigurationMap configMap,
+ int format, int width, int height, Duration durationKind, long expectedDuration) {
+
+ /** arbitrary class for which StreamConfigurationMap#isOutputSupportedFor(Class) is true */
+ final Class<?> IMPLEMENTATION_DEFINED_OUTPUT_CLASS = SurfaceTexture.class;
+
+ long actualDuration;
+
+ android.util.Size size = new android.util.Size(width, height);
+ switch (durationKind) {
+ case MinFrame:
+ if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ actualDuration = configMap.getOutputMinFrameDuration(
+ IMPLEMENTATION_DEFINED_OUTPUT_CLASS, size);
+ } else {
+ actualDuration = configMap.getOutputMinFrameDuration(format, size);
+ }
+
+ break;
+ case Stall:
+ if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ actualDuration = configMap.getOutputStallDuration(
+ IMPLEMENTATION_DEFINED_OUTPUT_CLASS, size);
+ } else {
+ actualDuration = configMap.getOutputStallDuration(format, size);
+ }
+
+ break;
+ default:
+ throw new AssertionError();
+ }
+
+ assertEquals("Expected " + durationKind + " to match actual value", expectedDuration,
+ actualDuration);
+ }
+
+ /**
* Validate metadata array tag read/write override.
*
* <p>Only support long and int array for now, can be easily extend to support other
* primitive arrays.</p>
*/
- private <T> void validateArrayMetadataReadWriteOverride(Key<T> key, T writeValues,
- T readValues, int tag) {
- Class<T> type = key.getType();
+ private <T> void validateArrayMetadataReadWriteOverride(Key<T> key, T expectedWriteValues,
+ T expectedReadValues, int tag) {
+ Class<?> type = expectedWriteValues.getClass();
if (!type.isArray()) {
throw new IllegalArgumentException("This function expects an key with array type");
} else if (type != int[].class && type != long[].class) {
@@ -699,13 +1249,13 @@
}
// Write
- mMetadata.set(key, writeValues);
+ mMetadata.set(key, expectedWriteValues);
byte[] readOutValues = mMetadata.readValues(tag);
ByteBuffer bf = ByteBuffer.wrap(readOutValues).order(ByteOrder.nativeOrder());
- int readValuesLength = Array.getLength(readValues);
+ int readValuesLength = Array.getLength(expectedReadValues);
int readValuesNumBytes = readValuesLength * 4;
if (type == long[].class) {
readValuesNumBytes = readValuesLength * 8;
@@ -714,9 +1264,9 @@
assertEquals(readValuesNumBytes, readOutValues.length);
for (int i = 0; i < readValuesLength; ++i) {
if (type == int[].class) {
- assertEquals(Array.getInt(readValues, i), bf.getInt());
+ assertEquals(Array.getInt(expectedReadValues, i), bf.getInt());
} else if (type == long[].class) {
- assertEquals(Array.getLong(readValues, i), bf.getLong());
+ assertEquals(Array.getLong(expectedReadValues, i), bf.getLong());
}
}
@@ -726,15 +1276,31 @@
ByteBuffer.wrap(readOutValuesAsByteArray).order(ByteOrder.nativeOrder());
for (int i = 0; i < readValuesLength; ++i) {
if (type == int[].class) {
- readOutValuesByteBuffer.putInt(Array.getInt(readValues, i));
+ readOutValuesByteBuffer.putInt(Array.getInt(expectedReadValues, i));
} else if (type == long[].class) {
- readOutValuesByteBuffer.putLong(Array.getLong(readValues, i));
+ readOutValuesByteBuffer.putLong(Array.getLong(expectedReadValues, i));
}
}
mMetadata.writeValues(tag, readOutValuesAsByteArray);
T result = mMetadata.get(key);
assertNotNull(key.getName() + " result shouldn't be null", result);
- assertArrayEquals(writeValues, result);
+ assertArrayEquals(expectedWriteValues, result);
+ }
+
+ // TODO: move somewhere else
+ @SmallTest
+ public void testToByteArray() {
+ assertArrayEquals(new byte[] { 5, 0, 0, 0, 6, 0, 0, 0 },
+ toByteArray(5, 6));
+ assertArrayEquals(new byte[] { 5, 0, 6, 0, },
+ toByteArray((short)5, (short)6));
+ assertArrayEquals(new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
+ (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,},
+ toByteArray(~0, ~0));
+
+ assertArrayEquals(new byte[] { (byte)0xAB, (byte)0xFF, 0, 0,
+ 0x0D, (byte)0xF0, (byte)0xAD, (byte)0xDE },
+ toByteArray(0xFFAB, 0xDEADF00D));
}
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsTypeReferenceTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsTypeReferenceTest.java
new file mode 100644
index 0000000..1b765ea
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsTypeReferenceTest.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mediaframeworktest.unit;
+
+import static android.hardware.camera2.utils.TypeReference.*;
+
+import android.hardware.camera2.utils.TypeReference;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import java.lang.reflect.Type;
+import java.util.List;
+
+public class CameraUtilsTypeReferenceTest extends junit.framework.TestCase {
+ private static final String TAG = CameraUtilsTypeReferenceTest.class.getSimpleName();
+ private static final boolean VERBOSE = false;
+
+ private class RegularClass {}
+ private class SubClass extends RegularClass {}
+
+ private class GenericClass<T> {}
+ private class SubGenericClass<T> extends GenericClass<T> {}
+
+ private class SpecificClass extends GenericClass<Integer> {}
+
+ private interface RegularInterface {}
+ private interface GenericInterface<T> {}
+ private interface GenericInterface2<T> {}
+
+ private class ImplementsRegularInterface implements RegularInterface {}
+ private class ImplementsGenericInterface<T> implements GenericInterface<T> {}
+ private class Implements2GenericInterface<T>
+ implements GenericInterface<Integer>, GenericInterface2<T> {}
+
+ private class GenericOuterClass<T> {
+ class GenericInnerClass {
+ @SuppressWarnings("unused")
+ T field;
+ }
+ }
+
+ private static void assertContainsTypeVariable(Type type) {
+ assertTrue(type.toString() + " was expected to have a type variable, but it didn't",
+ containsTypeVariable(type));
+ }
+
+ private static void assertLacksTypeVariable(Type type) {
+ assertFalse(type.toString() + " was expected to *not* have a type variable, but it did",
+ containsTypeVariable(type));
+ }
+
+ /*
+ * Only test classes and interfaces. Other types are not tested (e.g. fields, methods, etc).
+ */
+
+ @SmallTest
+ public void testLacksTypeVariables() {
+ assertLacksTypeVariable(RegularClass.class);
+ assertLacksTypeVariable(SubClass.class);
+ assertLacksTypeVariable(SpecificClass.class);
+
+ assertLacksTypeVariable(RegularInterface.class);
+ assertLacksTypeVariable(ImplementsRegularInterface.class);
+ }
+
+ @SmallTest
+ public void testContainsTypeVariables() {
+ assertContainsTypeVariable(GenericClass.class);
+ assertContainsTypeVariable(SubGenericClass.class);
+
+ assertContainsTypeVariable(GenericInterface.class);
+ assertContainsTypeVariable(ImplementsGenericInterface.class);
+ assertContainsTypeVariable(Implements2GenericInterface.class);
+
+ assertContainsTypeVariable(GenericOuterClass.class);
+ assertContainsTypeVariable(GenericOuterClass.GenericInnerClass.class);
+ }
+
+ /**
+ * This should always throw an IllegalArgumentException since the
+ * type reference to {@code T} will contain a type variable (also {@code T}).
+ *
+ * @throws IllegalArgumentException unconditionally
+ */
+ private static <T> TypeReference<T> createTypeRefWithTypeVar() {
+ return new TypeReference<T>() {{ }};
+ }
+
+ @SmallTest
+ public void testTypeReferences() {
+ TypeReference<Integer> typeRefInt = new TypeReference<Integer>() {{ }};
+ TypeReference<Integer> typeRefInt2 = new TypeReference<Integer>() {{ }};
+
+ assertEquals(typeRefInt, typeRefInt2);
+ assertEquals("The type ref's captured type should be the Integer class",
+ Integer.class, typeRefInt.getType());
+
+ TypeReference<Float> typeRefFloat = new TypeReference<Float>() {{ }};
+ assertFalse("Integer/Float type references must not be equal",
+ typeRefInt.equals(typeRefFloat));
+ assertEquals("The type ref's captured type should be the Float class",
+ Float.class, typeRefFloat.getType());
+
+ try {
+ TypeReference<Integer> typeRefTypeVar = createTypeRefWithTypeVar();
+ fail("Expected a type reference with type variables to fail");
+ // Unreachable. Make the warning about an unused variable go away.
+ assertFalse(typeRefTypeVar.equals(typeRefInt));
+ } catch (IllegalArgumentException e) {
+ // OK. Expected behavior
+ }
+ }
+
+ // Compare the raw type against rawClass
+ private static <T> void assertRawTypeEquals(TypeReference<T> typeRef, Class<?> rawClass) {
+ assertEquals("Expected the raw type from " + typeRef + " to match the class " + rawClass,
+ rawClass, typeRef.getRawType());
+ }
+
+ // Compare the normal type against the klass
+ private static <T> void assertTypeReferenceEquals(TypeReference<T> typeRef, Class<?> klass) {
+ assertEquals("Expected the type from " + typeRef + " to match the class " + klass,
+ klass, typeRef.getType());
+ }
+
+ @SmallTest
+ public void testRawTypes() {
+ TypeReference<Integer> intToken = new TypeReference<Integer>() {{ }};
+ assertRawTypeEquals(intToken, Integer.class);
+
+ TypeReference<List<Integer>> listToken = new TypeReference<List<Integer>>() {{ }};
+ assertRawTypeEquals(listToken, List.class);
+
+ TypeReference<List<List<Integer>>> listListToken =
+ new TypeReference<List<List<Integer>>>() {{ }};
+ assertRawTypeEquals(listListToken, List.class);
+
+ TypeReference<int[]> intArrayToken = new TypeReference<int[]>() {{ }};
+ assertRawTypeEquals(intArrayToken, int[].class);
+
+ TypeReference<Integer[]> integerArrayToken = new TypeReference<Integer[]>() {{ }};
+ assertRawTypeEquals(integerArrayToken, Integer[].class);
+
+ TypeReference<List<Integer>[]> listArrayToken = new TypeReference<List<Integer>[]>() {{ }};
+ assertRawTypeEquals(listArrayToken, List[].class);
+ }
+
+ private class IntTokenOne extends TypeReference<Integer> {}
+ private class IntTokenTwo extends TypeReference<Integer> {}
+
+ private class IntArrayToken1 extends TypeReference<Integer[]> {}
+ private class IntArrayToken2 extends TypeReference<Integer[]> {}
+
+ private class IntListToken1 extends TypeReference<List<Integer>> {}
+ private class IntListToken2 extends TypeReference<List<Integer>> {}
+
+ private class IntListArrayToken1 extends TypeReference<List<Integer>[]> {}
+ private class IntListArrayToken2 extends TypeReference<List<Integer>[]> {}
+
+
+ // FIXME: Equality will fail: b/14590652
+ @SmallTest
+ public void testEquals() {
+ // Not an array. component type should be null.
+ TypeReference<Integer> intToken = new TypeReference<Integer>() {{ }};
+ assertEquals(intToken, intToken);
+ assertEquals(intToken, new TypeReference<Integer>() {{ }});
+
+ assertEquals(intToken, new IntTokenOne());
+ assertEquals(intToken, new IntTokenTwo());
+ assertEquals(new IntTokenOne(), new IntTokenTwo());
+
+ assertEquals(new IntArrayToken1(), new IntArrayToken2());
+ assertEquals(new IntListToken1(), new IntListToken2());
+ assertEquals(new IntListArrayToken1(), new IntListArrayToken2());
+ }
+
+ @SmallTest
+ public void testComponentType() {
+ // Not an array. component type should be null.
+ TypeReference<Integer> intToken = new TypeReference<Integer>() {{ }};
+ assertNull(intToken.getComponentType());
+
+ TypeReference<List<Integer>> listToken = new TypeReference<List<Integer>>() {{ }};
+ assertNull(listToken.getComponentType());
+
+ TypeReference<List<List<Integer>>> listListToken =
+ new TypeReference<List<List<Integer>>>() {{ }};
+ assertNull(listListToken.getComponentType());
+
+ // Check arrays. Component types should be what we expect.
+ TypeReference<int[]> intArrayToken = new TypeReference<int[]>() {{ }};
+ assertTypeReferenceEquals(intArrayToken.getComponentType(), int.class);
+
+ TypeReference<Integer[]> integerArrayToken = new TypeReference<Integer[]>() {{ }};
+ assertTypeReferenceEquals(integerArrayToken.getComponentType(), Integer.class);
+
+ assertEquals(new IntArrayToken1().getComponentType(),
+ new IntArrayToken2().getComponentType());
+
+ assertEquals(new IntListArrayToken1().getComponentType(),
+ new IntListArrayToken2().getComponentType());
+
+ // FIXME: Equality will fail: b/14590652
+ TypeReference<List<Integer>[]> listArrayToken = new TypeReference<List<Integer>[]>() {{ }};
+ assertEquals(listToken, listArrayToken.getComponentType());
+ }
+}
diff --git a/packages/BackupRestoreConfirmation/res/values-sk/strings.xml b/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
index 12f562b..21e21b5 100644
--- a/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sk/strings.xml
@@ -24,7 +24,7 @@
<string name="restore_confirm_text" msgid="7499866728030461776">"Z pripojeného počítača bolo vyžiadané úplné obnovenie všetkých údajov. Chcete túto akciu povoliť?\n\nAk ste toto obnovenie nevyžiadali vy, túto operáciu nepovoľujte. Táto akcia nahradí všetky údaje v zariadení."</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"Obnoviť údaje"</string>
<string name="deny_restore_button_label" msgid="1724367334453104378">"Neobnoviť"</string>
- <string name="current_password_text" msgid="8268189555578298067">"Zadajte svoje aktuálne heslo záloh nižšie:"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"Zadajte svoje aktuálne heslo pre zálohu nižšie:"</string>
<string name="device_encryption_restore_text" msgid="1570864916855208992">"Zadajte svoje heslo na šifrovanie zariadenia nižšie."</string>
<string name="device_encryption_backup_text" msgid="5866590762672844664">"Zadajte svoje heslo na šifrovanie zariadenia nižšie. Bude tiež použité na šifrovanie archívu zálohy."</string>
<string name="backup_enc_password_text" msgid="4981585714795233099">"Zadajte heslo, ktoré sa použije pri šifrovaní údajov úplnej zálohy. Ak pole ponecháte prázdne, použije sa vaše aktuálne heslo zálohy:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-sw/strings.xml b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
index 4e35b91..619a6db 100644
--- a/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
@@ -18,17 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="backup_confirm_title" msgid="827563724209303345">"Kuhifadhi kikamilifu"</string>
<string name="restore_confirm_title" msgid="5469365809567486602">"Kurejesha kila kitu"</string>
- <string name="backup_confirm_text" msgid="1878021282758896593">"Ombi la kuhifadhi nakala rudufu kamili za data kwenye eneo kazi la kompyuta iliyounganishwa limewasilishwa. Ungependa shughuli hii ufanyike?\n\n Ikiwa sio wewe uliyewasilisha ombi hili, usikubali shughuli hii iendelee."</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"Chelezo kamili la data iliyounganishwa kwenye eneo kazi la kompyuta limeombwa. Unataka kuruhusu hii kutendeka?\n\n Ikiwa hukuomba chelezo mwenyewe, usikubali uendeshaji kuendelea."</string>
<string name="allow_backup_button_label" msgid="4217228747769644068">"Hifadhi nakala ya data yangu"</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"Usicheleze"</string>
<string name="restore_confirm_text" msgid="7499866728030461776">"Kurejesha kamili kwa data nzima kutoka kwa eneo kazi la kompyuta lililounganishwa limeombwa. Unataka kuruhusu hii kutendeka?\n\n Ikiwa hukuweza kurejesha upya mwenyewe, usiruhusu uendeshaji huu kuendelea. Hii itaweka upya data yoyote iliyo kwenye kifaa hiki sasa!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"Rejesha upya data yangu"</string>
<string name="deny_restore_button_label" msgid="1724367334453104378">"Usirejeshe upya"</string>
- <string name="current_password_text" msgid="8268189555578298067">"Tafadhali ingiza nenosiri unalotumia kuhifadhi nakala rudufu hapo chini:"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"Tafadhali ingiza nenosiri lako la chelezo hapo chini:"</string>
<string name="device_encryption_restore_text" msgid="1570864916855208992">"Tafadhali ingiza nenosiri la usimbaji fiche wa kifaa chako hapo chini."</string>
<string name="device_encryption_backup_text" msgid="5866590762672844664">"Tafadhali ingiza nenosiri lako la msimbo fiche hapo chini. Pia litatumika kusimba fiche jalidi ya hifadhi."</string>
- <string name="backup_enc_password_text" msgid="4981585714795233099">"Tafadhali ingiza nenosiri la kutumia katika kusimba nakala rudufu kamili za data kwa njia fiche. Ikiwa hii itawachwa wazi, nenosiri lako la sasa litatumika:"</string>
- <string name="backup_enc_password_optional" msgid="1350137345907579306">"Ikiwa unataka kusimba kwa njia fiche nakala rudufu za data, ingiza nenosiri lililo hapo chini:"</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Tafadhali ingiza nenosiri la kutumia kwa usimbaji fiche wa chelezo ya data kamili. Ikiwa hii itawachwa wazi, nenosiri lako la sasa litatumika:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"Ikiwa unataka kusimba fiche data nzima ya kucheleza, ingiza nenosiri la hapo chini:"</string>
<string name="restore_enc_password_text" msgid="6140898525580710823">"Ikiwa data iliyorejeshwa upya, tafadhali ingiza nenosiri lililo hapo chini:"</string>
<string name="toast_backup_started" msgid="550354281452756121">"Inaanza kuhifadhi..."</string>
<string name="toast_backup_ended" msgid="3818080769548726424">"Imemaliza kuhifadhi"</string>
diff --git a/packages/DefaultContainerService/res/values-th/strings.xml b/packages/DefaultContainerService/res/values-th/strings.xml
index 621d7ed..3a7080c 100644
--- a/packages/DefaultContainerService/res/values-th/strings.xml
+++ b/packages/DefaultContainerService/res/values-th/strings.xml
@@ -20,5 +20,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="service_name" msgid="4841491635055379553">"ตัวช่วยเหลือของการเข้าถึงแพ็กเกจ"</string>
+ <string name="service_name" msgid="4841491635055379553">"ตัวช่วยเหลือของการเข้าถึงแพคเกจ"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index ca76a7d..41fd63a 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Stoor"</string>
<string name="menu_share" msgid="3075149983979628146">"Deel"</string>
<string name="menu_delete" msgid="8138799623850614177">"Vee uit"</string>
- <string name="menu_select" msgid="8711270657353563424">"Kies \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> gekies"</string>
<string name="sort_name" msgid="9183560467917256779">"Volgens naam"</string>
<string name="sort_date" msgid="586080032956151448">"Volgens datum gewysig"</string>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index 84879d5..c77a8ee 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"አስቀምጥ"</string>
<string name="menu_share" msgid="3075149983979628146">"አጋራ"</string>
<string name="menu_delete" msgid="8138799623850614177">"ሰርዝ"</string>
- <string name="menu_select" msgid="8711270657353563424">"«<xliff:g id="DIRECTORY">^1</xliff:g>»ን ይምረጡ"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ተመርጠዋል"</string>
<string name="sort_name" msgid="9183560467917256779">"በስም"</string>
<string name="sort_date" msgid="586080032956151448">"በተለወጠበት ቀን"</string>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index 5c5d863..c59c0ee 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"حفظ"</string>
<string name="menu_share" msgid="3075149983979628146">"مشاركة"</string>
<string name="menu_delete" msgid="8138799623850614177">"حذف"</string>
- <string name="menu_select" msgid="8711270657353563424">"تحديد \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"تم تحديد <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"بحسب الاسم"</string>
<string name="sort_date" msgid="586080032956151448">"بحسب تاريخ التعديل"</string>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index d1da879..c3242b2 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Запазване"</string>
<string name="menu_share" msgid="3075149983979628146">"Споделяне"</string>
<string name="menu_delete" msgid="8138799623850614177">"Изтриване"</string>
- <string name="menu_select" msgid="8711270657353563424">"Избиране на „<xliff:g id="DIRECTORY">^1</xliff:g>“"</string>
<string name="mode_selected_count" msgid="459111894725594625">"Избрахте <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"По име"</string>
<string name="sort_date" msgid="586080032956151448">"По дата на промяната"</string>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index 23e7284..68c7b0e 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Desa"</string>
<string name="menu_share" msgid="3075149983979628146">"Comparteix"</string>
<string name="menu_delete" msgid="8138799623850614177">"Suprimeix"</string>
- <string name="menu_select" msgid="8711270657353563424">"Selecciona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"Seleccionats: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Per nom"</string>
<string name="sort_date" msgid="586080032956151448">"Per data de modificació"</string>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index ad8897a..f089c8b 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Uložit"</string>
<string name="menu_share" msgid="3075149983979628146">"Sdílet"</string>
<string name="menu_delete" msgid="8138799623850614177">"Smazat"</string>
- <string name="menu_select" msgid="8711270657353563424">"Vyberte adresář <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
<string name="mode_selected_count" msgid="459111894725594625">"Vybráno: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Podle názvu"</string>
<string name="sort_date" msgid="586080032956151448">"Podle data úpravy"</string>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index 7ae5d1e..816f9a7 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Gem"</string>
<string name="menu_share" msgid="3075149983979628146">"Del"</string>
<string name="menu_delete" msgid="8138799623850614177">"Slet"</string>
- <string name="menu_select" msgid="8711270657353563424">"Vælg \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> er valgt"</string>
<string name="sort_name" msgid="9183560467917256779">"Efter navn"</string>
<string name="sort_date" msgid="586080032956151448">"Efter ændringsdato"</string>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index 98c1787..3b448d9 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Speichern"</string>
<string name="menu_share" msgid="3075149983979628146">"Teilen"</string>
<string name="menu_delete" msgid="8138799623850614177">"Löschen"</string>
- <string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" auswählen"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ausgewählt"</string>
<string name="sort_name" msgid="9183560467917256779">"Nach Name"</string>
<string name="sort_date" msgid="586080032956151448">"Nach Änderungsdatum"</string>
@@ -48,7 +47,7 @@
<string name="pref_advanced_devices" msgid="903257239609301276">"Erweiterte Geräte anzeigen"</string>
<string name="pref_file_size" msgid="2826879315743961459">"Dateigröße anzeigen"</string>
<string name="pref_device_size" msgid="3542106883278997222">"Geräteabmessungen anzeigen"</string>
- <string name="empty" msgid="7858882803708117596">"Keine Dokumente"</string>
+ <string name="empty" msgid="7858882803708117596">"Keine Elemente"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Datei kann nicht geöffnet werden."</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Einige Dokumente konnten nicht gelöscht werden."</string>
<string name="share_via" msgid="8966594246261344259">"Teilen über"</string>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index f0f7e10..aec3318 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -27,9 +27,8 @@
<string name="menu_settings" msgid="6008033148948428823">"Ρυθμίσεις"</string>
<string name="menu_open" msgid="432922957274920903">"Άνοιγμα"</string>
<string name="menu_save" msgid="2394743337684426338">"Αποθήκευση"</string>
- <string name="menu_share" msgid="3075149983979628146">"Κοινοποίηση"</string>
+ <string name="menu_share" msgid="3075149983979628146">"Κοινή χρήση"</string>
<string name="menu_delete" msgid="8138799623850614177">"Διαγραφή"</string>
- <string name="menu_select" msgid="8711270657353563424">"Επιλογή \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"Επιλέχθηκαν <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Κατά όνομα"</string>
<string name="sort_date" msgid="586080032956151448">"Κατά ημερομηνία τροποποίησης"</string>
@@ -51,5 +50,5 @@
<string name="empty" msgid="7858882803708117596">"Δεν υπάρχουν στοιχεία"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Δεν είναι δυνατό το άνοιγμα του αρχείου"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"Δεν είναι δυνατή η διαγραφή ορισμένων εγγράφων"</string>
- <string name="share_via" msgid="8966594246261344259">"Κοινοποίηση μέσω"</string>
+ <string name="share_via" msgid="8966594246261344259">"Κοινή χρήση μέσω"</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index d2af473..a95e7f1 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Save"</string>
<string name="menu_share" msgid="3075149983979628146">"Share"</string>
<string name="menu_delete" msgid="8138799623850614177">"Delete"</string>
- <string name="menu_select" msgid="8711270657353563424">"Select \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selected"</string>
<string name="sort_name" msgid="9183560467917256779">"By name"</string>
<string name="sort_date" msgid="586080032956151448">"By date modified"</string>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index d2af473..a95e7f1 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Save"</string>
<string name="menu_share" msgid="3075149983979628146">"Share"</string>
<string name="menu_delete" msgid="8138799623850614177">"Delete"</string>
- <string name="menu_select" msgid="8711270657353563424">"Select \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selected"</string>
<string name="sort_name" msgid="9183560467917256779">"By name"</string>
<string name="sort_date" msgid="586080032956151448">"By date modified"</string>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index daf18cf..4a3ff33 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Guardar"</string>
<string name="menu_share" msgid="3075149983979628146">"Compartir"</string>
<string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
- <string name="menu_select" msgid="8711270657353563424">"Seleccionar \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> seleccionado(s)"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nombre"</string>
<string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index 573ee41..1682542 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Guardar"</string>
<string name="menu_share" msgid="3075149983979628146">"Compartir"</string>
<string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
- <string name="menu_select" msgid="8711270657353563424">"Selecciona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"Seleccionado: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nombre"</string>
<string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index dae965a0..5412956 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Salvesta"</string>
<string name="menu_share" msgid="3075149983979628146">"Jaga"</string>
<string name="menu_delete" msgid="8138799623850614177">"Kustuta"</string>
- <string name="menu_select" msgid="8711270657353563424">"Kataloogi „<xliff:g id="DIRECTORY">^1</xliff:g>” valimine"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> on valitud"</string>
<string name="sort_name" msgid="9183560467917256779">"Nime järgi"</string>
<string name="sort_date" msgid="586080032956151448">"Muutmiskuupäeva järgi"</string>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index a646eda..c922b37 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"ذخیره"</string>
<string name="menu_share" msgid="3075149983979628146">"اشتراکگذاری"</string>
<string name="menu_delete" msgid="8138799623850614177">"حذف"</string>
- <string name="menu_select" msgid="8711270657353563424">"انتخاب «<xliff:g id="DIRECTORY">^1</xliff:g>»"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> انتخاب شد"</string>
<string name="sort_name" msgid="9183560467917256779">"بر اساس نام"</string>
<string name="sort_date" msgid="586080032956151448">"بر اساس تاریخ اصلاح"</string>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index aa118ed..5e40ecd 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Tallenna"</string>
<string name="menu_share" msgid="3075149983979628146">"Jaa"</string>
<string name="menu_delete" msgid="8138799623850614177">"Poista"</string>
- <string name="menu_select" msgid="8711270657353563424">"Valitse <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> valittua"</string>
<string name="sort_name" msgid="9183560467917256779">"Nimen mukaan"</string>
<string name="sort_date" msgid="586080032956151448">"Muokkauspäivän mukaan"</string>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index b370a1e..a837379 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Enregistrer"</string>
<string name="menu_share" msgid="3075149983979628146">"Partager"</string>
<string name="menu_delete" msgid="8138799623850614177">"Supprimer"</string>
- <string name="menu_select" msgid="8711270657353563424">"Sélectionner « <xliff:g id="DIRECTORY">^1</xliff:g> »"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> sélectionné(s)"</string>
<string name="sort_name" msgid="9183560467917256779">"Par nom"</string>
<string name="sort_date" msgid="586080032956151448">"Par date de modification"</string>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index 070b130..ff9aeda 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Enregistrer"</string>
<string name="menu_share" msgid="3075149983979628146">"Partager"</string>
<string name="menu_delete" msgid="8138799623850614177">"Supprimer"</string>
- <string name="menu_select" msgid="8711270657353563424">"Sélectionner \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> élément(s) sélectionné(s)"</string>
<string name="sort_name" msgid="9183560467917256779">"Par nom"</string>
<string name="sort_date" msgid="586080032956151448">"Par date de modification"</string>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index 66c707e..8d7fcba 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"सहेजें"</string>
<string name="menu_share" msgid="3075149983979628146">"साझा करें"</string>
<string name="menu_delete" msgid="8138799623850614177">"हटाएं"</string>
- <string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" चुनें"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> चयनित"</string>
<string name="sort_name" msgid="9183560467917256779">"नाम के अनुसार"</string>
<string name="sort_date" msgid="586080032956151448">"बदलाव के दिनांक के अनुसार"</string>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index 3438e73..73c2f04 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Spremi"</string>
<string name="menu_share" msgid="3075149983979628146">"Dijeli"</string>
<string name="menu_delete" msgid="8138799623850614177">"Izbriši"</string>
- <string name="menu_select" msgid="8711270657353563424">"Odaberi \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"Odabrano: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Po korisniku"</string>
<string name="sort_date" msgid="586080032956151448">"Po datumu izmjene"</string>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index 2af559b..db7854b 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Mentés"</string>
<string name="menu_share" msgid="3075149983979628146">"Megosztás"</string>
<string name="menu_delete" msgid="8138799623850614177">"Törlés"</string>
- <string name="menu_select" msgid="8711270657353563424">"A(z) „<xliff:g id="DIRECTORY">^1</xliff:g>” mappa kiválasztása"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> kiválasztva"</string>
<string name="sort_name" msgid="9183560467917256779">"Név szerint"</string>
<string name="sort_date" msgid="586080032956151448">"Módosítás dátuma szerint"</string>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 67a1f7e..c683f3e 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Պահել"</string>
<string name="menu_share" msgid="3075149983979628146">"Համօգտագործել"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ջնջել"</string>
- <string name="menu_select" msgid="8711270657353563424">"Ընտրել «<xliff:g id="DIRECTORY">^1</xliff:g>»"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ընտրված"</string>
<string name="sort_name" msgid="9183560467917256779">"Ըստ անվան"</string>
<string name="sort_date" msgid="586080032956151448">"Ըստ փոփոխման ամսաթվի"</string>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index 62057c7..519b936 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -22,14 +22,13 @@
<string name="menu_create_dir" msgid="5947289605844398389">"Buat folder"</string>
<string name="menu_grid" msgid="6878021334497835259">"Tampilan kisi"</string>
<string name="menu_list" msgid="7279285939892417279">"Tampilan daftar"</string>
- <string name="menu_sort" msgid="7677740407158414452">"Urutkan menurut"</string>
+ <string name="menu_sort" msgid="7677740407158414452">"Sortir menurut"</string>
<string name="menu_search" msgid="3816712084502856974">"Telusuri"</string>
<string name="menu_settings" msgid="6008033148948428823">"Setelan"</string>
<string name="menu_open" msgid="432922957274920903">"Buka"</string>
<string name="menu_save" msgid="2394743337684426338">"Simpan"</string>
<string name="menu_share" msgid="3075149983979628146">"Bagikan"</string>
<string name="menu_delete" msgid="8138799623850614177">"Hapus"</string>
- <string name="menu_select" msgid="8711270657353563424">"Pilih \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> dipilih"</string>
<string name="sort_name" msgid="9183560467917256779">"Menurut nama"</string>
<string name="sort_date" msgid="586080032956151448">"Menurut tanggal diubah"</string>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index bec4d00..28323b6 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Salva"</string>
<string name="menu_share" msgid="3075149983979628146">"Condividi"</string>
<string name="menu_delete" msgid="8138799623850614177">"Elimina"</string>
- <string name="menu_select" msgid="8711270657353563424">"Seleziona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selezionati"</string>
<string name="sort_name" msgid="9183560467917256779">"Per nome"</string>
<string name="sort_date" msgid="586080032956151448">"Per data di modifica"</string>
@@ -39,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"Impossibile salvare il documento"</string>
<string name="create_error" msgid="3735649141335444215">"Impossibile creare la cartella"</string>
<string name="query_error" msgid="1222448261663503501">"Impossibile chiedere documenti"</string>
- <string name="root_recent" msgid="4470053704320518133">"Recenti"</string>
+ <string name="root_recent" msgid="4470053704320518133">"Recente"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> liberi"</string>
<string name="root_type_service" msgid="2178854894416775409">"Servizi di archiviazione"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"Scorciatoie"</string>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index c8a3fb9..712c060 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"שמור"</string>
<string name="menu_share" msgid="3075149983979628146">"שתף"</string>
<string name="menu_delete" msgid="8138799623850614177">"מחק"</string>
- <string name="menu_select" msgid="8711270657353563424">"בחר ב-\"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> נבחרו"</string>
<string name="sort_name" msgid="9183560467917256779">"לפי שם"</string>
<string name="sort_date" msgid="586080032956151448">"לפי תאריך שינוי"</string>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index 1475005..996496d 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"保存"</string>
<string name="menu_share" msgid="3075149983979628146">"共有"</string>
<string name="menu_delete" msgid="8138799623850614177">"削除"</string>
- <string name="menu_select" msgid="8711270657353563424">"「<xliff:g id="DIRECTORY">^1</xliff:g>」を選択"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g>件選択済み"</string>
<string name="sort_name" msgid="9183560467917256779">"名前順"</string>
<string name="sort_date" msgid="586080032956151448">"更新日順"</string>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index c90768f..f3e1274 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"შენახვა"</string>
<string name="menu_share" msgid="3075149983979628146">"გაზიარება"</string>
<string name="menu_delete" msgid="8138799623850614177">"წაშლა"</string>
- <string name="menu_select" msgid="8711270657353563424">"„<xliff:g id="DIRECTORY">^1</xliff:g>“-ის არჩევა"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> მონიშნული"</string>
<string name="sort_name" msgid="9183560467917256779">"სახელით"</string>
<string name="sort_date" msgid="586080032956151448">"ცვლილების თარიღით"</string>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index e8944ec..e632209 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -20,16 +20,15 @@
<string name="title_open" msgid="4353228937663917801">"បើកពី"</string>
<string name="title_save" msgid="2433679664882857999">"រក្សាទុកទៅ"</string>
<string name="menu_create_dir" msgid="5947289605844398389">"បង្កើតថត"</string>
- <string name="menu_grid" msgid="6878021334497835259">"ទិដ្ឋភាពក្រឡា"</string>
+ <string name="menu_grid" msgid="6878021334497835259">"ទិដ្ឋភាពក្រឡា"</string>
<string name="menu_list" msgid="7279285939892417279">"ទិដ្ឋភាពបញ្ជី"</string>
<string name="menu_sort" msgid="7677740407158414452">"តម្រៀបតាម"</string>
<string name="menu_search" msgid="3816712084502856974">"ស្វែងរក"</string>
<string name="menu_settings" msgid="6008033148948428823">"ការកំណត់"</string>
<string name="menu_open" msgid="432922957274920903">"បើក"</string>
<string name="menu_save" msgid="2394743337684426338">"រក្សាទុក"</string>
- <string name="menu_share" msgid="3075149983979628146">"ចែករំលែក"</string>
+ <string name="menu_share" msgid="3075149983979628146">"ចែករំលែក"</string>
<string name="menu_delete" msgid="8138799623850614177">"លុប"</string>
- <string name="menu_select" msgid="8711270657353563424">"ជ្រើស \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"បានជ្រើស <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"តាមឈ្មោះ"</string>
<string name="sort_date" msgid="586080032956151448">"តាមកាលបរិច្ឆេទបានកែប្រែ"</string>
@@ -48,7 +47,7 @@
<string name="pref_advanced_devices" msgid="903257239609301276">"បង្ហាញឧបករណ៍កម្រិតខ្ពស់"</string>
<string name="pref_file_size" msgid="2826879315743961459">"បង្ហាញទំហំឯកសារ"</string>
<string name="pref_device_size" msgid="3542106883278997222">"បង្ហាញទំហំឧបករណ៍"</string>
- <string name="empty" msgid="7858882803708117596">"គ្មានធាតុ"</string>
+ <string name="empty" msgid="7858882803708117596">"គ្មានធាតុ"</string>
<string name="toast_no_application" msgid="1339885974067891667">"មិនអាចបើកឯកសារ"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"មិនអាចលុបឯកសារមួយចំនួន"</string>
<string name="share_via" msgid="8966594246261344259">"ចែករំលែកតាម"</string>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index 5996e66..2cd0d44 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"저장"</string>
<string name="menu_share" msgid="3075149983979628146">"공유"</string>
<string name="menu_delete" msgid="8138799623850614177">"삭제"</string>
- <string name="menu_select" msgid="8711270657353563424">"\'<xliff:g id="DIRECTORY">^1</xliff:g>\' 선택"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g>개 선택됨"</string>
<string name="sort_name" msgid="9183560467917256779">"이름순"</string>
<string name="sort_date" msgid="586080032956151448">"수정된 날짜순"</string>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index 8452ae1..9a6f32f 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"ບັນທຶກ"</string>
<string name="menu_share" msgid="3075149983979628146">"ແບ່ງປັນ"</string>
<string name="menu_delete" msgid="8138799623850614177">"ລຶບ"</string>
- <string name="menu_select" msgid="8711270657353563424">"ເລືອກ \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"ເລືອກແລ້ວ <xliff:g id="COUNT">%1$d</xliff:g> ລາຍການ"</string>
<string name="sort_name" msgid="9183560467917256779">"ຕາມຊື່"</string>
<string name="sort_date" msgid="586080032956151448">"ຕາມວັນທີທີ່ແກ້ໄຂ"</string>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index 8ec3e0b..f861b99 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Išsaugoti"</string>
<string name="menu_share" msgid="3075149983979628146">"Bendrinti"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ištrinti"</string>
- <string name="menu_select" msgid="8711270657353563424">"Pasirinkti katalogą „<xliff:g id="DIRECTORY">^1</xliff:g>“"</string>
<string name="mode_selected_count" msgid="459111894725594625">"Pasirinkta: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Pagal pavadinimą"</string>
<string name="sort_date" msgid="586080032956151448">"Pagal keitimo datą"</string>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index caaf8ec..651a59fe0d 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Saglabāt"</string>
<string name="menu_share" msgid="3075149983979628146">"Kopīgot"</string>
<string name="menu_delete" msgid="8138799623850614177">"Dzēst"</string>
- <string name="menu_select" msgid="8711270657353563424">"Atlasīt “<xliff:g id="DIRECTORY">^1</xliff:g>”"</string>
<string name="mode_selected_count" msgid="459111894725594625">"Atlasīts: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Pēc nosaukuma"</string>
<string name="sort_date" msgid="586080032956151448">"Pēc pārveidošanas datuma"</string>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index 3d90cc1..22c9fcd 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Хадгалах"</string>
<string name="menu_share" msgid="3075149983979628146">"Хуваалцах"</string>
<string name="menu_delete" msgid="8138799623850614177">"Устгах"</string>
- <string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\"-г сонгох"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> сонгогдсон"</string>
<string name="sort_name" msgid="9183560467917256779">"Нэрээр"</string>
<string name="sort_date" msgid="586080032956151448">"Өөрчлөгдсөн огноогоор"</string>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index 9ea7119..7e09c57 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Simpan"</string>
<string name="menu_share" msgid="3075149983979628146">"Kongsi"</string>
<string name="menu_delete" msgid="8138799623850614177">"Padam"</string>
- <string name="menu_select" msgid="8711270657353563424">"Pilih \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> dipilih"</string>
<string name="sort_name" msgid="9183560467917256779">"Mengikut nama"</string>
<string name="sort_date" msgid="586080032956151448">"Diubah suai mengikut tarikh"</string>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index af7c282..8831bd8 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Lagre"</string>
<string name="menu_share" msgid="3075149983979628146">"Del"</string>
<string name="menu_delete" msgid="8138799623850614177">"Slett"</string>
- <string name="menu_select" msgid="8711270657353563424">"Velg «<xliff:g id="DIRECTORY">^1</xliff:g>»"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> valgt"</string>
<string name="sort_name" msgid="9183560467917256779">"Etter navn"</string>
<string name="sort_date" msgid="586080032956151448">"«Etter dato» endret"</string>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index a8cf114..08862e8 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Opslaan"</string>
<string name="menu_share" msgid="3075149983979628146">"Delen"</string>
<string name="menu_delete" msgid="8138799623850614177">"Verwijderen"</string>
- <string name="menu_select" msgid="8711270657353563424">"<xliff:g id="DIRECTORY">^1</xliff:g> selecteren"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> geselecteerd"</string>
<string name="sort_name" msgid="9183560467917256779">"Op naam"</string>
<string name="sort_date" msgid="586080032956151448">"Op aanpassingsdatum"</string>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index ead40e9..f4e5582 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Zapisz"</string>
<string name="menu_share" msgid="3075149983979628146">"Udostępnij"</string>
<string name="menu_delete" msgid="8138799623850614177">"Usuń"</string>
- <string name="menu_select" msgid="8711270657353563424">"Zaznacz „<xliff:g id="DIRECTORY">^1</xliff:g>”"</string>
<string name="mode_selected_count" msgid="459111894725594625">"Wybrano: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Według nazwy"</string>
<string name="sort_date" msgid="586080032956151448">"Według daty edycji"</string>
@@ -45,8 +44,8 @@
<string name="root_type_shortcut" msgid="3318760609471618093">"Skróty"</string>
<string name="root_type_device" msgid="7121342474653483538">"Urządzenia"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Więcej aplikacji"</string>
- <string name="pref_advanced_devices" msgid="903257239609301276">"Pokaż urządzenia zaawansowane"</string>
- <string name="pref_file_size" msgid="2826879315743961459">"Pokaż rozmiar pliku"</string>
+ <string name="pref_advanced_devices" msgid="903257239609301276">"Wyświetl urządzenia zaawansowane"</string>
+ <string name="pref_file_size" msgid="2826879315743961459">"Wyświetl rozmiar pliku"</string>
<string name="pref_device_size" msgid="3542106883278997222">"Wyświetl rozmiar urządzenia"</string>
<string name="empty" msgid="7858882803708117596">"Brak elementów"</string>
<string name="toast_no_application" msgid="1339885974067891667">"Nie można otworzyć pliku"</string>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index 0003c05..1c1ba8b 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Guardar"</string>
<string name="menu_share" msgid="3075149983979628146">"Partilhar"</string>
<string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
- <string name="menu_select" msgid="8711270657353563424">"Selecionar \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selecionado(s)"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
<string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string>
@@ -45,7 +44,7 @@
<string name="root_type_shortcut" msgid="3318760609471618093">"Atalhos"</string>
<string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Mais aplicações"</string>
- <string name="pref_advanced_devices" msgid="903257239609301276">"Ver dispositivos avançados"</string>
+ <string name="pref_advanced_devices" msgid="903257239609301276">"Apresentar dispositivos avançados"</string>
<string name="pref_file_size" msgid="2826879315743961459">"Apresentar tamanho do ficheiro"</string>
<string name="pref_device_size" msgid="3542106883278997222">"Apresentar tamanho do dispositivo"</string>
<string name="empty" msgid="7858882803708117596">"Sem itens"</string>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index 4a5c72a..78fcaf8 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Salvar"</string>
<string name="menu_share" msgid="3075149983979628146">"Compartilhar"</string>
<string name="menu_delete" msgid="8138799623850614177">"Excluir"</string>
- <string name="menu_select" msgid="8711270657353563424">"Selecionar \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selecionados"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
<string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index 0dfa11d4..5fd44c8 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Salvați"</string>
<string name="menu_share" msgid="3075149983979628146">"Distribuiți"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ștergeți"</string>
- <string name="menu_select" msgid="8711270657353563424">"Selectați „<xliff:g id="DIRECTORY">^1</xliff:g>”"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selectate"</string>
<string name="sort_name" msgid="9183560467917256779">"După nume"</string>
<string name="sort_date" msgid="586080032956151448">"După data modificării"</string>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index f86a4af..85fd70e0 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Сохранить"</string>
<string name="menu_share" msgid="3075149983979628146">"Поделиться"</string>
<string name="menu_delete" msgid="8138799623850614177">"Удалить"</string>
- <string name="menu_select" msgid="8711270657353563424">"Выбрать папку \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"Выбрано: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"По названию"</string>
<string name="sort_date" msgid="586080032956151448">"По дате изменения"</string>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index 5d03df6..2a96b1a 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Uložiť"</string>
<string name="menu_share" msgid="3075149983979628146">"Zdieľať"</string>
<string name="menu_delete" msgid="8138799623850614177">"Odstrániť"</string>
- <string name="menu_select" msgid="8711270657353563424">"Vyberte adresár <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
<string name="mode_selected_count" msgid="459111894725594625">"Vybraté: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Podľa názvu"</string>
<string name="sort_date" msgid="586080032956151448">"Podľa dátumu zmeny"</string>
@@ -45,7 +44,7 @@
<string name="root_type_shortcut" msgid="3318760609471618093">"Skratky"</string>
<string name="root_type_device" msgid="7121342474653483538">"Zariadenia"</string>
<string name="root_type_apps" msgid="8838065367985945189">"Ďalšie aplikácie"</string>
- <string name="pref_advanced_devices" msgid="903257239609301276">"Zobraziť pokročilé zariadenia"</string>
+ <string name="pref_advanced_devices" msgid="903257239609301276">"Zobraziť rozšírené zariadenia"</string>
<string name="pref_file_size" msgid="2826879315743961459">"Zobraziť veľkosť súboru"</string>
<string name="pref_device_size" msgid="3542106883278997222">"Zobraziť veľkosť zariadenia"</string>
<string name="empty" msgid="7858882803708117596">"Žiadne položky"</string>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index b3e52dd43..f984a0a 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Shrani"</string>
<string name="menu_share" msgid="3075149983979628146">"Skupna raba"</string>
<string name="menu_delete" msgid="8138799623850614177">"Izbriši"</string>
- <string name="menu_select" msgid="8711270657353563424">"Izbira mape »<xliff:g id="DIRECTORY">^1</xliff:g>«"</string>
<string name="mode_selected_count" msgid="459111894725594625">"Št. izbranih: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Po imenu"</string>
<string name="sort_date" msgid="586080032956151448">"Po datumu spremembe"</string>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index 892dbce..eb0b197 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Сачувај"</string>
<string name="menu_share" msgid="3075149983979628146">"Дели"</string>
<string name="menu_delete" msgid="8138799623850614177">"Избриши"</string>
- <string name="menu_select" msgid="8711270657353563424">"Изабери „<xliff:g id="DIRECTORY">^1</xliff:g>“"</string>
<string name="mode_selected_count" msgid="459111894725594625">"Изабрано је <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Према имену"</string>
<string name="sort_date" msgid="586080032956151448">"Према датуму измене"</string>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index fd6457d..7aa5c50 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Spara"</string>
<string name="menu_share" msgid="3075149983979628146">"Dela"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ta bort"</string>
- <string name="menu_select" msgid="8711270657353563424">"Välj <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
<string name="mode_selected_count" msgid="459111894725594625">"Har valt <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Efter namn"</string>
<string name="sort_date" msgid="586080032956151448">"Efter ändringsdatum"</string>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index 0948c71..299fda7 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Hifadhi"</string>
<string name="menu_share" msgid="3075149983979628146">"Shiriki"</string>
<string name="menu_delete" msgid="8138799623850614177">"Futa"</string>
- <string name="menu_select" msgid="8711270657353563424">"Chagua \" <xliff:g id="DIRECTORY">^1</xliff:g> \""</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> zimechaguliwa"</string>
<string name="sort_name" msgid="9183560467917256779">"Kwa jina"</string>
<string name="sort_date" msgid="586080032956151448">"Kwa tarehe viliporekebishwa"</string>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index 4bf3e4f..6ac8810 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"บันทึก"</string>
<string name="menu_share" msgid="3075149983979628146">"แชร์"</string>
<string name="menu_delete" msgid="8138799623850614177">"ลบ"</string>
- <string name="menu_select" msgid="8711270657353563424">"เลือก \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"เลือกไว้ <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"ตามชื่อ"</string>
<string name="sort_date" msgid="586080032956151448">"ตามวันที่ที่ปรับเปลี่ยน"</string>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index 8ef8aa5..e0fd8c8 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"I-save"</string>
<string name="menu_share" msgid="3075149983979628146">"Ibahagi"</string>
<string name="menu_delete" msgid="8138799623850614177">"Tanggalin"</string>
- <string name="menu_select" msgid="8711270657353563424">"Piliin ang \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ang pinili"</string>
<string name="sort_name" msgid="9183560467917256779">"Ayon sa pangalan"</string>
<string name="sort_date" msgid="586080032956151448">"Ayon sa petsa ng pagbago"</string>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 93586d0..699a5cd 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Kaydet"</string>
<string name="menu_share" msgid="3075149983979628146">"Paylaş"</string>
<string name="menu_delete" msgid="8138799623850614177">"Sil"</string>
- <string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" dizinini seç"</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> tane seçildi"</string>
<string name="sort_name" msgid="9183560467917256779">"Ada göre"</string>
<string name="sort_date" msgid="586080032956151448">"Değişiklik tarihine göre"</string>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index 8f8865b..f87b6a2 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Зберегти"</string>
<string name="menu_share" msgid="3075149983979628146">"Поділитися"</string>
<string name="menu_delete" msgid="8138799623850614177">"Видалити"</string>
- <string name="menu_select" msgid="8711270657353563424">"Вибрати каталог \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"Вибрано <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"За назвою"</string>
<string name="sort_date" msgid="586080032956151448">"За датою змінення"</string>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index 8b8ff1f..41e29fa 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Lưu"</string>
<string name="menu_share" msgid="3075149983979628146">"Chia sẻ"</string>
<string name="menu_delete" msgid="8138799623850614177">"Xóa"</string>
- <string name="menu_select" msgid="8711270657353563424">"Chọn \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"Đã chọn <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Theo tên"</string>
<string name="sort_date" msgid="586080032956151448">"Theo ngày sửa đổi"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index 68ab5f8..742cda7 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"保存"</string>
<string name="menu_share" msgid="3075149983979628146">"分享"</string>
<string name="menu_delete" msgid="8138799623850614177">"删除"</string>
- <string name="menu_select" msgid="8711270657353563424">"选择“<xliff:g id="DIRECTORY">^1</xliff:g>”"</string>
<string name="mode_selected_count" msgid="459111894725594625">"已选择<xliff:g id="COUNT">%1$d</xliff:g>项"</string>
<string name="sort_name" msgid="9183560467917256779">"按名称"</string>
<string name="sort_date" msgid="586080032956151448">"按修改日期"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index afd8b63..67ed587 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"儲存"</string>
<string name="menu_share" msgid="3075149983979628146">"分享"</string>
<string name="menu_delete" msgid="8138799623850614177">"刪除"</string>
- <string name="menu_select" msgid="8711270657353563424">"選取「<xliff:g id="DIRECTORY">^1</xliff:g>」"</string>
<string name="mode_selected_count" msgid="459111894725594625">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 個"</string>
<string name="sort_name" msgid="9183560467917256779">"按名稱"</string>
<string name="sort_date" msgid="586080032956151448">"按修改日期"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index 2e77f21..269583a 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="2783841764617238354">"文件"</string>
- <string name="title_open" msgid="4353228937663917801">"開啟檔案"</string>
+ <string name="title_open" msgid="4353228937663917801">"開啟工具"</string>
<string name="title_save" msgid="2433679664882857999">"儲存至"</string>
<string name="menu_create_dir" msgid="5947289605844398389">"建立資料夾"</string>
<string name="menu_grid" msgid="6878021334497835259">"格狀檢視"</string>
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"儲存"</string>
<string name="menu_share" msgid="3075149983979628146">"共用"</string>
<string name="menu_delete" msgid="8138799623850614177">"刪除"</string>
- <string name="menu_select" msgid="8711270657353563424">"選取「<xliff:g id="DIRECTORY">^1</xliff:g>」"</string>
<string name="mode_selected_count" msgid="459111894725594625">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 個項目"</string>
<string name="sort_name" msgid="9183560467917256779">"依名稱"</string>
<string name="sort_date" msgid="586080032956151448">"依修改日期"</string>
@@ -39,7 +38,7 @@
<string name="save_error" msgid="6167009778003223664">"無法儲存文件"</string>
<string name="create_error" msgid="3735649141335444215">"無法建立資料夾"</string>
<string name="query_error" msgid="1222448261663503501">"無法查詢文件"</string>
- <string name="root_recent" msgid="4470053704320518133">"最近存取過"</string>
+ <string name="root_recent" msgid="4470053704320518133">"最近使用過的項目"</string>
<string name="root_available_bytes" msgid="8568452858617033281">"可用空間:<xliff:g id="SIZE">%1$s</xliff:g>"</string>
<string name="root_type_service" msgid="2178854894416775409">"儲存空間服務"</string>
<string name="root_type_shortcut" msgid="3318760609471618093">"捷徑"</string>
@@ -48,7 +47,7 @@
<string name="pref_advanced_devices" msgid="903257239609301276">"顯示進階裝置"</string>
<string name="pref_file_size" msgid="2826879315743961459">"顯示檔案大小"</string>
<string name="pref_device_size" msgid="3542106883278997222">"顯示裝置大小"</string>
- <string name="empty" msgid="7858882803708117596">"沒有任何項目"</string>
+ <string name="empty" msgid="7858882803708117596">"沒有項目"</string>
<string name="toast_no_application" msgid="1339885974067891667">"無法開啟檔案"</string>
<string name="toast_failed_delete" msgid="2180678019407244069">"無法刪除部分文件"</string>
<string name="share_via" msgid="8966594246261344259">"分享方式:"</string>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index 55e2c75..bedd2cdf 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -29,7 +29,6 @@
<string name="menu_save" msgid="2394743337684426338">"Londoloza"</string>
<string name="menu_share" msgid="3075149983979628146">"Yabelana"</string>
<string name="menu_delete" msgid="8138799623850614177">"Susa"</string>
- <string name="menu_select" msgid="8711270657353563424">"Khetha i-\"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> okukhethiwe"</string>
<string name="sort_name" msgid="9183560467917256779">"Ngegama"</string>
<string name="sort_date" msgid="586080032956151448">"Ngedethi yokuguqula"</string>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index b2b2bd8..9069a55 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -436,6 +436,8 @@
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.mode_directory, menu);
+ mode.setTitle(getResources()
+ .getString(R.string.mode_selected_count, mCurrentView.getCheckedItemCount()));
return true;
}
diff --git a/packages/ExternalStorageProvider/res/values-sk/strings.xml b/packages/ExternalStorageProvider/res/values-sk/strings.xml
index 9be7b79..fd424c8 100644
--- a/packages/ExternalStorageProvider/res/values-sk/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-sk/strings.xml
@@ -17,6 +17,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7123375275748530234">"Externý ukladací priestor"</string>
- <string name="root_internal_storage" msgid="827844243068584127">"Interné úložisko"</string>
+ <string name="root_internal_storage" msgid="827844243068584127">"Interný ukladací priestor"</string>
<string name="root_documents" msgid="4051252304075469250">"Dokumenty"</string>
</resources>
diff --git a/packages/FusedLocation/res/values-fr-rCA/strings.xml b/packages/FusedLocation/res/values-fr-rCA/strings.xml
index c7d33af..0d2cccc 100644
--- a/packages/FusedLocation/res/values-fr-rCA/strings.xml
+++ b/packages/FusedLocation/res/values-fr-rCA/strings.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5379477904423203699">"Tables de fusion"</string>
+ <string name="app_label" msgid="5379477904423203699">"Fused Location"</string>
</resources>
diff --git a/packages/InputDevices/res/values-af/strings.xml b/packages/InputDevices/res/values-af/strings.xml
index ddaf706..13fcbb4 100644
--- a/packages/InputDevices/res/values-af/strings.xml
+++ b/packages/InputDevices/res/values-af/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Sloweens"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turks"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Oekraïens"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabies"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grieks"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreeus"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litaus"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spaans (Latyn)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-am/strings.xml b/packages/InputDevices/res/values-am/strings.xml
index 09b65e0..d475772 100644
--- a/packages/InputDevices/res/values-am/strings.xml
+++ b/packages/InputDevices/res/values-am/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"ስሎቫኒያ"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"ቱርክኛ"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ዩክሬን"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"አረብኛ"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"ግሪክኛ"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ዕብራስጥ"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ሊቱዌኒያኛ"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ስፓኒሽ (ላቲን)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ar/strings.xml b/packages/InputDevices/res/values-ar/strings.xml
index 4c5cccc..903d978 100644
--- a/packages/InputDevices/res/values-ar/strings.xml
+++ b/packages/InputDevices/res/values-ar/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"السلوفينية"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"التركية"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"الأوكرانية"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"العربية"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"اليونانية"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"العبرية"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"الليتوانية"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"الإسبانية (اللاتينية)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-bg/strings.xml b/packages/InputDevices/res/values-bg/strings.xml
index cc3eb36..0c413a4 100644
--- a/packages/InputDevices/res/values-bg/strings.xml
+++ b/packages/InputDevices/res/values-bg/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"словенски"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"турски"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"украински"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Арабска клавиатурна подредба"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Гръцка клавиатурна подредба"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ивритска клавиатурна подредба"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Литовска клавиатурна подредба"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Исп. клав. подредба (Лат. Америка)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ca/strings.xml b/packages/InputDevices/res/values-ca/strings.xml
index 2c8521c..2021b8f 100644
--- a/packages/InputDevices/res/values-ca/strings.xml
+++ b/packages/InputDevices/res/values-ca/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Eslovè"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turc"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraïnès"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Àrab"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grec"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreu"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituà"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espanyol (llatí)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-cs/strings.xml b/packages/InputDevices/res/values-cs/strings.xml
index 9b65eed..33b420e 100644
--- a/packages/InputDevices/res/values-cs/strings.xml
+++ b/packages/InputDevices/res/values-cs/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovinské"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"turecké"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrajinské"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arabština"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"řečtina"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrejština"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litevština"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španělština (Latinská Amerika)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-da/strings.xml b/packages/InputDevices/res/values-da/strings.xml
index 8b423ab..fc07db2 100644
--- a/packages/InputDevices/res/values-da/strings.xml
+++ b/packages/InputDevices/res/values-da/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovensk"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Tyrkisk"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainsk"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabisk"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Græsk"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebræisk"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauisk"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spansk (latinamerika)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-de/strings.xml b/packages/InputDevices/res/values-de/strings.xml
index b5a5870..b5c3b50 100644
--- a/packages/InputDevices/res/values-de/strings.xml
+++ b/packages/InputDevices/res/values-de/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slowenisch"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Türkisch"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainisch"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabisch"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Griechisch"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebräisch"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauisch"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanisch (Lateinisch)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-el/strings.xml b/packages/InputDevices/res/values-el/strings.xml
index 976f370..f5d57a0 100644
--- a/packages/InputDevices/res/values-el/strings.xml
+++ b/packages/InputDevices/res/values-el/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Σλοβενικά"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Τουρκικά"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ουκρανικά"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Αραβικά"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Ελληνικά"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Εβραϊκά"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Λιθουανικά"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Ισπανικά (Λατινικής Αμερικής)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-en-rGB/strings.xml b/packages/InputDevices/res/values-en-rGB/strings.xml
index 50a98b26..2d794a6 100644
--- a/packages/InputDevices/res/values-en-rGB/strings.xml
+++ b/packages/InputDevices/res/values-en-rGB/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenian"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkish"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainian"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabic"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Greek"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrew"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lithuanian"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-en-rIN/strings.xml b/packages/InputDevices/res/values-en-rIN/strings.xml
index 50a98b26..2d794a6 100644
--- a/packages/InputDevices/res/values-en-rIN/strings.xml
+++ b/packages/InputDevices/res/values-en-rIN/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenian"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkish"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainian"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabic"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Greek"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrew"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lithuanian"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-es-rUS/strings.xml b/packages/InputDevices/res/values-es-rUS/strings.xml
index b842a3b..2d61b80 100644
--- a/packages/InputDevices/res/values-es-rUS/strings.xml
+++ b/packages/InputDevices/res/values-es-rUS/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Esloveno"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turco"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraniano"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Árabe"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Griego"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreo"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Español (latino)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-es/strings.xml b/packages/InputDevices/res/values-es/strings.xml
index 5dc85a0..82ea4d6 100644
--- a/packages/InputDevices/res/values-es/strings.xml
+++ b/packages/InputDevices/res/values-es/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Esloveno"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turco"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraniano"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Árabe"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Griego"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreo"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Español (Latinoamérica)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-et-rEE/strings.xml b/packages/InputDevices/res/values-et-rEE/strings.xml
index 4ffdb37..5b4fa3b 100644
--- a/packages/InputDevices/res/values-et-rEE/strings.xml
+++ b/packages/InputDevices/res/values-et-rEE/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Sloveenia"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Türgi"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraina"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Araabia"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Kreeka"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Heebrea"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Leedu"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Hispaania (Ladina-Ameerika)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-fa/strings.xml b/packages/InputDevices/res/values-fa/strings.xml
index fd6f54b..06c7f3a 100644
--- a/packages/InputDevices/res/values-fa/strings.xml
+++ b/packages/InputDevices/res/values-fa/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"اسلوونیایی"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"ترکی"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"اوکراینی"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"عربی"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"یونانی"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"عبری"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"لیتوانیایی"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"اسپانیایی (لاتین)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-fi/strings.xml b/packages/InputDevices/res/values-fi/strings.xml
index b7ec183..428eb30 100644
--- a/packages/InputDevices/res/values-fi/strings.xml
+++ b/packages/InputDevices/res/values-fi/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"sloveeni"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"turkki"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukraina"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arabia"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"kreikka"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"heprea"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"liettua"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"espanja (Latinalainen Amerikka)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-fr-rCA/strings.xml b/packages/InputDevices/res/values-fr-rCA/strings.xml
index 18600ed..c947634 100644
--- a/packages/InputDevices/res/values-fr-rCA/strings.xml
+++ b/packages/InputDevices/res/values-fr-rCA/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovène"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turc"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainien"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabe"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grec"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hébreu"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituanien"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espagnol (latin)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-fr/strings.xml b/packages/InputDevices/res/values-fr/strings.xml
index e3ca49c..4ad4ffa 100644
--- a/packages/InputDevices/res/values-fr/strings.xml
+++ b/packages/InputDevices/res/values-fr/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovène"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turc"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainien"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabe"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grec"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hébreu"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituanien"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espagnol (latin)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-hi/strings.xml b/packages/InputDevices/res/values-hi/strings.xml
index a1a4ef2..8e1864e 100644
--- a/packages/InputDevices/res/values-hi/strings.xml
+++ b/packages/InputDevices/res/values-hi/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"स्लोवेनियाई"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"तुर्की"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"यूक्रेनियाई"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"अरबी"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"ग्रीक"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"हिब्रू"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"लिथुआनियाई"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"स्पेनिश (लैटिन)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-hr/strings.xml b/packages/InputDevices/res/values-hr/strings.xml
index 512ffd7..6217bf0 100644
--- a/packages/InputDevices/res/values-hr/strings.xml
+++ b/packages/InputDevices/res/values-hr/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovenska"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"turska"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrajinska"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arapski"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"grčki"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrejski"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litavski"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španjolski (Latinska Amerika)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-hu/strings.xml b/packages/InputDevices/res/values-hu/strings.xml
index 645e597..0cdbfb2 100644
--- a/packages/InputDevices/res/values-hu/strings.xml
+++ b/packages/InputDevices/res/values-hu/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"szlovén"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"török"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrán"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arab"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"görög"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"héber"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litván"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"spanyol (latin-amerikai)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-hy-rAM/strings.xml b/packages/InputDevices/res/values-hy-rAM/strings.xml
index 282dc82..bc5bbfc 100644
--- a/packages/InputDevices/res/values-hy-rAM/strings.xml
+++ b/packages/InputDevices/res/values-hy-rAM/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Սլովեներեն"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Թուրքերեն"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ուկրաիներեն"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Արաբերեն"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Հունարեն"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Եբրայերեն"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Լիտվերեն"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Իսպաներեն (Լատինական)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-in/strings.xml b/packages/InputDevices/res/values-in/strings.xml
index a7fc330..11e2dd0a 100644
--- a/packages/InputDevices/res/values-in/strings.xml
+++ b/packages/InputDevices/res/values-in/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenia"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turki"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraina"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arab"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Yunani"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ibrani"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lithuania"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanyol (Latin)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-it/strings.xml b/packages/InputDevices/res/values-it/strings.xml
index e8fe310..334318e 100644
--- a/packages/InputDevices/res/values-it/strings.xml
+++ b/packages/InputDevices/res/values-it/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Sloveno"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turco"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraino"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabo"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Greco"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ebraico"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spagnolo (America Latina)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-iw/strings.xml b/packages/InputDevices/res/values-iw/strings.xml
index d2673d9..a989391 100644
--- a/packages/InputDevices/res/values-iw/strings.xml
+++ b/packages/InputDevices/res/values-iw/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"סלובנית"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"טורקית"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"אוקראינית"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"ערבית"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"יוונית"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"עברית"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ליטאית"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ספרדית (לטינית)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ja/strings.xml b/packages/InputDevices/res/values-ja/strings.xml
index 86cd30e..950b727 100644
--- a/packages/InputDevices/res/values-ja/strings.xml
+++ b/packages/InputDevices/res/values-ja/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"スロベニア語"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"トルコ語"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ウクライナ語"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"アラビア語"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"ギリシャ語"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ヘブライ語"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"リトアニア語"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"スペイン語(中南米)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ka-rGE/strings.xml b/packages/InputDevices/res/values-ka-rGE/strings.xml
index 14ebee8..6e507aa 100644
--- a/packages/InputDevices/res/values-ka-rGE/strings.xml
+++ b/packages/InputDevices/res/values-ka-rGE/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"სლოვენური"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"თურქული"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"უკრაინული"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"არაბული"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"ბერძნული"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ებრაული"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ლიტვური"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ესპანური (ლათინური)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-km-rKH/strings.xml b/packages/InputDevices/res/values-km-rKH/strings.xml
index 569f273..9a8c99b 100644
--- a/packages/InputDevices/res/values-km-rKH/strings.xml
+++ b/packages/InputDevices/res/values-km-rKH/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"ស្លូវ៉ានី"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"ទួរគី"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"អ៊ុយក្រែន"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"អារ៉ាប់"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"ក្រិក"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"អ៊ីស្រាអែល"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"លីទុយអានី"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"អេស្ប៉ាញ (ឡាតាំង)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ko/strings.xml b/packages/InputDevices/res/values-ko/strings.xml
index dbbe6ea..8071586 100644
--- a/packages/InputDevices/res/values-ko/strings.xml
+++ b/packages/InputDevices/res/values-ko/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"슬로베니아어"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"터키어"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"우크라이나어"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"아랍어"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"그리스어"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"히브리어"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"리투아니아어"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"스페인어(라틴)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-lo-rLA/strings.xml b/packages/InputDevices/res/values-lo-rLA/strings.xml
index eaf5026..2c97e11 100644
--- a/packages/InputDevices/res/values-lo-rLA/strings.xml
+++ b/packages/InputDevices/res/values-lo-rLA/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"ສະໂລເວນຽນ"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"ເຕີກິສ"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ຢູເຄຣນຽນ"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"ອາຣັບ"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"ກຣີກ"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ຮີບຣິວ"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ລິທົວນຽນ"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"ສະແປນນິດ (ລາຕິນ)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-lt/strings.xml b/packages/InputDevices/res/values-lt/strings.xml
index 2fcacde..c0ed159 100644
--- a/packages/InputDevices/res/values-lt/strings.xml
+++ b/packages/InputDevices/res/values-lt/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovėnų k."</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkų k."</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainiečių k."</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabų"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Graikų"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrajų"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lietuvių"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Ispanų (Lotynų Amerika)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-lv/strings.xml b/packages/InputDevices/res/values-lv/strings.xml
index 921c881..07a8654 100644
--- a/packages/InputDevices/res/values-lv/strings.xml
+++ b/packages/InputDevices/res/values-lv/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovēņu"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turku"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraiņu"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arābu"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grieķu"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ivrits"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lietuviešu"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spāņu (latīņu)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-mn-rMN/strings.xml b/packages/InputDevices/res/values-mn-rMN/strings.xml
index c99339e..ec6cccb 100644
--- a/packages/InputDevices/res/values-mn-rMN/strings.xml
+++ b/packages/InputDevices/res/values-mn-rMN/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Словени"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Турк"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Украйн"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Араб"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Грек"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Еврей"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Литви"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Испани (Латин)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ms-rMY/strings.xml b/packages/InputDevices/res/values-ms-rMY/strings.xml
index 32041d0..486f048 100644
--- a/packages/InputDevices/res/values-ms-rMY/strings.xml
+++ b/packages/InputDevices/res/values-ms-rMY/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Bahasa Slovenia"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Bahasa Turki"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Bahasa Ukraine"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Bahasa Arab"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Bahasa Greek"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Bahasa Ibrani"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Bahasa Lithuania"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Bahasa Sepanyol (Latin)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-nb/strings.xml b/packages/InputDevices/res/values-nb/strings.xml
index e880981..b646061 100644
--- a/packages/InputDevices/res/values-nb/strings.xml
+++ b/packages/InputDevices/res/values-nb/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovensk"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Tyrkisk"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainsk"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabisk"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Gresk"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebraisk"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauisk"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spansk (latinsk)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-nl/strings.xml b/packages/InputDevices/res/values-nl/strings.xml
index 92a9fcf..56d84c9 100644
--- a/packages/InputDevices/res/values-nl/strings.xml
+++ b/packages/InputDevices/res/values-nl/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Sloveens"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turks"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Oekraïens"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabisch"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grieks"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreeuws"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litouws"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spaans (Latijns-Amerika)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-pl/strings.xml b/packages/InputDevices/res/values-pl/strings.xml
index f84252a..4522215 100644
--- a/packages/InputDevices/res/values-pl/strings.xml
+++ b/packages/InputDevices/res/values-pl/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Słoweński"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turecki"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraiński"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arabski"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"grecki"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrajski"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litewski"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"hiszpański (Ameryka Łacińska)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-pt-rPT/strings.xml b/packages/InputDevices/res/values-pt-rPT/strings.xml
index 670badd..9a639cd 100644
--- a/packages/InputDevices/res/values-pt-rPT/strings.xml
+++ b/packages/InputDevices/res/values-pt-rPT/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Esloveno"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turco"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraniano"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Árabe"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grego"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebraico"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espanhol (América Latina)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-pt/strings.xml b/packages/InputDevices/res/values-pt/strings.xml
index 71274aa..05a0cd0 100644
--- a/packages/InputDevices/res/values-pt/strings.xml
+++ b/packages/InputDevices/res/values-pt/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Esloveno"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turco"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraniano"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Árabe"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grego"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebraico"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituano"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Espanhol (América Latina)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ro/strings.xml b/packages/InputDevices/res/values-ro/strings.xml
index 151c11d..895d8f6 100644
--- a/packages/InputDevices/res/values-ro/strings.xml
+++ b/packages/InputDevices/res/values-ro/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenă"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turcă"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ucraineană"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabă"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Greacă"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Ebraică"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lituaniană"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spaniolă (America Latină)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ru/strings.xml b/packages/InputDevices/res/values-ru/strings.xml
index 585a215..a4cbfd7 100644
--- a/packages/InputDevices/res/values-ru/strings.xml
+++ b/packages/InputDevices/res/values-ru/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"словенский"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"турецкий"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"украинский"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Арабский"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Греческий"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Иврит"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Литовский"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Испанский (Латинская Америка)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sk/strings.xml b/packages/InputDevices/res/values-sk/strings.xml
index d14c204..01ab042 100644
--- a/packages/InputDevices/res/values-sk/strings.xml
+++ b/packages/InputDevices/res/values-sk/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovinské"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"turecké"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrajinské"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabčina"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Gréčtina"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrejčina"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litovčina"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Španielčina (Latinská Amerika)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sl/strings.xml b/packages/InputDevices/res/values-sl/strings.xml
index b8fc823e..30ff3c4 100644
--- a/packages/InputDevices/res/values-sl/strings.xml
+++ b/packages/InputDevices/res/values-sl/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovenska"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"turška"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrajinska"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arabščina"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"grščina"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrejščina"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litovščina"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španščina (Latinska Amerika)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sr/strings.xml b/packages/InputDevices/res/values-sr/strings.xml
index 45e0b4b..d23ac00 100644
--- a/packages/InputDevices/res/values-sr/strings.xml
+++ b/packages/InputDevices/res/values-sr/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"словеначка"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"турска"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"украјинска"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"арапски"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"грчки"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"хебрејски"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"литвански"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"шпански (Латинска Америка)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sv/strings.xml b/packages/InputDevices/res/values-sv/strings.xml
index ce20bff..25a5ae8 100644
--- a/packages/InputDevices/res/values-sv/strings.xml
+++ b/packages/InputDevices/res/values-sv/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenskt"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkiskt"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainskt"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabiska"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grekiska"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreiska"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauiska"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanska (latinamerikansk)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-sw/strings.xml b/packages/InputDevices/res/values-sw/strings.xml
index 38bc83a..65ab96a1 100644
--- a/packages/InputDevices/res/values-sw/strings.xml
+++ b/packages/InputDevices/res/values-sw/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Kislovenia"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Kituruki"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Kiukrania"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Kiarabu"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Kigiriki"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Kiyahudi"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Kilithuania"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Kihispania (Kilatini)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-th/strings.xml b/packages/InputDevices/res/values-th/strings.xml
index 8951281..0cc7d47 100644
--- a/packages/InputDevices/res/values-th/strings.xml
+++ b/packages/InputDevices/res/values-th/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"สโลวีเนีย"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"ตุรกี"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ยูเครน"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"ภาษาอารบิค"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"กรีก"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"ฮิบรู"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"ลิทัวเนีย"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"สเปน (ละติน)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-tl/strings.xml b/packages/InputDevices/res/values-tl/strings.xml
index c551e20..08f34d2 100644
--- a/packages/InputDevices/res/values-tl/strings.xml
+++ b/packages/InputDevices/res/values-tl/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenian"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkish"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainian"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabic"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Greek"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebrew"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Lithuanian"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanish (Latin)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-tr/strings.xml b/packages/InputDevices/res/values-tr/strings.xml
index d828e78..f7c1262 100644
--- a/packages/InputDevices/res/values-tr/strings.xml
+++ b/packages/InputDevices/res/values-tr/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovence"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Türkçe"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukraynaca"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arapça"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Yunanca"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"İbranice"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litvanca"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"İspanyolca (Latin)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-uk/strings.xml b/packages/InputDevices/res/values-uk/strings.xml
index b4b9923..ee6ffc7 100644
--- a/packages/InputDevices/res/values-uk/strings.xml
+++ b/packages/InputDevices/res/values-uk/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"словенська"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"турецька"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"українська"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Арабська"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Грецька"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Іврит"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Литовська"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Іспанська (латиниця)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-vi/strings.xml b/packages/InputDevices/res/values-vi/strings.xml
index 18aa989..7a65e45 100644
--- a/packages/InputDevices/res/values-vi/strings.xml
+++ b/packages/InputDevices/res/values-vi/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Tiếng Sloven"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Tiếng Thổ Nhĩ Kỳ"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Tiếng Ukraina"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Tiếng Ả rập"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Tiếng Hy Lạp"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Tiếng Do Thái"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Tiếng Lithuania"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Tiếng Tây Ban Nha (La tinh)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-zh-rCN/strings.xml b/packages/InputDevices/res/values-zh-rCN/strings.xml
index 8d76f92..85b1c84 100644
--- a/packages/InputDevices/res/values-zh-rCN/strings.xml
+++ b/packages/InputDevices/res/values-zh-rCN/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"斯洛文尼亚语"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"土耳其语"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"乌克兰语"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"阿拉伯语"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"希腊语"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"希伯来语"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"立陶宛语"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"西班牙语(拉丁美洲)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-zh-rHK/strings.xml b/packages/InputDevices/res/values-zh-rHK/strings.xml
index 031f294..839c546 100644
--- a/packages/InputDevices/res/values-zh-rHK/strings.xml
+++ b/packages/InputDevices/res/values-zh-rHK/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"斯洛文尼亞文"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"土耳其文"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"烏克蘭文"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"阿拉伯文"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"希臘文"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"希伯來文"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"立陶宛文"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"西班牙文 (拉丁美洲)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-zh-rTW/strings.xml b/packages/InputDevices/res/values-zh-rTW/strings.xml
index 76cb6a2..ba9f132 100644
--- a/packages/InputDevices/res/values-zh-rTW/strings.xml
+++ b/packages/InputDevices/res/values-zh-rTW/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"斯洛維尼亞文"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"土耳其文"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"烏克蘭文"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"阿拉伯文"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"希臘文"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"希伯來文"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"立陶宛文"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"西班牙文 (拉丁美洲)"</string>
</resources>
diff --git a/packages/InputDevices/res/values-zu/strings.xml b/packages/InputDevices/res/values-zu/strings.xml
index 3e4ad67..fbf1074 100644
--- a/packages/InputDevices/res/values-zu/strings.xml
+++ b/packages/InputDevices/res/values-zu/strings.xml
@@ -34,9 +34,4 @@
<string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Isi-Slovenian"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Isi-Turkish"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Isi-Ukrainian"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Isi-Arabic"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Isi-Greek"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Isi-Hebrew"</string>
- <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Isi-Lithuanian"</string>
- <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Isi-Spanish (Latin)"</string>
</resources>
diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml
index 546ddd4..0d943ed 100644
--- a/packages/Keyguard/res/layout/keyguard_status_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -28,7 +28,7 @@
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
androidprv:layout_maxHeight="@dimen/keyguard_security_height"
android:gravity="center_horizontal|top"
- android:layout_marginTop="32dp"
+ android:layout_marginTop="48dp"
android:layout_marginBottom="32dp"
android:contentDescription="@string/keyguard_accessibility_status">
<LinearLayout
diff --git a/packages/Keyguard/res/values-af/strings.xml b/packages/Keyguard/res/values-af/strings.xml
index a046dc5..2667ed2 100644
--- a/packages/Keyguard/res/values-af/strings.xml
+++ b/packages/Keyguard/res/values-af/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Voer PIN-kode in"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Voer SIM PUK- en nuwe PIN-kode in"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK-kode"</string>
diff --git a/packages/Keyguard/res/values-am/strings.xml b/packages/Keyguard/res/values-am/strings.xml
index 0bb7993..fd4cf78 100644
--- a/packages/Keyguard/res/values-am/strings.xml
+++ b/packages/Keyguard/res/values-am/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"የቁልፍ ጥበቃ"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"ፒን ኮድ ተይብ"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"የሲም PUK እና አዲሱን ፒን ኮድ ይተይቡ"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"የሲም PUK ኮድ"</string>
@@ -28,7 +27,7 @@
<string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"የይለፍ ቃል ለመተየብ ንካ"</font></string>
<string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"ለመክፈት የይለፍ ቃል ተይብ"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"ለመክፈት ፒን ተይብ"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ትክክል ያልሆነ ፒን ኮድ።"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ትክክል ያልሆነ PIN ኮድ።"</string>
<string name="keyguard_label_text" msgid="861796461028298424">"ለመክፈት፣ምናሌ ተጫን ከዛ 0"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"የመጨረሻውን የገጽ ክፈት ሙከራዎችን አልፏል"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"ባትሪ ሞልቷል"</string>
@@ -83,7 +82,7 @@
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
- <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ይቅር"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ተወው"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ሰርዝ"</string>
<string name="keyboardview_keycode_done" msgid="1992571118466679775">"ተከናውኗል"</string>
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ሞድ ለውጥ"</string>
diff --git a/packages/Keyguard/res/values-ar/strings.xml b/packages/Keyguard/res/values-ar/strings.xml
index eac3216..83d4b93 100644
--- a/packages/Keyguard/res/values-ar/strings.xml
+++ b/packages/Keyguard/res/values-ar/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"اكتب رمز رمز PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"أدخل رمز PUK لبطاقة SIM ورمز \"رقم التعريف الشخصي\" الجديد"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"رمز PUK لبطاقة SIM"</string>
diff --git a/packages/Keyguard/res/values-bg/strings.xml b/packages/Keyguard/res/values-bg/strings.xml
index ad4285a..641adbd 100644
--- a/packages/Keyguard/res/values-bg/strings.xml
+++ b/packages/Keyguard/res/values-bg/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Въведете ПИН кода"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Въведете PUK за SIM картата и новия ПИН код"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK код за SIM картата"</string>
diff --git a/packages/Keyguard/res/values-ca/strings.xml b/packages/Keyguard/res/values-ca/strings.xml
index 7e40709..8b81086 100644
--- a/packages/Keyguard/res/values-ca/strings.xml
+++ b/packages/Keyguard/res/values-ca/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Bloqueig de teclat"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Introdueix el codi PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Escriu el PUK de la SIM i el codi PIN nou."</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Codi PUK de la SIM"</string>
diff --git a/packages/Keyguard/res/values-cs/strings.xml b/packages/Keyguard/res/values-cs/strings.xml
index 53cc707..e4ed02a 100644
--- a/packages/Keyguard/res/values-cs/strings.xml
+++ b/packages/Keyguard/res/values-cs/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Uzamčení kláves"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Zadejte kód PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Zadejte kód PUK SIM karty a nový kód PIN."</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Kód PUK SIM karty"</string>
diff --git a/packages/Keyguard/res/values-da/strings.xml b/packages/Keyguard/res/values-da/strings.xml
index cf1aad9..f8f0a6f 100644
--- a/packages/Keyguard/res/values-da/strings.xml
+++ b/packages/Keyguard/res/values-da/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Tastaturlås"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Indtast pinkode"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Indtast PUK-koden til SIM-kortet og den nye pinkode"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK-kode til SIM-kort"</string>
diff --git a/packages/Keyguard/res/values-de/strings.xml b/packages/Keyguard/res/values-de/strings.xml
index 14df237..edbbffd 100644
--- a/packages/Keyguard/res/values-de/strings.xml
+++ b/packages/Keyguard/res/values-de/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PIN-Code eingeben"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Geben Sie den PUK-Code der SIM-Karte und den neuen PIN-Code ein."</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK-Code der SIM-Karte"</string>
diff --git a/packages/Keyguard/res/values-el/strings.xml b/packages/Keyguard/res/values-el/strings.xml
index 63d8409..be07dcd 100644
--- a/packages/Keyguard/res/values-el/strings.xml
+++ b/packages/Keyguard/res/values-el/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Πληκτρολογήστε τον κωδικό αριθμό PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Πληκτρολογήστε τον κωδικό PUK της κάρτας SIM και τον νέο κωδικό PIN"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Κωδικός PUK κάρτας SIM"</string>
diff --git a/packages/Keyguard/res/values-en-rGB/strings.xml b/packages/Keyguard/res/values-en-rGB/strings.xml
index ecc850d..f0d81b8 100644
--- a/packages/Keyguard/res/values-en-rGB/strings.xml
+++ b/packages/Keyguard/res/values-en-rGB/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Type PIN code"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Type SIM PUK and new PIN code"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK code"</string>
diff --git a/packages/Keyguard/res/values-en-rIN/strings.xml b/packages/Keyguard/res/values-en-rIN/strings.xml
index ecc850d..f0d81b8 100644
--- a/packages/Keyguard/res/values-en-rIN/strings.xml
+++ b/packages/Keyguard/res/values-en-rIN/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Type PIN code"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Type SIM PUK and new PIN code"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK code"</string>
diff --git a/packages/Keyguard/res/values-es-rUS/strings.xml b/packages/Keyguard/res/values-es-rUS/strings.xml
index c6d63ba..38beca3 100644
--- a/packages/Keyguard/res/values-es-rUS/strings.xml
+++ b/packages/Keyguard/res/values-es-rUS/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Bloqueo de teclado"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ingresa el código PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Escribe el código PUK de la tarjeta SIM y un nuevo código PIN."</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Código PUK de la tarjeta SIM"</string>
diff --git a/packages/Keyguard/res/values-es/strings.xml b/packages/Keyguard/res/values-es/strings.xml
index 8a78399..a93b10d 100644
--- a/packages/Keyguard/res/values-es/strings.xml
+++ b/packages/Keyguard/res/values-es/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Bloqueo"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Introduce el código PIN."</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Escribe el PUK de la tarjeta SIM y un nuevo código PIN"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Código PUK de la tarjeta SIM"</string>
diff --git a/packages/Keyguard/res/values-et-rEE/strings.xml b/packages/Keyguard/res/values-et-rEE/strings.xml
index b837f01..90bd829 100644
--- a/packages/Keyguard/res/values-et-rEE/strings.xml
+++ b/packages/Keyguard/res/values-et-rEE/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Klahvilukk"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Sisestage PIN-kood"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Sisestage SIM-i PUK- ja uus PIN-kood"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM-i PUK-kood"</string>
diff --git a/packages/Keyguard/res/values-fa/strings.xml b/packages/Keyguard/res/values-fa/strings.xml
index 5d1c487..b4a4c61 100644
--- a/packages/Keyguard/res/values-fa/strings.xml
+++ b/packages/Keyguard/res/values-fa/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"پین کد را وارد کنید"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"PUK سیم کارت و کد پین جدید را تایپ کنید"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"کد PUK سیم کارت"</string>
diff --git a/packages/Keyguard/res/values-fi/strings.xml b/packages/Keyguard/res/values-fi/strings.xml
index bdf6677..e079ffa 100644
--- a/packages/Keyguard/res/values-fi/strings.xml
+++ b/packages/Keyguard/res/values-fi/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Näppäinvahti"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Anna PIN-koodi"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Anna SIM-kortin PUK-koodi ja uusi PIN-koodi"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM-kortin PUK-koodi"</string>
diff --git a/packages/Keyguard/res/values-fr-rCA/strings.xml b/packages/Keyguard/res/values-fr-rCA/strings.xml
index e77927c..59f27aa 100644
--- a/packages/Keyguard/res/values-fr-rCA/strings.xml
+++ b/packages/Keyguard/res/values-fr-rCA/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Verrouillage du clavier"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Saisissez le NIP."</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Entrez le code PUK et le nouveau NIP de la carte SIM"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Code PUK de la carte SIM"</string>
diff --git a/packages/Keyguard/res/values-fr/strings.xml b/packages/Keyguard/res/values-fr/strings.xml
index 41be1eb..b910dd4 100644
--- a/packages/Keyguard/res/values-fr/strings.xml
+++ b/packages/Keyguard/res/values-fr/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Protection des touches"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Saisissez le code PIN."</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Saisissez la clé PUK et le nouveau code PIN de la carte SIM."</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Clé PUK de la carte SIM"</string>
diff --git a/packages/Keyguard/res/values-hi/strings.xml b/packages/Keyguard/res/values-hi/strings.xml
index c963beb..8c94eb3 100644
--- a/packages/Keyguard/res/values-hi/strings.xml
+++ b/packages/Keyguard/res/values-hi/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"कीगार्ड"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"पिन कोड लिखें"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"सिम PUK और नया PIN कोड लिखें"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"सिम PUK कोड"</string>
diff --git a/packages/Keyguard/res/values-hr/strings.xml b/packages/Keyguard/res/values-hr/strings.xml
index 6bbdd51..3843549 100644
--- a/packages/Keyguard/res/values-hr/strings.xml
+++ b/packages/Keyguard/res/values-hr/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Zaštita tipkovnice"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Unesite PIN kôd"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Unesite PUK i novi PIN kôd SIM kartice"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK kôd SIM kartice"</string>
diff --git a/packages/Keyguard/res/values-hu/strings.xml b/packages/Keyguard/res/values-hu/strings.xml
index 9706874..bf6f528 100644
--- a/packages/Keyguard/res/values-hu/strings.xml
+++ b/packages/Keyguard/res/values-hu/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Billentyűzár"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Írja be a PIN kódot"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Írja be a SIM kártya PUK kódját, majd az új PIN kódot"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM kártya PUK kódja"</string>
diff --git a/packages/Keyguard/res/values-hy-rAM/strings.xml b/packages/Keyguard/res/values-hy-rAM/strings.xml
index 60c626d..ff87920 100644
--- a/packages/Keyguard/res/values-hy-rAM/strings.xml
+++ b/packages/Keyguard/res/values-hy-rAM/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Մուտքագրեք PIN կոդը"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Մուտքագրեք SIM PUK-ը և նոր PIN կոդը"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK կոդը"</string>
diff --git a/packages/Keyguard/res/values-in/strings.xml b/packages/Keyguard/res/values-in/strings.xml
index 9ea5a29..9e19472 100644
--- a/packages/Keyguard/res/values-in/strings.xml
+++ b/packages/Keyguard/res/values-in/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ketik kode PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Ketik kode PIN baru dan PUK SIM"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Kode PUK SIM"</string>
diff --git a/packages/Keyguard/res/values-it/strings.xml b/packages/Keyguard/res/values-it/strings.xml
index 2a481e6..7212e5e 100644
--- a/packages/Keyguard/res/values-it/strings.xml
+++ b/packages/Keyguard/res/values-it/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Inserisci il codice PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Digita il PUK della SIM e il nuovo codice PIN"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Codice PUK della SIM"</string>
diff --git a/packages/Keyguard/res/values-iw/strings.xml b/packages/Keyguard/res/values-iw/strings.xml
index a6a3192..12b45e4 100644
--- a/packages/Keyguard/res/values-iw/strings.xml
+++ b/packages/Keyguard/res/values-iw/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"מגן מקלדת"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"הקלד קוד PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"הקלד קוד PUK של כרטיס SIM וקוד PIN חדש"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"קוד PUK של כרטיס SIM"</string>
diff --git a/packages/Keyguard/res/values-ja/strings.xml b/packages/Keyguard/res/values-ja/strings.xml
index b683a9d..5106271 100644
--- a/packages/Keyguard/res/values-ja/strings.xml
+++ b/packages/Keyguard/res/values-ja/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"キーガード"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PINコードを入力"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"PUKと新しいPINコードを入力"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUKコード"</string>
diff --git a/packages/Keyguard/res/values-ka-rGE/strings.xml b/packages/Keyguard/res/values-ka-rGE/strings.xml
index 4414096..3d7af75 100644
--- a/packages/Keyguard/res/values-ka-rGE/strings.xml
+++ b/packages/Keyguard/res/values-ka-rGE/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"აკრიფეთ PIN კოდი"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"დაბეჭდეთ SIM-ის PUK კოდი და ახალი PIN კოდი"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK კოდი"</string>
diff --git a/packages/Keyguard/res/values-km-rKH/strings.xml b/packages/Keyguard/res/values-km-rKH/strings.xml
index a2e54a7..f78b93d 100644
--- a/packages/Keyguard/res/values-km-rKH/strings.xml
+++ b/packages/Keyguard/res/values-km-rKH/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"ការពារគ្រាប់ចុច"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"បញ្ចូលកូដ PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"បញ្ចូលលេខកូដ PUK និង PIN ថ្មីរបស់ស៊ីម"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"លេខកូដ PUK ស៊ីម"</string>
@@ -83,7 +82,7 @@
<string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
<string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
- <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"បោះបង់"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"បោះបង់"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"លុប"</string>
<string name="keyboardview_keycode_done" msgid="1992571118466679775">"រួចរាល់"</string>
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ប្ដូររបៀប"</string>
@@ -120,7 +119,7 @@
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ព្យាយាមលំនាំច្រើនពេក"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"ដើម្បីដោះសោ ចូលក្នុងគណនី Google ។"</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"ឈ្មោះអ្នកប្រើ (អ៊ីម៉ែល)"</string>
- <string name="kg_login_password_hint" msgid="9057289103827298549">"ពាក្យសម្ងាត់"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"ពាក្យសម្ងាត់"</string>
<string name="kg_login_submit_button" msgid="5355904582674054702">"ចូល"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"ឈ្មោះអ្នកប្រើ ឬពាក្យសម្ងាត់មិនត្រឹមត្រូវ។"</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"ភ្លេចឈ្មោះអ្នកប្រើ ឬពាក្យសម្ងាត់របស់អ្នក?\nមើល "<b>"google.com/accounts/recovery"</b>" ។"</string>
diff --git a/packages/Keyguard/res/values-ko/strings.xml b/packages/Keyguard/res/values-ko/strings.xml
index cde2b1c..2a7200c 100644
--- a/packages/Keyguard/res/values-ko/strings.xml
+++ b/packages/Keyguard/res/values-ko/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"키가드"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PIN 코드 입력"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"SIM PUK 및 새 PIN 코드 입력"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK 코드"</string>
diff --git a/packages/Keyguard/res/values-lo-rLA/strings.xml b/packages/Keyguard/res/values-lo-rLA/strings.xml
index 0571768..81c10181 100644
--- a/packages/Keyguard/res/values-lo-rLA/strings.xml
+++ b/packages/Keyguard/res/values-lo-rLA/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"ພິມລະຫັດ PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"ປະເພດ PUK ຂອງ SIM ແລະລະຫັດ PIN ໃໝ່"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"ລະຫັດ PUK ຂອງ SIM"</string>
diff --git a/packages/Keyguard/res/values-lt/strings.xml b/packages/Keyguard/res/values-lt/strings.xml
index 0fd6605..ff3034a 100644
--- a/packages/Keyguard/res/values-lt/strings.xml
+++ b/packages/Keyguard/res/values-lt/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Klaviatūros apsauga"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Įveskite PIN kodą"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Įveskite SIM kortelės PUK kodą ir naują PIN kodą"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM kortelės PUK kodas"</string>
diff --git a/packages/Keyguard/res/values-lv/strings.xml b/packages/Keyguard/res/values-lv/strings.xml
index 2bcde1d..539f91d 100644
--- a/packages/Keyguard/res/values-lv/strings.xml
+++ b/packages/Keyguard/res/values-lv/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Taustiņslēgs"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ievadiet PIN kodu."</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Ievadiet SIM kartes PUK kodu un jaunu PIN kodu."</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM kartes PUK kods"</string>
diff --git a/packages/Keyguard/res/values-mn-rMN/strings.xml b/packages/Keyguard/res/values-mn-rMN/strings.xml
index 7bb819d..e1b833e 100644
--- a/packages/Keyguard/res/values-mn-rMN/strings.xml
+++ b/packages/Keyguard/res/values-mn-rMN/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PIN кодыг бичнэ үү"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"СИМ ПҮК-г бичээд шинэ ПИН код оруулна уу"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"СИМ ПҮК код"</string>
diff --git a/packages/Keyguard/res/values-ms-rMY/strings.xml b/packages/Keyguard/res/values-ms-rMY/strings.xml
index b4c1b46..a6845bc 100644
--- a/packages/Keyguard/res/values-ms-rMY/strings.xml
+++ b/packages/Keyguard/res/values-ms-rMY/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Pengawal kekunci"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Taip kod PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Taip PUK SIM dan kod PIN baharu"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Kod PUK SIM"</string>
diff --git a/packages/Keyguard/res/values-nb/strings.xml b/packages/Keyguard/res/values-nb/strings.xml
index 801e03d..71138a5 100644
--- a/packages/Keyguard/res/values-nb/strings.xml
+++ b/packages/Keyguard/res/values-nb/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Tastaturlås"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Skriv inn PIN-kode"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Skriv inn PUK-koden for SIM-kortet og en ny PIN-kode"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK-koden for SIM-kortet"</string>
diff --git a/packages/Keyguard/res/values-nl/strings.xml b/packages/Keyguard/res/values-nl/strings.xml
index 195f950..34149c9 100644
--- a/packages/Keyguard/res/values-nl/strings.xml
+++ b/packages/Keyguard/res/values-nl/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Toetsblokkering"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Pincode typen"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Typ de pukcode voor de simkaart en de nieuwe pincode"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Pukcode voor simkaart"</string>
diff --git a/packages/Keyguard/res/values-pl/strings.xml b/packages/Keyguard/res/values-pl/strings.xml
index 165b2c4..cfcbc46 100644
--- a/packages/Keyguard/res/values-pl/strings.xml
+++ b/packages/Keyguard/res/values-pl/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Blokada klawiszy"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Wpisz kod PIN."</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Wpisz PUK i nowy kod PIN karty SIM"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Kod PUK karty SIM"</string>
diff --git a/packages/Keyguard/res/values-pt-rPT/strings.xml b/packages/Keyguard/res/values-pt-rPT/strings.xml
index 332a943..abd4fcd 100644
--- a/packages/Keyguard/res/values-pt-rPT/strings.xml
+++ b/packages/Keyguard/res/values-pt-rPT/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Escreva o código PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Introduzir PUK do cartão SIM e o novo código PIN"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Código PUK do cartão SIM"</string>
diff --git a/packages/Keyguard/res/values-pt/strings.xml b/packages/Keyguard/res/values-pt/strings.xml
index a97b1b6..24d78e5 100644
--- a/packages/Keyguard/res/values-pt/strings.xml
+++ b/packages/Keyguard/res/values-pt/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Bloqueio do teclado"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Insira o código PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Digite o PUK do SIM e o novo código PIN."</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Código PUK do SIM"</string>
diff --git a/packages/Keyguard/res/values-rm/strings.xml b/packages/Keyguard/res/values-rm/strings.xml
index 4d71f27..ee26a3d 100644
--- a/packages/Keyguard/res/values-rm/strings.xml
+++ b/packages/Keyguard/res/values-rm/strings.xml
@@ -20,8 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_name (719438068451601849) -->
- <skip />
<!-- no translation found for keyguard_password_enter_pin_code (3037685796058495017) -->
<skip />
<!-- no translation found for keyguard_password_enter_puk_code (3035856550289724338) -->
diff --git a/packages/Keyguard/res/values-ro/strings.xml b/packages/Keyguard/res/values-ro/strings.xml
index 58bc337..1c7e88f 100644
--- a/packages/Keyguard/res/values-ro/strings.xml
+++ b/packages/Keyguard/res/values-ro/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Blocarea tastaturii"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Introduceţi codul PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Introduceți codul PUK pentru cardul SIM și codul PIN nou"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Codul PUK pentru cardul SIM"</string>
diff --git a/packages/Keyguard/res/values-ru/strings.xml b/packages/Keyguard/res/values-ru/strings.xml
index 866abc0..304f474 100644
--- a/packages/Keyguard/res/values-ru/strings.xml
+++ b/packages/Keyguard/res/values-ru/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Введите PIN-код"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Введите PUK-код и новый PIN-код"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK-код"</string>
diff --git a/packages/Keyguard/res/values-sk/strings.xml b/packages/Keyguard/res/values-sk/strings.xml
index 45e4288..cdf8ca9 100644
--- a/packages/Keyguard/res/values-sk/strings.xml
+++ b/packages/Keyguard/res/values-sk/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Zámka klávesnice"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Zadajte kód PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Zadajte kód PUK karty SIM a nový kód PIN"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Kód PUK karty SIM"</string>
@@ -36,7 +35,7 @@
<string name="keyguard_low_battery" msgid="8143808018719173859">"Pripojte nabíjačku."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Telefón odomknete stlačením tlačidla Menu."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Sieť je zablokovaná"</string>
- <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Nie je vložená karta SIM"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Nie je vložená karta SIM."</string>
<string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"V tablete nie je žiadna karta SIM."</string>
<string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"V telefóne nie je žiadna karta SIM."</string>
<string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Vložte kartu SIM."</string>
diff --git a/packages/Keyguard/res/values-sl/strings.xml b/packages/Keyguard/res/values-sl/strings.xml
index cf72e47..b0ec84e 100644
--- a/packages/Keyguard/res/values-sl/strings.xml
+++ b/packages/Keyguard/res/values-sl/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Vnesite kodo PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Vnesite kodo PUK in novo kodo PIN kartice SIM"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Koda PUK kartice SIM"</string>
diff --git a/packages/Keyguard/res/values-sr/strings.xml b/packages/Keyguard/res/values-sr/strings.xml
index bd08eae..2bdd8f5 100644
--- a/packages/Keyguard/res/values-sr/strings.xml
+++ b/packages/Keyguard/res/values-sr/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Заштита тастера"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Унесите PIN кôд"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Унесите SIM PUK кôд и нови PIN кôд"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK кôд"</string>
@@ -119,7 +118,7 @@
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN кодови се не подударају"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Превише покушаја уноса шаблона"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Да бисте откључали, пријавите се помоћу Google налога."</string>
- <string name="kg_login_username_hint" msgid="5718534272070920364">"Корисничко име (имејл адреса)"</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Корисничко име (адреса е-поште)"</string>
<string name="kg_login_password_hint" msgid="9057289103827298549">"Лозинка"</string>
<string name="kg_login_submit_button" msgid="5355904582674054702">"Пријави ме"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Неважеће корисничко име или лозинка."</string>
diff --git a/packages/Keyguard/res/values-sv/strings.xml b/packages/Keyguard/res/values-sv/strings.xml
index 1214100..e446f61 100644
--- a/packages/Keyguard/res/values-sv/strings.xml
+++ b/packages/Keyguard/res/values-sv/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ange PIN-kod"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Ange PUK-koden och en ny pinkod för SIM-kortet"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK-kod för SIM-kortet"</string>
diff --git a/packages/Keyguard/res/values-sw/strings.xml b/packages/Keyguard/res/values-sw/strings.xml
index fc1ce17..1d60a13 100644
--- a/packages/Keyguard/res/values-sw/strings.xml
+++ b/packages/Keyguard/res/values-sw/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Kilinda vitufe"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ingiza msimbo wa PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Chapa PUK ya SIM na msimbo mpya wa PIN"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Msimbo wa PUK ya SIM"</string>
diff --git a/packages/Keyguard/res/values-th/strings.xml b/packages/Keyguard/res/values-th/strings.xml
index 34d97c2..a44f9fe 100644
--- a/packages/Keyguard/res/values-th/strings.xml
+++ b/packages/Keyguard/res/values-th/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"การล็อกปุ่มกด"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"พิมพ์รหัส PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"พิมพ์ PUK และรหัส PIN ใหม่"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"รหัส PUK ของซิม"</string>
diff --git a/packages/Keyguard/res/values-tl/strings.xml b/packages/Keyguard/res/values-tl/strings.xml
index 9d97d22..6516766 100644
--- a/packages/Keyguard/res/values-tl/strings.xml
+++ b/packages/Keyguard/res/values-tl/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"I-type ang PIN code"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"I-type ang SIM PUK at bagong PIN code"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK code ng SIM"</string>
diff --git a/packages/Keyguard/res/values-tr/strings.xml b/packages/Keyguard/res/values-tr/strings.xml
index 1d8b982..aed8a47 100644
--- a/packages/Keyguard/res/values-tr/strings.xml
+++ b/packages/Keyguard/res/values-tr/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"PIN kodunu yazın"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"SIM PUK kodunu ve yeni bir PIN kodu yazın."</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK kodu"</string>
diff --git a/packages/Keyguard/res/values-uk/strings.xml b/packages/Keyguard/res/values-uk/strings.xml
index 16cf6cf..5e355e4 100644
--- a/packages/Keyguard/res/values-uk/strings.xml
+++ b/packages/Keyguard/res/values-uk/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Введіть PIN-код"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Введіть PUK-код і новий PIN-код SIM-карти"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK-код SIM-карти"</string>
diff --git a/packages/Keyguard/res/values-vi/strings.xml b/packages/Keyguard/res/values-vi/strings.xml
index 00693aa5..19eb4c5 100644
--- a/packages/Keyguard/res/values-vi/strings.xml
+++ b/packages/Keyguard/res/values-vi/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Khóa bàn phím"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Nhập mã PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Nhập mã PIN mới và mã PUK của SIM"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Mã PUK của SIM"</string>
@@ -76,7 +75,7 @@
<string name="keyguard_accessibility_transport_thumbs_down_description" msgid="8101433677192177861">"Bài hát được đánh dấu không thích"</string>
<string name="keyguard_accessibility_transport_heart_description" msgid="2336943232474689887">"Trái tim"</string>
<string name="keyguard_accessibility_show_bouncer" msgid="5425837272418176176">"Mở khóa để tiếp tục"</string>
- <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Quá trình chạy bị hủy"</string>
+ <string name="keyguard_accessibility_hide_bouncer" msgid="7896992171878309358">"Quá trình khởi chạy bị hủy"</string>
<string name="keyguard_accessibility_delete_widget_start" msgid="4096550552634391451">"Thả <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> để xóa."</string>
<string name="keyguard_accessibility_delete_widget_end" msgid="508833506780909393">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> sẽ không bị xóa."</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
diff --git a/packages/Keyguard/res/values-zh-rCN/strings.xml b/packages/Keyguard/res/values-zh-rCN/strings.xml
index 1c014c3..18578e4 100644
--- a/packages/Keyguard/res/values-zh-rCN/strings.xml
+++ b/packages/Keyguard/res/values-zh-rCN/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Keyguard"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"输入 PIN 码"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"请输入 SIM 卡 PUK 码和新的 PIN 码"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM 卡 PUK 码"</string>
diff --git a/packages/Keyguard/res/values-zh-rHK/strings.xml b/packages/Keyguard/res/values-zh-rHK/strings.xml
index 1b621d6..010ad2f 100644
--- a/packages/Keyguard/res/values-zh-rHK/strings.xml
+++ b/packages/Keyguard/res/values-zh-rHK/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"鍵盤鎖"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"輸入 PIN 碼"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"請輸入 SIM PUK 碼和新 PIN 碼"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK 碼"</string>
diff --git a/packages/Keyguard/res/values-zh-rTW/strings.xml b/packages/Keyguard/res/values-zh-rTW/strings.xml
index 6e632ef..d81cc16 100644
--- a/packages/Keyguard/res/values-zh-rTW/strings.xml
+++ b/packages/Keyguard/res/values-zh-rTW/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"鍵盤鎖"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"輸入 PIN 碼"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"輸入 SIM 卡 PUK 碼和新 PIN 碼"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM 卡 PUK 碼"</string>
diff --git a/packages/Keyguard/res/values-zu/strings.xml b/packages/Keyguard/res/values-zu/strings.xml
index 95d3474..b205634 100644
--- a/packages/Keyguard/res/values-zu/strings.xml
+++ b/packages/Keyguard/res/values-zu/strings.xml
@@ -20,7 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="719438068451601849">"Ukhiye wokugada"</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Faka ikhodi ye-PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Thayipha i-PUK ye-SIM nekhodi yephinikhodi entsha"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Ikhodi ye-PUK ye-SIM"</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 4b386b6..2d17b7b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -68,13 +68,6 @@
mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled();
}
- @Override
- public void onWindowFocusChanged(boolean hasWindowFocus) {
- if (hasWindowFocus) {
- reset();
- }
- }
-
public void reset() {
// start fresh
mPasswordEntry.setText("");
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index b4308c6..98122fc 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -231,15 +231,6 @@
mLockPatternView.setOnPatternListener(null);
}
- @Override
- public void onWindowFocusChanged(boolean hasWindowFocus) {
- super.onWindowFocusChanged(hasWindowFocus);
- if (hasWindowFocus) {
- // when timeout dialog closes we want to update our state
- reset();
- }
- }
-
private class UnlockPatternListener implements LockPatternView.OnPatternListener {
public void onPatternStart() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index ba67a82..d6351df 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -99,6 +99,7 @@
private static final int MSG_SCREEN_TURNED_ON = 319;
private static final int MSG_SCREEN_TURNED_OFF = 320;
private static final int MSG_NFC_UNLOCK = 321;
+ private static final int MSG_KEYGUARD_BOUNCER_CHANGED = 322;
private static KeyguardUpdateMonitor sInstance;
@@ -111,6 +112,7 @@
private int mRingMode;
private int mPhoneState;
private boolean mKeyguardIsVisible;
+ private boolean mBouncer;
private boolean mBootCompleted;
// Device provisioning state
@@ -155,7 +157,7 @@
handleRingerModeChange(msg.arg1);
break;
case MSG_PHONE_STATE_CHANGED:
- handlePhoneStateChanged((String)msg.obj);
+ handlePhoneStateChanged((String) msg.obj);
break;
case MSG_CLOCK_VISIBILITY_CHANGED:
handleClockVisibilityChanged();
@@ -167,7 +169,7 @@
handleDevicePolicyManagerStateChanged();
break;
case MSG_USER_SWITCHING:
- handleUserSwitching(msg.arg1, (IRemoteCallback)msg.obj);
+ handleUserSwitching(msg.arg1, (IRemoteCallback) msg.obj);
break;
case MSG_USER_SWITCH_COMPLETE:
handleUserSwitchComplete(msg.arg1);
@@ -178,6 +180,9 @@
case MSG_KEYGUARD_VISIBILITY_CHANGED:
handleKeyguardVisibilityChanged(msg.arg1);
break;
+ case MSG_KEYGUARD_BOUNCER_CHANGED:
+ handleKeyguardBouncerChanged(msg.arg1);
+ break;
case MSG_BOOT_COMPLETED:
handleBootCompleted();
break;
@@ -887,6 +892,22 @@
}
/**
+ * Handle {@link #MSG_KEYGUARD_BOUNCER_CHANGED}
+ * @see #sendKeyguardBouncerChanged(boolean)
+ */
+ private void handleKeyguardBouncerChanged(int bouncer) {
+ if (DEBUG) Log.d(TAG, "handleKeyguardBouncerChanged(" + bouncer + ")");
+ boolean isBouncer = (bouncer == 1);
+ mBouncer = isBouncer;
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onKeyguardBouncerChanged(isBouncer);
+ }
+ }
+ }
+
+ /**
* Handle {@link #MSG_REPORT_EMERGENCY_CALL_ACTION}
*/
private void handleReportEmergencyCallAction() {
@@ -902,6 +923,13 @@
return mKeyguardIsVisible;
}
+ /**
+ * @return if the keyguard is currently in bouncer mode.
+ */
+ public boolean isKeyguardBouncer() {
+ return mBouncer;
+ }
+
public boolean isSwitchingUser() {
return mSwitchingUser;
}
@@ -1021,6 +1049,16 @@
message.sendToTarget();
}
+ /**
+ * @see #handleKeyguardBouncerChanged(int)
+ */
+ public void sendKeyguardBouncerChanged(boolean showingBouncer) {
+ if (DEBUG) Log.d(TAG, "sendKeyguardBouncerChanged(" + showingBouncer + ")");
+ Message message = mHandler.obtainMessage(MSG_KEYGUARD_BOUNCER_CHANGED);
+ message.arg1 = showingBouncer ? 1 : 0;
+ message.sendToTarget();
+ }
+
public void reportClockVisible(boolean visible) {
mClockVisible = visible;
mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget();
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 7be4cec..91a024f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -87,6 +87,12 @@
}
/**
+ * Called when the keyguard enters or leaves bouncer mode.
+ * @param bouncer if true, keyguard is now in bouncer mode.
+ */
+ public void onKeyguardBouncerChanged(boolean bouncer) { }
+
+ /**
* Called when visibility of lockscreen clock changes, such as when
* obscured by a widget.
*/
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
index d8e5b8a..a9206e7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewBase.java
@@ -297,7 +297,7 @@
* @param event The key event
* @return whether the event was consumed as a media key.
*/
- private boolean interceptMediaKey(KeyEvent event) {
+ public boolean interceptMediaKey(KeyEvent event) {
final int keyCode = event.getKeyCode();
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch (keyCode) {
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index d86acb86cb..3b94d6d 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -58,7 +58,7 @@
<item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> የህትመት ስራ"</item>
<item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> የህትመት ስራዎች"</item>
</plurals>
- <string name="cancel" msgid="4373674107267141885">"ይቅር"</string>
+ <string name="cancel" msgid="4373674107267141885">"ሰርዝ"</string>
<string name="restart" msgid="2472034227037808749">"እንደገና ጀምር"</string>
<string name="no_connection_to_printer" msgid="2159246915977282728">"ከአታሚ ጋር ምንም ግንኙነት የለም"</string>
<string name="reason_unknown" msgid="5507940196503246139">"አይታወቅም"</string>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index 1a871f8..74190b4 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -69,8 +69,8 @@
<item msgid="2762241247228983754">"Farve"</item>
</string-array>
<string-array name="orientation_labels">
- <item msgid="4061931020926489228">"Stående"</item>
- <item msgid="3199660090246166812">"Liggende"</item>
+ <item msgid="4061931020926489228">"Portræt"</item>
+ <item msgid="3199660090246166812">"Landskab"</item>
</string-array>
<string-array name="page_options_labels">
<item msgid="7421377442011699994">"Alle"</item>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index 17fabdc..cfb557e 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -33,7 +33,7 @@
<string name="page_count_unknown" msgid="6058852665954511124">"Pages"</string>
<string name="generating_print_job" msgid="3119608742651698916">"Génération tâche impression…"</string>
<string name="save_as_pdf" msgid="5718454119847596853">"Enregistrer au format .PDF"</string>
- <string name="all_printers" msgid="5018829726861876202">"Toutes les imprim."</string>
+ <string name="all_printers" msgid="5018829726861876202">"Toutes les imprimantes…"</string>
<string name="print_dialog" msgid="32628687461331979">"Boîte de dialogue d\'impression"</string>
<string name="search" msgid="5421724265322228497">"Rechercher"</string>
<string name="all_printers_label" msgid="3178848870161526399">"Toutes les imprimantes"</string>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index d3f4f85..f8be5c7 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -23,7 +23,7 @@
<string name="label_destination" msgid="9132510997381599275">"印刷先"</string>
<string name="label_copies" msgid="3634531042822968308">"部数"</string>
<string name="label_paper_size" msgid="8681895607876809323">"用紙サイズ"</string>
- <string name="label_color" msgid="1108690305218188969">"カラー選択"</string>
+ <string name="label_color" msgid="1108690305218188969">"カラー"</string>
<string name="label_orientation" msgid="2853142581990496477">"方向"</string>
<string name="label_pages" msgid="6300874667546617333">"ページ(<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
<string name="pages_range_example" msgid="8558694453556945172">"例: 1-5,8,11-13"</string>
@@ -66,7 +66,7 @@
<string name="print_error_default_message" msgid="8568506918983980567">"印刷ジョブを生成できませんでした"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"モノクロ"</item>
- <item msgid="2762241247228983754">"カラー"</item>
+ <item msgid="2762241247228983754">"色"</item>
</string-array>
<string-array name="orientation_labels">
<item msgid="4061931020926489228">"縦向き"</item>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index c89f9bf..ba3c042 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -60,7 +60,7 @@
</plurals>
<string name="cancel" msgid="4373674107267141885">"បោះបង់"</string>
<string name="restart" msgid="2472034227037808749">"ចាប់ផ្ដើមឡើងវិញ"</string>
- <string name="no_connection_to_printer" msgid="2159246915977282728">"គ្មានការភ្ជាប់ទៅម៉ាស៊ីនបោះពុម្ព"</string>
+ <string name="no_connection_to_printer" msgid="2159246915977282728">"គ្មានការភ្ជាប់ទៅម៉ាស៊ីនបោះពុម្ព"</string>
<string name="reason_unknown" msgid="5507940196503246139">"មិនស្គាល់"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – មិនអាចប្រើបាន"</string>
<string name="print_error_default_message" msgid="8568506918983980567">"មិនអាចបង្កើតការងារបោះពុម្ព"</string>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index e299508..5d4fe94 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -69,7 +69,7 @@
<item msgid="2762241247228983754">"Barvno"</item>
</string-array>
<string-array name="orientation_labels">
- <item msgid="4061931020926489228">"Pokončno"</item>
+ <item msgid="4061931020926489228">"Navpično"</item>
<item msgid="3199660090246166812">"Ležeče"</item>
</string-array>
<string-array name="page_options_labels">
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index a84e9b3..55c8687 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -31,7 +31,7 @@
<string name="install_for_print_preview" msgid="6366303997385509332">"Sakinisha kitazamaji cha PDF kwa onyesho la kuchungulia"</string>
<string name="printing_app_crashed" msgid="854477616686566398">"Programu ya kuchapisha imeacha kufanya kazi"</string>
<string name="page_count_unknown" msgid="6058852665954511124">"Kurasa"</string>
- <string name="generating_print_job" msgid="3119608742651698916">"Inaleta kazi ya kuchapisha"</string>
+ <string name="generating_print_job" msgid="3119608742651698916">"Inazanzisha kazi ya kuchapisha"</string>
<string name="save_as_pdf" msgid="5718454119847596853">"Hifadhi kama PDF"</string>
<string name="all_printers" msgid="5018829726861876202">"Printa zote..."</string>
<string name="print_dialog" msgid="32628687461331979">"Chapisha mazungumzo"</string>
@@ -63,7 +63,7 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Hakuna muunganisho kwa printa"</string>
<string name="reason_unknown" msgid="5507940196503246139">"haijulikani"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - haipatikani"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Haikuweza kuleta kazi ya kuchapisha"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Haikuweza kuunda kazi ya kuchapisha"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Nyeusi na Nyeupe"</item>
<item msgid="2762241247228983754">"Rangi"</item>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 59b486f..bf97fc0 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -189,4 +189,7 @@
<!-- Default for Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, 1==on -->
<integer name="def_heads_up_enabled">1</integer>
+ <!-- Default for Settings.Global.DEVICE_NAME $1=BRAND $2=MODEL-->
+ <string name="def_device_name">%1$s %2$s</string>
+
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 58086c4..909c32e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -31,6 +31,7 @@
import android.media.AudioManager;
import android.media.AudioService;
import android.net.ConnectivityManager;
+import android.os.Build;
import android.os.Environment;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -69,7 +70,7 @@
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 101;
+ private static final int DATABASE_VERSION = 102;
private Context mContext;
private int mUserHandle;
@@ -1614,6 +1615,23 @@
upgradeVersion = 101;
}
+ if (upgradeVersion == 101) {
+ if (mUserHandle == UserHandle.USER_OWNER) {
+ db.beginTransaction();
+ SQLiteStatement stmt = null;
+ try {
+ stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
+ + " VALUES(?,?);");
+ loadSetting(stmt, Settings.Global.DEVICE_NAME, getDefaultDeviceName());
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ if (stmt != null) stmt.close();
+ }
+ }
+ upgradeVersion = 102;
+ }
+
// *** Remember to update DATABASE_VERSION above!
if (upgradeVersion != currentVersion) {
@@ -2342,6 +2360,8 @@
loadIntegerSetting(stmt, Global.HEADS_UP_NOTIFICATIONS_ENABLED,
R.integer.def_heads_up_enabled);
+ loadSetting(stmt, Settings.Global.DEVICE_NAME, getDefaultDeviceName());
+
// --- New global settings start here
} finally {
if (stmt != null) stmt.close();
@@ -2398,4 +2418,9 @@
}
return defaultValue;
}
+
+ private String getDefaultDeviceName() {
+ return mContext.getResources().getString(R.string.def_device_name, Build.BRAND,
+ Build.MODEL);
+ }
}
diff --git a/packages/Shell/res/values-el/strings.xml b/packages/Shell/res/values-el/strings.xml
index 9b1eb7b..3669f78 100644
--- a/packages/Shell/res/values-el/strings.xml
+++ b/packages/Shell/res/values-el/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Κέλυφος"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"Η λήψη της αναφοράς ήταν επιτυχής"</string>
- <string name="bugreport_finished_text" msgid="3559904746859400732">"Αγγίξτε για να μοιραστείτε τη αναφορά σφαλμάτων"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"Αγγίξτε για κοινή χρήση της αναφοράς σας σφαλμάτων"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Οι αναφορές σφαλμάτων περιέχουν δεδομένα από τα διάφορα αρχεία καταγραφής του συστήματος, συμπεριλαμβανομένων προσωπικών και ιδιωτικών πληροφοριών. Να μοιράζεστε αναφορές σφαλμάτων μόνο με εφαρμογές και άτομα που εμπιστεύεστε."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Εμφάνιση αυτού του μηνύματος την επόμενη φορά"</string>
</resources>
diff --git a/packages/Shell/res/values-sk/strings.xml b/packages/Shell/res/values-sk/strings.xml
index 59c3ccf..99f36f9 100644
--- a/packages/Shell/res/values-sk/strings.xml
+++ b/packages/Shell/res/values-sk/strings.xml
@@ -17,8 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"Prostredie"</string>
- <string name="bugreport_finished_title" msgid="2293711546892863898">"Hlásenie o chybách bolo vytvorené"</string>
- <string name="bugreport_finished_text" msgid="3559904746859400732">"Hlásenie o chybách môžete zdielať klepnutím"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"Správa o chybách sa zaznamenala"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"Dotykom môžete zdieľať správu o chybách"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"Správy o chybách obsahujú údaje z rôznych súborov denníkov systému vrátane osobných a súkromných informácií. Zdieľajte ich iba s dôveryhodnými aplikáciami a ľuďmi."</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Zobraziť túto správu nabudúce"</string>
</resources>
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png
deleted file mode 100644
index 54dde82..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png
deleted file mode 100644
index 3c0dc4e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png
deleted file mode 100644
index 3b1944d..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png
deleted file mode 100644
index 693abf5..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_auto_rotate.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_auto_rotate.png
deleted file mode 100644
index 63acea0..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_auto_rotate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_contrast_alpha.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_contrast_alpha.png
deleted file mode 100644
index 0f9dfc7..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_contrast_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_location_off.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_location_off.png
deleted file mode 100644
index 189f27b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_location_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_location_on.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_location_on.png
deleted file mode 100644
index b03d30c..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_location_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_rotation_locked.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_rotation_locked.png
deleted file mode 100644
index f3dc08f..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_rotation_locked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_normal.png
deleted file mode 100644
index c526433..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_normal.png
deleted file mode 100644
index d13bc69..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_normal.png
deleted file mode 100644
index a137a80..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_clear_normal.png
deleted file mode 100644
index 8da7945..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png
deleted file mode 100644
index 7cb52e3..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png
deleted file mode 100644
index 8010ce7..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png
deleted file mode 100644
index 807f607..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png
deleted file mode 100644
index 15340d3..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_auto_rotate.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_auto_rotate.png
deleted file mode 100644
index ac6c1cf0..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_auto_rotate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_contrast_alpha.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_contrast_alpha.png
deleted file mode 100644
index a4dd087..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_contrast_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_location_off.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_location_off.png
deleted file mode 100644
index b692107..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_location_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_location_on.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_location_on.png
deleted file mode 100644
index 867c57d..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_location_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_rotation_locked.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_rotation_locked.png
deleted file mode 100644
index 3b7a284..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_rotation_locked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png
deleted file mode 100644
index b9afa44..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png
deleted file mode 100644
index 6d46fdd..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png
deleted file mode 100644
index e562bc2..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png
deleted file mode 100644
index e3cc9b0..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_auto_rotate.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_auto_rotate.png
deleted file mode 100644
index c553bc2..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_auto_rotate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_contrast_alpha.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_contrast_alpha.png
deleted file mode 100644
index 9331e52..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_contrast_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_off.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_off.png
deleted file mode 100644
index 7ce8f83..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_on.png
deleted file mode 100644
index 6300bdc..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_rotation_locked.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_rotation_locked.png
deleted file mode 100644
index b6daaf3..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_rotation_locked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_clear_normal.png
deleted file mode 100644
index afdee8f..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png
deleted file mode 100644
index 7742207..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png
deleted file mode 100644
index a2e8fe1..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_quicksettings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png
deleted file mode 100644
index e15981a..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_auto_rotate.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_auto_rotate.png
deleted file mode 100644
index b6cfaec..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_auto_rotate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_contrast_alpha.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_contrast_alpha.png
deleted file mode 100644
index 82c3842..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_contrast_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_off.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_off.png
deleted file mode 100644
index c14c1bb..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_on.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_on.png
deleted file mode 100644
index d6d4c70..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_rotation_locked.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_rotation_locked.png
deleted file mode 100644
index 8e37884..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_rotation_locked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_location_24_01.xml b/packages/SystemUI/res/drawable/ic_location_24_01.xml
new file mode 100644
index 0000000..ff37d9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_01.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.0,2.0C8.13,2.0 5.0,5.13 5.0,9.0c0.0,5.25 7.0,13.0 7.0,13.0s7.0,-7.75 7.0,-13.0C19.0,5.13 15.87,2.0 12.0,2.0zM12.0,11.5c-1.38,0.0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5c1.38,0.0 2.5,1.12 2.5,2.5S13.38,11.5 12.0,11.5z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_02.xml b/packages/SystemUI/res/drawable/ic_location_24_02.xml
new file mode 100644
index 0000000..bb4465f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_02.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.0,4.0c-3.48,0.0 -6.3,2.82 -6.3,6.3C5.7,15.02 12.0,22.0 12.0,22.0s6.3,-6.98 6.3,-11.7C18.3,6.82 15.48,4.0 12.0,4.0zM12.0,12.55c-1.24,0.0 -2.25,-1.01 -2.25,-2.25S10.76,8.05 12.0,8.05c1.24,0.0 2.25,1.01 2.25,2.25S13.24,12.55 12.0,12.55z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_03.xml b/packages/SystemUI/res/drawable/ic_location_24_03.xml
new file mode 100644
index 0000000..956a8c3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_03.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.0,7.0c-2.9,0.0 -5.25,2.35 -5.25,5.25C6.75,16.19 12.0,22.0 12.0,22.0s5.25,-5.81 5.25,-9.75C17.25,9.35 14.9,7.0 12.0,7.0zM12.0,14.12c-1.04,0.0 -1.88,-0.84 -1.88,-1.88s0.84,-1.88 1.88,-1.88c1.04,0.0 1.87,0.84 1.87,1.88S13.04,14.12 12.0,14.12z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_04.xml b/packages/SystemUI/res/drawable/ic_location_24_04.xml
new file mode 100644
index 0000000..0c0fb3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_04.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.0,10.0c-2.32,0.0 -4.2,1.88 -4.2,4.2C7.8,17.35 12.0,22.0 12.0,22.0s4.2,-4.65 4.2,-7.8C16.2,11.88 14.32,10.0 12.0,10.0zM12.0,15.7c-0.83,0.0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5c0.83,0.0 1.5,0.67 1.5,1.5S12.83,15.7 12.0,15.7z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_05.xml b/packages/SystemUI/res/drawable/ic_location_24_05.xml
new file mode 100644
index 0000000..1a21e2f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_05.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.0,13.0c-1.74,0.0 -3.15,1.41 -3.15,3.15C8.85,18.51 12.0,22.0 12.0,22.0s3.15,-3.49 3.15,-5.85C15.15,14.41 13.74,13.0 12.0,13.0zM12.0,17.27c-0.62,0.0 -1.13,-0.5 -1.13,-1.12c0.0,-0.62 0.5,-1.12 1.13,-1.12c0.62,0.0 1.12,0.5 1.12,1.12C13.12,16.77 12.62,17.27 12.0,17.27z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_06.xml b/packages/SystemUI/res/drawable/ic_location_24_06.xml
new file mode 100644
index 0000000..25c9ae5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_06.xml
@@ -0,0 +1,33 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.0,16.0c-1.16,0.0 -2.1,0.94 -2.1,2.1C9.9,19.67 12.0,22.0 12.0,22.0s2.1,-2.33 2.1,-3.9C14.1,16.94 13.16,16.0 12.0,16.0zM12.0,18.85c-0.41,0.0 -0.75,-0.34 -0.75,-0.75s0.34,-0.75 0.75,-0.75c0.41,0.0 0.75,0.34 0.75,0.75S12.41,18.85 12.0,18.85z"/>
+ <path
+ android:pathData="M11.99,15c-1.35,0,-2.45,1.1,-2.45,2.45 c0,1.84,2.45,4.55,2.45,4.55s2.45,-2.71,2.45,-4.55C14.44,16.1,13.34,15,11.99,15z M11.99,18.33c-0.48,0,-0.88,-0.39,-0.88,-0.88 s0.39,-0.88,0.88,-0.88c0.48,0,0.87,0.39,0.87,0.88S12.47,18.33,11.99,18.33z"
+ android:strokeWidth=".35"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_07.xml b/packages/SystemUI/res/drawable/ic_location_24_07.xml
new file mode 100644
index 0000000..a69c3a2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_07.xml
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M12,9c-2.51,0,-4.55,2.04,-4.55,4.55 C7.45,16.96,12,22,12,22s4.55,-5.04,4.55,-8.45C16.55,11.04,14.51,9,12,9z M12,15.18c-0.9,0,-1.63,-0.73,-1.63,-1.62 s0.73,-1.62,1.63,-1.62c0.9,0,1.62,0.73,1.62,1.62S12.9,15.18,12,15.18z"
+ android:strokeWidth="0.65"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_08.xml b/packages/SystemUI/res/drawable/ic_location_24_08.xml
new file mode 100644
index 0000000..c89c047
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_08.xml
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M12,6c-3.09,0,-5.6,2.51,-5.6,5.6 C6.4,15.8,12,22,12,22s5.6,-6.2,5.6,-10.4C17.6,8.51,15.09,6,12,6z M12,13.6c-1.1,0,-2,-0.9,-2,-2s0.9,-2,2,-2c1.1,0,2,0.9,2,2 S13.1,13.6,12,13.6z"
+ android:strokeWidth="0.8"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_09.xml b/packages/SystemUI/res/drawable/ic_location_24_09.xml
new file mode 100644
index 0000000..96bb6ce
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_09.xml
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M12,4c-3.48,0,-6.3,2.82,-6.3,6.3 C5.7,15.02,12,22,12,22s6.3,-6.98,6.3,-11.7C18.3,6.82,15.48,4,12,4z M12,12.55c-1.24,0,-2.25,-1.01,-2.25,-2.25S10.76,8.05,12,8.05 c1.24,0,2.25,1.01,2.25,2.25S13.24,12.55,12,12.55z"
+ android:strokeWidth="0.9"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_10.xml b/packages/SystemUI/res/drawable/ic_location_24_10.xml
new file mode 100644
index 0000000..aced4bd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_10.xml
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M12,3C8.33,3,5.35,5.98,5.35,9.65 C5.35,14.64,12,22,12,22s6.65,-7.36,6.65,-12.35C18.65,5.98,15.67,3,12,3z M12,12.02c-1.31,0,-2.38,-1.06,-2.38,-2.38 S10.69,7.28,12,7.28c1.31,0,2.37,1.06,2.37,2.37S13.31,12.02,12,12.02z"
+ android:strokeWidth="0.95"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_11.xml b/packages/SystemUI/res/drawable/ic_location_24_11.xml
new file mode 100644
index 0000000..578308e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_11.xml
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M12,2C8.13,2,5,5.13,5,9c0,5.25,7,13,7,13s7,-7.75,7,-13 C19,5.13,15.87,2,12,2z M12,11.5c-1.38,0,-2.5,-1.12,-2.5,-2.5s1.12,-2.5,2.5,-2.5c1.38,0,2.5,1.12,2.5,2.5S13.38,11.5,12,11.5z"
+ android:fill="#00000000"
+ android:stroke="#CCCCCC"
+ android:strokeWidth="1.0"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_off_anim.xml b/packages/SystemUI/res/drawable/ic_location_off_anim.xml
new file mode 100644
index 0000000..864eda1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_off_anim.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<animation-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:oneshot="true">
+ <item android:drawable="@drawable/ic_location_24_01" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_02" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_03" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_04" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_05" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_06" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_07" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_08" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_09" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_10" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_11" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_location_on_anim.xml b/packages/SystemUI/res/drawable/ic_location_on_anim.xml
new file mode 100644
index 0000000..65a8afe
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_on_anim.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<animation-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:oneshot="true">
+ <item android:drawable="@drawable/ic_location_24_11" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_10" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_09" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_08" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_07" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_06" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_05" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_04" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_03" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_02" android:duration="16" />
+ <item android:drawable="@drawable/ic_location_24_01" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_notifications.xml b/packages/SystemUI/res/drawable/ic_notifications.xml
deleted file mode 100644
index 97a7623..0000000
--- a/packages/SystemUI/res/drawable/ic_notifications.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/ic_notify_open_normal" />
- <item
- android:drawable="@drawable/ic_notify_open_normal" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/ic_notify_clear.xml b/packages/SystemUI/res/drawable/ic_notify_clear.xml
deleted file mode 100644
index 2163198..0000000
--- a/packages/SystemUI/res/drawable/ic_notify_clear.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/ic_notify_clear_normal" />
- <item android:drawable="@drawable/ic_notify_clear_normal" />
-</selector>
diff --git a/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml b/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml
deleted file mode 100644
index 7cf3175..0000000
--- a/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/ic_notify_quicksettings_normal" />
- <item
- android:drawable="@drawable/ic_notify_quicksettings_normal" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/ic_notify_settings.xml b/packages/SystemUI/res/drawable/ic_notify_settings.xml
deleted file mode 100644
index 9303ca4..0000000
--- a/packages/SystemUI/res/drawable/ic_notify_settings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/ic_notify_settings_normal" />
- <item
- android:drawable="@drawable/ic_notify_settings_normal" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane.xml b/packages/SystemUI/res/drawable/ic_qs_airplane.xml
new file mode 100644
index 0000000..ffe571f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_airplane.xml
@@ -0,0 +1,31 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FF000000"
+ android:pathData="M10.2,9.0"/>
+ <path
+ android:fill="#FF000000"
+ android:pathData="M21.0,16.0l0.0,-2.0l-8.0,-5.0L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5L10.0,9.0l-8.0,5.0l0.0,2.0l8.0,-2.5L10.0,19.0l-2.0,1.5L8.0,22.0l3.5,-1.0l3.5,1.0l0.0,-1.5L13.0,19.0l0.0,-5.5L21.0,16.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
new file mode 100644
index 0000000..22d0dcf
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FF000000"
+ android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bugreport.xml b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
new file mode 100644
index 0000000..2dfe183
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FF000000"
+ android:pathData="M20.0,8.0l-2.8,0.0c-0.5,-0.8 -1.1,-1.5 -1.8,-2.0L17.0,4.4L15.6,3.0l-2.2,2.2C13.0,5.1 12.5,5.0 12.0,5.0s-1.0,0.1 -1.4,0.2L8.4,3.0L7.0,4.4L8.6,6.0C7.9,6.5 7.3,7.2 6.8,8.0L4.0,8.0l0.0,2.0l2.1,0.0C6.0,10.3 6.0,10.7 6.0,11.0l0.0,1.0L4.0,12.0l0.0,2.0l2.0,0.0l0.0,1.0c0.0,0.3 0.0,0.7 0.1,1.0L4.0,16.0l0.0,2.0l2.8,0.0c1.0,1.8 3.0,3.0 5.2,3.0s4.2,-1.2 5.2,-3.0L20.0,18.0l0.0,-2.0l-2.1,0.0c0.1,-0.3 0.1,-0.7 0.1,-1.0l0.0,-1.0l2.0,0.0l0.0,-2.0l-2.0,0.0l0.0,-1.0c0.0,-0.3 0.0,-0.7 -0.1,-1.0L20.0,10.0L20.0,8.0zM14.0,16.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,16.0zM14.0,12.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,12.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast.xml b/packages/SystemUI/res/drawable/ic_qs_cast.xml
new file mode 100644
index 0000000..6f2840b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_cast.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FF000000"
+ android:pathData="M21.0,3.0L3.0,3.0C1.9,3.0 1.0,3.9 1.0,5.0l0.0,3.0l2.0,0.0L3.0,5.0l18.0,0.0l0.0,14.0l-7.0,0.0l0.0,2.0l7.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L23.0,5.0C23.0,3.9 22.1,3.0 21.0,3.0zM1.0,18.0l0.0,3.0l3.0,0.0C4.0,19.3 2.7,18.0 1.0,18.0zM1.0,14.0l0.0,2.0c2.8,0.0 5.0,2.2 5.0,5.0l2.0,0.0C8.0,17.1 4.9,14.0 1.0,14.0zM1.0,10.0l0.0,2.0c5.0,0.0 9.0,4.0 9.0,9.0l2.0,0.0C12.0,14.9 7.1,10.0 1.0,10.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_close.xml b/packages/SystemUI/res/drawable/ic_qs_close.xml
new file mode 100644
index 0000000..c2c72c8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_close.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FF000000"
+ android:pathData="M19.0,6.4l-1.3999996,-1.4000001 -5.6000004,5.6000004 -5.6,-5.6000004 -1.4000001,1.4000001 5.6000004,5.6 -5.6000004,5.6000004 1.4000001,1.3999996 5.6,-5.6000004 5.6000004,5.6000004 1.3999996,-1.3999996 -5.6000004,-5.6000004z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_contrast_off.xml b/packages/SystemUI/res/drawable/ic_qs_contrast_off.xml
deleted file mode 100644
index 5f65d8a..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_contrast_off.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_qs_contrast_alpha"
- android:tint="@color/ic_qs_off" />
diff --git a/packages/SystemUI/res/drawable/ic_qs_contrast_on.xml b/packages/SystemUI/res/drawable/ic_qs_contrast_on.xml
deleted file mode 100644
index a018929..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_contrast_on.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_qs_contrast_alpha"
- android:tint="@color/ic_qs_on" />
diff --git a/packages/SystemUI/res/drawable/ic_qs_hotspot.xml b/packages/SystemUI/res/drawable/ic_qs_hotspot.xml
new file mode 100644
index 0000000..965e3c1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_hotspot.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FF000000"
+ android:pathData="M12.0,11.0c-1.1,0.0 -2.0,0.9 -2.0,2.0c0.0,1.1 0.9,2.0 2.0,2.0c1.1,0.0 2.0,-0.9 2.0,-2.0C14.0,11.9 13.1,11.0 12.0,11.0zM18.0,13.0c0.0,-3.3 -2.7,-6.0 -6.0,-6.0c-3.3,0.0 -6.0,2.7 -6.0,6.0c0.0,2.2 1.2,4.1 3.0,5.2l1.0,-1.7c-1.2,-0.7 -2.0,-2.0 -2.0,-3.4c0.0,-2.2 1.8,-4.0 4.0,-4.0s4.0,1.8 4.0,4.0c0.0,1.5 -0.8,2.8 -2.0,3.4l1.0,1.7C16.8,17.1 18.0,15.2 18.0,13.0zM12.0,3.0C6.5,3.0 2.0,7.5 2.0,13.0c0.0,3.7 2.0,6.9 5.0,8.6l1.0,-1.7c-2.4,-1.4 -4.0,-4.0 -4.0,-6.9c0.0,-4.4 3.6,-8.0 8.0,-8.0s8.0,3.6 8.0,8.0c0.0,3.0 -1.6,5.5 -4.0,6.9l1.0,1.7c3.0,-1.7 5.0,-5.0 5.0,-8.6C22.0,7.5 17.5,3.0 12.0,3.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_invert_colors.xml b/packages/SystemUI/res/drawable/ic_qs_invert_colors.xml
new file mode 100644
index 0000000..7c92052
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_invert_colors.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FF000000"
+ android:pathData="M18.939,7.244c-5.887,-5.885 -6.214,-6.214 -6.222,-6.222l-0.707,-0.737L5.088,7.207c-2.914,2.915 -3.74,6.629 -2.266,10.19c1.541,3.719 5.312,6.316 9.174,6.317l0.0,0.0c3.861,-0.001 7.636,-2.603 9.179,-6.328C22.646,13.834 21.832,10.138 18.939,7.244zM4.67,16.632c-1.149,-2.776 -0.481,-5.696 1.832,-8.011l5.494,-5.492c0.0,0.002 0.002,0.003 0.003,0.004l0.0,18.582c-0.001,0.0 -0.002,0.0 -0.003,0.0C8.922,21.714 5.91,19.624 4.67,16.632z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location.xml b/packages/SystemUI/res/drawable/ic_qs_location.xml
new file mode 100644
index 0000000..e6e98a0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_location.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FF000000"
+ android:pathData="M12.0,2.0C8.1,2.0 5.0,5.1 5.0,9.0c0.0,5.2 7.0,13.0 7.0,13.0s7.0,-7.8 7.0,-13.0C19.0,5.1 15.9,2.0 12.0,2.0zM12.0,11.5c-1.4,0.0 -2.5,-1.1 -2.5,-2.5s1.1,-2.5 2.5,-2.5c1.4,0.0 2.5,1.1 2.5,2.5S13.4,11.5 12.0,11.5z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_minus.xml b/packages/SystemUI/res/drawable/ic_qs_minus.xml
new file mode 100644
index 0000000..8323e89
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_minus.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FF000000"
+ android:pathData="M7.0,11.0l0.0,2.0l10.0,0.0l0.0,-2.0L7.0,11.0zM12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,20.0c-4.4,0.0 -8.0,-3.6 -8.0,-8.0s3.6,-8.0 8.0,-8.0c4.4,0.0 8.0,3.6 8.0,8.0S16.4,20.0 12.0,20.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_plus.xml b/packages/SystemUI/res/drawable/ic_qs_plus.xml
new file mode 100644
index 0000000..84cd72a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_plus.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FF000000"
+ android:pathData="M13.0,7.0l-2.0,0.0l0.0,4.0L7.0,11.0l0.0,2.0l4.0,0.0l0.0,4.0l2.0,0.0l0.0,-4.0l4.0,0.0l0.0,-2.0l-4.0,0.0L13.0,7.0zM12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,20.0c-4.4,0.0 -8.0,-3.6 -8.0,-8.0s3.6,-8.0 8.0,-8.0c4.4,0.0 8.0,3.6 8.0,8.0S16.4,20.0 12.0,20.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
new file mode 100644
index 0000000..fa6f20c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FF000000"
+ android:pathData="M3.0,9.0c0.0,0.0 0.0,6.0 0.0,6.0l4.0,0.0l5.0,5.0L12.0,4.0L7.0,9.0L3.0,9.0zM16.5,12.0c0.0,-1.8 -1.0,-3.3 -2.5,-4.0L14.0,16.0C15.5,15.3 16.5,13.8 16.5,12.0zM14.0,3.2l0.0,2.1c2.9,0.9 5.0,3.5 5.0,6.7s-2.1,5.8 -5.0,6.7l0.0,2.1c4.0,-0.9 7.0,-4.5 7.0,-8.8S18.0,4.1 14.0,3.2z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
new file mode 100644
index 0000000..0665196
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FF000000"
+ android:pathData="M16.5,12.0c0.0,-1.8 -1.0,-3.3 -2.5,-4.0l0.0,2.2l2.5,2.5C16.5,12.4 16.5,12.2 16.5,12.0zM19.0,12.0c0.0,0.9 -0.2,1.8 -0.5,2.6l1.5,1.5c0.7,-1.2 1.0,-2.7 1.0,-4.2c0.0,-4.3 -3.0,-7.9 -7.0,-8.8l0.0,2.1C16.9,6.2 19.0,8.8 19.0,12.0zM4.3,3.0L3.0,4.3L7.7,9.0L3.0,9.0c0.0,0.0 0.0,6.0 0.0,6.0l4.0,0.0l5.0,5.0l0.0,-6.7l4.3,4.3c-0.7,0.5 -1.4,0.9 -2.3,1.2l0.0,2.1c1.4,-0.3 2.6,-0.9 3.7,-1.8l2.0,2.0l1.3,-1.3l-9.0,-9.0L4.3,3.0zM12.0,4.0L9.9,6.1L12.0,8.2L12.0,4.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
new file mode 100644
index 0000000..299a2ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FF000000"
+ android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_zen.xml b/packages/SystemUI/res/drawable/ic_qs_zen.xml
new file mode 100644
index 0000000..059c068
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_zen.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FF000000"
+ android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0zM14.0,9.8l-2.8,3.4L14.0,13.200001L14.0,15.0L9.0,15.0l0.0,-1.8l2.8,-3.4L9.0,9.799999L9.0,8.0l5.0,0.0L14.0,9.8z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_01.xml b/packages/SystemUI/res/drawable/ic_rotate_24_01.xml
new file mode 100644
index 0000000..a6c2cf8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_01.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M10.25,1.75c-0.6,-0.6 -1.5,-0.6 -2.1,0.0l-6.4,6.4c-0.6,0.6 -0.6,1.5 0.0,2.1l12.0,12.0c0.6,0.6 1.5,0.6 2.1,0.0l6.4,-6.4c0.6,-0.6 0.6,-1.5 0.0,-2.1L10.25,1.75zM14.85,21.25l-12.0,-12.0l6.4,-6.4l12.0,12.0L14.85,21.25z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M16.55,2.5c3.3,1.5 5.6,4.7 6.0,8.5l1.5,0.0c-0.6,-6.2 -5.7,-11.0 -12.0,-11.0c-0.2,0.0 -0.4,0.0 -0.7,0.0l3.8,3.8L16.55,2.5z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M7.55,21.5c-3.3,-1.5 -5.6,-4.7 -6.0,-8.5l-1.4,0.0c0.5,6.2 5.6,11.0 11.9,11.0c0.2,0.0 0.4,0.0 0.7,0.0l-3.8,-3.8L7.55,21.5z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_02.xml b/packages/SystemUI/res/drawable/ic_rotate_24_02.xml
new file mode 100644
index 0000000..4107c46
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_02.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M10.24,2.43C9.67,1.88 8.83,1.88 8.28,2.45L2.34,8.48c-0.56,0.57 -0.55,1.41 0.02,1.96l11.3,11.13c0.57,0.56 1.41,0.55 1.96,-0.02l5.93,-6.03c0.56,-0.57 0.55,-1.41 -0.02,-1.96L10.24,2.43zM14.68,20.62L3.38,9.5l5.93,-6.03l11.3,11.13L14.68,20.62z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M16.91,2.71c3.23,1.64 5.39,4.94 5.62,8.76l1.5,0.07c-0.33,-6.22 -5.21,-11.24 -11.5,-11.52c-0.2,-0.01 -0.4,-0.02 -0.7,-0.03l3.63,3.96L16.91,2.71z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M7.09,21.29c-3.23,-1.64 -5.39,-4.94 -5.62,-8.76l-1.4,-0.06c0.23,6.22 5.11,11.24 11.4,11.51c0.2,0.01 0.4,0.02 0.7,0.03l-3.63,-3.96L7.09,21.29z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_03.xml b/packages/SystemUI/res/drawable/ic_rotate_24_03.xml
new file mode 100644
index 0000000..127296c4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_03.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M11.07,4.12c-0.43,-0.49 -1.11,-0.53 -1.6,-0.1L4.3,8.57C3.81,9.0 3.77,9.68 4.19,10.17l8.54,9.71c0.43,0.49 1.11,0.53 1.6,0.1l5.18,-4.55c0.49,-0.43 0.53,-1.11 0.1,-1.6L11.07,4.12zM13.61,19.17L5.08,9.46l5.18,-4.55l8.54,9.71L13.61,19.17z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M17.72,3.2c3.06,1.94 4.9,5.43 4.77,9.25l1.49,0.21C24.23,6.43 19.84,0.97 13.6,0.11c-0.2,-0.03 -0.4,-0.06 -0.69,-0.1l3.24,4.29L17.72,3.2z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M6.19,20.78c-3.06,-1.94 -4.9,-5.43 -4.77,-9.25l-1.39,-0.19c-0.36,6.21 4.03,11.67 10.27,12.53c0.2,0.03 0.4,0.06 0.69,0.1l-3.24,-4.29L6.19,20.78z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_04.xml b/packages/SystemUI/res/drawable/ic_rotate_24_04.xml
new file mode 100644
index 0000000..d00262a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_04.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M11.88,5.72c-0.3,-0.42 -0.83,-0.51 -1.25,-0.21L6.19,8.69c-0.42,0.3 -0.51,0.83 -0.21,1.25l5.95,8.34c0.3,0.42 0.83,0.51 1.25,0.21l4.45,-3.17c0.42,-0.3 0.51,-0.83 0.21,-1.25L11.88,5.72zM12.68,17.79L6.73,9.45l4.45,-3.17l5.95,8.34L12.68,17.79z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M18.8,4.01c2.79,2.32 4.16,6.01 3.54,9.78l1.45,0.4c1.06,-6.14 -2.59,-12.11 -8.67,-13.78c-0.19,-0.05 -0.39,-0.11 -0.68,-0.18l2.66,4.67L18.8,4.01z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M5.11,19.96c-2.79,-2.32 -4.16,-6.01 -3.54,-9.78L0.21,9.81c-1.15,6.11 2.5,12.09 8.57,13.75c0.19,0.05 0.39,0.11 0.68,0.18L6.8,19.08L5.11,19.96z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_05.xml b/packages/SystemUI/res/drawable/ic_rotate_24_05.xml
new file mode 100644
index 0000000..570f51f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_05.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M15.41,8.14c0.05,-0.42 -0.23,-0.78 -0.65,-0.83l-4.5,-0.54C9.84,6.72 9.48,7.0 9.43,7.42l-1.01,8.44c-0.05,0.42 0.23,0.78 0.65,0.83l4.5,0.54C14.0,17.28 14.35,17.0 14.4,16.58L15.41,8.14zM9.16,15.99l1.01,-8.44l4.5,0.54l-1.01,8.44L9.16,15.99z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M22.35,10.28c0.64,3.57 -0.69,7.28 -3.59,9.77l0.85,1.23c4.76,-4.01 5.82,-10.94 2.24,-16.12c-0.11,-0.16 -0.23,-0.33 -0.4,-0.58l-0.97,5.29L22.35,10.28z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M1.6,13.66c-0.64,-3.57 0.69,-7.28 3.59,-9.77L4.4,2.74c-4.82,3.93 -5.88,10.86 -2.3,16.04c0.11,0.16 0.23,0.33 0.4,0.58l0.97,-5.29L1.6,13.66z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_06.xml b/packages/SystemUI/res/drawable/ic_rotate_24_06.xml
new file mode 100644
index 0000000..aaf9356
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_06.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M15.62,13.08c0.29,-0.1 0.44,-0.39 0.34,-0.69L14.9,9.27c-0.1,-0.29 -0.39,-0.44 -0.69,-0.34l-5.86,1.98c-0.29,0.1 -0.44,0.39 -0.34,0.69l1.06,3.12c0.1,0.29 0.39,0.44 0.69,0.34L15.62,13.08zM8.51,11.44l5.86,-1.98l1.06,3.12l-5.86,1.98L8.51,11.44z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M18.53,20.21c-2.8,2.3 -6.69,2.95 -10.27,1.64L7.6,23.2c5.83,2.2 12.39,-0.26 15.16,-5.92c0.09,-0.18 0.18,-0.36 0.31,-0.63l-5.09,1.73L18.53,20.21z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M5.45,3.76c2.8,-2.3 6.69,-2.95 10.27,-1.64l0.62,-1.26C10.56,-1.42 4.0,1.04 1.22,6.69C1.13,6.87 1.05,7.05 0.91,7.32L6.0,5.59L5.45,3.76z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_07.xml b/packages/SystemUI/res/drawable/ic_rotate_24_07.xml
new file mode 100644
index 0000000..330ce6a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_07.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.23,14.48c0.13,0.16 0.35,0.17 0.5,0.04l1.66,-1.4c0.16,-0.13 0.17,-0.35 0.04,-0.5l-2.62,-3.11c-0.13,-0.16 -0.35,-0.17 -0.5,-0.04l-1.66,1.4c-0.16,0.13 -0.17,0.35 -0.04,0.5L12.23,14.48zM11.53,9.73l2.62,3.11l-1.66,1.4l-2.62,-3.11L11.53,9.73z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M6.04,20.63c-3.01,-2.02 -4.75,-5.56 -4.52,-9.37l-1.48,-0.25c-0.43,6.21 3.81,11.79 10.02,12.83c0.2,0.03 0.39,0.07 0.69,0.12l-3.12,-4.37L6.04,20.63z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M18.04,3.37c3.01,2.02 4.75,5.56 4.52,9.37l1.38,0.23c0.53,-6.2 -3.71,-11.77 -9.93,-12.81c-0.2,-0.03 -0.39,-0.07 -0.69,-0.12l3.12,4.37L18.04,3.37z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_08.xml b/packages/SystemUI/res/drawable/ic_rotate_24_08.xml
new file mode 100644
index 0000000..1c7f1a1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_08.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M10.55,12.73c-0.06,0.12 -0.02,0.25 0.1,0.32l1.26,0.68c0.12,0.06 0.25,0.02 0.32,-0.1l1.27,-2.36c0.06,-0.12 0.02,-0.25 -0.1,-0.32l-1.26,-0.68c-0.12,-0.06 -0.25,-0.02 -0.32,0.1L10.55,12.73zM13.29,11.15l-1.27,2.36l-1.26,-0.68l1.27,-2.36L13.29,11.15z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M1.55,12.95C1.18,9.34 2.78,5.74 5.86,3.47L5.1,2.18C0.05,5.83 -1.51,12.66 1.67,18.09c0.1,0.17 0.2,0.35 0.35,0.6l1.36,-5.2L1.55,12.95z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M22.5,11.12c0.37,3.61 -1.23,7.21 -4.31,9.47l0.71,1.21c5.1,-3.56 6.67,-10.39 3.48,-15.83c-0.1,-0.17 -0.2,-0.35 -0.35,-0.6l-1.36,5.2L22.5,11.12z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_09.xml b/packages/SystemUI/res/drawable/ic_rotate_24_09.xml
new file mode 100644
index 0000000..ebfbad6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_09.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M11.45,12c0,0.14,0.12,0.25,0.25,0.25l0.06,0l0,-0.5l-0.06,0C11.57,11.75,11.45,11.86,11.45,12z"
+ android:fill="#00000000"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M11.77,11.62l-0.06,0.0c-0.21,0.0 -0.37,0.17 -0.38,0.37c0.0,0.21 0.17,0.37 0.37,0.37l0.06,0.0c0.0,0.07 0.06,0.12 0.12,0.13l0.62,0.0c0.07,0.0 0.12,-0.06 0.13,-0.12l0.0,-0.75c0.0,-0.07 -0.06,-0.12 -0.12,-0.13l-0.62,0.0C11.83,11.5 11.77,11.56 11.77,11.62zM12.33,12.0c0.0,0.07 -0.06,0.12 -0.13,0.12c-0.07,0.0 -0.12,-0.06 -0.12,-0.13c0.0,-0.07 0.06,-0.12 0.13,-0.12C12.28,11.88 12.33,11.93 12.33,12.0zM11.77,11.75l0.0,0.5l-0.06,0.0c-0.14,0.0 -0.26,-0.11 -0.25,-0.25c0.0,-0.14 0.12,-0.25 0.26,-0.25L11.77,11.75z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M3.83,5.44c2.21,-2.87 5.85,-4.38 9.64,-3.9l0.34,-1.46C7.64,-0.75 1.81,3.12 0.37,9.25C0.32,9.45 0.28,9.64 0.21,9.93L4.78,7.1L3.83,5.44zM20.28,18.53c-2.21,2.87 -5.85,4.38 -9.64,3.9l-0.32,1.36c6.15,0.93 11.99,-2.95 13.42,-9.08c0.05,-0.19 0.09,-0.39 0.16,-0.68l-4.57,2.83L20.28,18.53z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_10.xml b/packages/SystemUI/res/drawable/ic_rotate_24_10.xml
new file mode 100644
index 0000000..21dda8c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_10.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M10.42,9.96c-0.42,0.42,-0.39,1.12,0.03,1.54l0.19,0.19l1.51,-1.53l-0.19,-0.19 C11.54,9.55,10.84,9.54,10.42,9.96z"
+ android:fill="#00000000"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M12.53,9.78l-0.19,-0.19c-0.63,-0.63 -1.66,-0.62 -2.28,0.02c-0.63,0.63 -0.62,1.66 0.02,2.28l0.19,0.19c-0.21,0.21 -0.21,0.55 0.01,0.76l1.92,1.89c0.21,0.21 0.55,0.21 0.76,-0.01l2.27,-2.3c0.21,-0.21 0.21,-0.55 -0.01,-0.76l-1.92,-1.89C13.08,9.56 12.74,9.56 12.53,9.78zM13.12,12.62c-0.21,0.21 -0.55,0.21 -0.76,0.01c-0.21,-0.21 -0.21,-0.55 -0.01,-0.76c0.21,-0.21 0.55,-0.21 0.76,-0.01C13.33,12.07 13.33,12.41 13.12,12.62zM12.15,10.16l-1.51,1.53l-0.19,-0.19c-0.42,-0.42 -0.45,-1.12 -0.03,-1.54c0.42,-0.42 1.12,-0.41 1.54,0.01L12.15,10.16z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M7.82,2.36c3.3,-1.49 7.23,-1.12 10.35,1.09l0.99,-1.13C14.09,-1.32 7.12,-0.64 2.97,4.1C2.84,4.25 2.71,4.4 2.51,4.62l5.36,-0.36L7.82,2.36zM16.18,21.64c-3.3,1.49 -7.23,1.12 -10.35,-1.09l-0.92,1.05c4.99,3.71 11.97,3.03 16.12,-1.71c0.13,-0.15 0.26,-0.3 0.46,-0.53l-5.36,0.36L16.18,21.64z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_11.xml b/packages/SystemUI/res/drawable/ic_rotate_24_11.xml
new file mode 100644
index 0000000..f4186fe
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_11.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M10.53,8.85c-0.7,0.37,-0.95,1.28,-0.58,1.98l0.17,0.32l2.55,-1.36L12.5,9.48 C12.12,8.78,11.23,8.48,10.53,8.85z"
+ android:fill="#00000000"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M13.3,9.46l-0.17,-0.32c-0.56,-1.05 -1.87,-1.45 -2.93,-0.89s-1.45,1.87 -0.89,2.93l0.17,0.32c-0.35,0.19 -0.48,0.62 -0.3,0.98l1.7,3.18c0.19,0.35 0.62,0.48 0.98,0.3l3.82,-2.04c0.35,-0.19 0.48,-0.62 0.3,-0.98l-1.7,-3.18C14.09,9.4 13.65,9.27 13.3,9.46zM12.92,13.34c-0.35,0.19 -0.79,0.06 -0.98,-0.3c-0.19,-0.35 -0.05,-0.79 0.3,-0.98c0.35,-0.19 0.79,-0.05 0.98,0.3C13.41,12.72 13.27,13.15 12.92,13.34zM12.67,9.8l-2.55,1.36l-0.17,-0.32c-0.37,-0.7 -0.13,-1.61 0.58,-1.98c0.7,-0.37 1.59,-0.08 1.97,0.63L12.67,9.8z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M11.48,1.5c3.62,-0.23 7.16,1.5 9.3,4.66l1.32,-0.71C18.65,0.27 11.89,-1.55 6.34,1.42C6.16,1.51 5.98,1.61 5.72,1.75l5.14,1.56L11.48,1.5zM12.52,22.5c-3.62,0.23 -7.16,-1.5 -9.3,-4.66L1.98,18.5c3.37,5.23 10.13,7.06 15.68,4.08c0.18,-0.09 0.35,-0.19 0.62,-0.33l-5.14,-1.56L12.52,22.5z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_12.xml b/packages/SystemUI/res/drawable/ic_rotate_24_12.xml
new file mode 100644
index 0000000..d408e28
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_12.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M10.83,8.49c-0.91,0.3,-1.39,1.31,-1.09,2.22l0.13,0.41l3.28,-1.08l-0.13,-0.41 C12.72,8.72,11.73,8.19,10.83,8.49z"
+ android:fill="#00000000"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M13.98,9.77l-0.13,-0.41C13.4,8.0 11.93,7.26 10.57,7.71c-1.36,0.45 -2.1,1.91 -1.65,3.27l0.13,0.41c-0.45,0.15 -0.7,0.64 -0.55,1.09l1.35,4.1c0.15,0.45 0.64,0.7 1.09,0.55l4.92,-1.62c0.45,-0.15 0.7,-0.64 0.55,-1.09l-1.35,-4.1C14.92,9.87 14.43,9.62 13.98,9.77zM12.73,14.27c-0.45,0.15 -0.94,-0.1 -1.09,-0.55c-0.15,-0.45 0.1,-0.94 0.55,-1.09c0.45,-0.15 0.94,0.1 1.09,0.55C13.43,13.64 13.18,14.12 12.73,14.27zM13.16,10.04l-3.28,1.08l-0.13,-0.41c-0.3,-0.91 0.18,-1.92 1.09,-2.22c0.91,-0.3 1.9,0.24 2.19,1.14L13.16,10.04z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M13.55,1.6c3.59,0.48 6.72,2.87 8.21,6.39l1.44,-0.44C20.82,1.8 14.54,-1.31 8.51,0.52c-0.19,0.06 -0.38,0.12 -0.67,0.2l4.74,2.53L13.55,1.6zM10.45,22.4c-3.59,-0.48 -6.72,-2.87 -8.21,-6.39L0.9,16.41c2.28,5.79 8.55,8.9 14.58,7.07c0.19,-0.06 0.38,-0.12 0.67,-0.2l-4.74,-2.53L10.45,22.4z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_13.xml b/packages/SystemUI/res/drawable/ic_rotate_24_13.xml
new file mode 100644
index 0000000..1ac6b39
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_13.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M11.17,7.71c-1.09,0.19,-1.8,1.28,-1.61,2.37l0.09,0.49l3.94,-0.7l-0.09,-0.49C13.3,8.3,12.26,7.52,11.17,7.71 z"
+ android:fill="#00000000"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M14.57,9.7l-0.09,-0.49C14.19,7.58 12.63,6.49 11.0,6.78c-1.63,0.29 -2.71,1.85 -2.43,3.48l0.08,0.49c-0.54,0.1 -0.91,0.62 -0.81,1.16l0.87,4.92c0.1,0.54 0.62,0.91 1.16,0.81l5.91,-1.05c0.54,-0.1 0.91,-0.61 0.81,-1.16l-0.87,-4.92C15.63,9.97 15.11,9.61 14.57,9.7zM12.4,14.66c-0.54,0.1 -1.06,-0.27 -1.16,-0.81c-0.1,-0.54 0.27,-1.06 0.81,-1.16s1.06,0.27 1.16,0.81C13.3,14.04 12.94,14.56 12.4,14.66zM13.58,9.88l-3.94,0.7l-0.09,-0.49c-0.19,-1.09 0.52,-2.17 1.61,-2.37s2.13,0.58 2.33,1.67L13.58,9.88z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M14.99,1.92c3.49,0.97 6.26,3.78 7.24,7.48l1.48,-0.23c-1.55,-6.03 -7.32,-9.99 -13.55,-9.02c-0.2,0.03 -0.4,0.06 -0.69,0.11l4.34,3.17L14.99,1.92zM9.01,22.08C5.52,21.1 2.76,18.3 1.78,14.6L0.4,14.82c1.45,6.05 7.22,10.01 13.45,9.04c0.2,-0.03 0.4,-0.06 0.69,-0.11l-4.34,-3.17L9.01,22.08z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_14.xml b/packages/SystemUI/res/drawable/ic_rotate_24_14.xml
new file mode 100644
index 0000000..c43e363c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_14.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M11.72,7.61c-1.1,0.08,-1.93,1.08,-1.86,2.18l0.03,0.5l3.99,-0.27l-0.03,-0.5 C13.78,8.42,12.82,7.54,11.72,7.61z"
+ android:fill="#00000000"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M14.88,9.95l-0.03,-0.5c-0.11,-1.65 -1.54,-2.9 -3.2,-2.79C10.0,6.78 8.75,8.21 8.87,9.86l0.03,0.5c-0.55,0.04 -0.97,0.52 -0.93,1.07l0.34,4.99c0.04,0.55 0.52,0.97 1.07,0.93l5.99,-0.41c0.55,-0.04 0.97,-0.51 0.93,-1.07l-0.34,-4.99C15.91,10.33 15.43,9.91 14.88,9.95zM12.2,14.64c-0.55,0.04 -1.03,-0.38 -1.07,-0.93c-0.04,-0.55 0.38,-1.03 0.93,-1.07c0.55,-0.04 1.03,0.38 1.07,0.93C13.16,14.13 12.75,14.61 12.2,14.64zM13.88,10.02l-3.99,0.27l-0.03,-0.5c-0.08,-1.1 0.75,-2.11 1.86,-2.18c1.1,-0.08 2.06,0.81 2.13,1.91L13.88,10.02z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M15.71,2.17c3.41,1.23 5.96,4.23 6.67,7.98l1.5,-0.12c-1.1,-6.13 -6.58,-10.5 -12.86,-9.99c-0.2,0.02 -0.4,0.03 -0.7,0.06l4.1,3.48L15.71,2.17zM8.29,21.83c-3.41,-1.23 -5.96,-4.23 -6.67,-7.98l-1.4,0.11c1.0,6.14 6.48,10.51 12.76,9.99c0.2,-0.02 0.4,-0.03 0.7,-0.06l-4.1,-3.48L8.29,21.83z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_15.xml b/packages/SystemUI/res/drawable/ic_rotate_24_15.xml
new file mode 100644
index 0000000..22fa428
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_24_15.xml
@@ -0,0 +1,34 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+ <path
+ android:pathData="M12.05,7.7c-1.1,0,-2,0.94,-2,2.05v0.5h4v-0.5C14.05,8.65,13.15,7.7,12.05,7.7z"
+ android:fill="#00000000"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M15.05,10.25l0.0,-0.5c0.0,-1.66 -1.34,-3.0 -3.0,-3.0s-2.99,1.34 -2.99,3.0l-0.01,0.5c-0.55,0.0 -1.0,0.45 -1.0,1.0l0.0,5.0c0.0,0.55 0.45,1.0 1.0,1.0l6.0,0.0c0.55,0.0 1.0,-0.45 1.0,-1.0l0.0,-5.0C16.05,10.7 15.6,10.25 15.05,10.25zM12.05,14.75c-0.55,0.0 -1.0,-0.45 -1.0,-1.0c0.0,-0.55 0.45,-1.0 1.0,-1.0s1.0,0.45 1.0,1.0C13.05,14.3 12.6,14.75 12.05,14.75zM14.05,10.25l-4.0,0.0l0.0,-0.5c0.0,-1.1 0.9,-2.05 2.0,-2.05s2.0,0.94 2.0,2.05L14.05,10.25z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M16.5,2.5c3.3,1.5 5.6,4.7 6.0,8.5L24.0,11.0C23.4,4.8 18.3,0.0 12.0,0.0c-0.2,0.0 -0.4,0.0 -0.7,0.0l3.8,3.8L16.5,2.5zM7.5,21.5c-3.3,-1.5 -5.6,-4.7 -6.0,-8.5L0.1,13.0C0.6,19.2 5.7,24.0 12.0,24.0c0.2,0.0 0.4,0.0 0.7,0.0l-3.8,-3.8L7.5,21.5z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_locked_anim.xml b/packages/SystemUI/res/drawable/ic_rotate_locked_anim.xml
new file mode 100644
index 0000000..e14a1ce
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_locked_anim.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<animation-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:oneshot="true">
+ <item android:drawable="@drawable/ic_rotate_24_01" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_02" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_03" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_04" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_05" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_06" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_07" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_08" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_09" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_10" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_11" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_12" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_13" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_14" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_15" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_unlocked_anim.xml b/packages/SystemUI/res/drawable/ic_rotate_unlocked_anim.xml
new file mode 100644
index 0000000..63b8c5f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_rotate_unlocked_anim.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<animation-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:oneshot="true">
+ <item android:drawable="@drawable/ic_rotate_24_15" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_14" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_13" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_12" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_11" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_10" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_09" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_08" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_07" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_06" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_05" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_04" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_03" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_02" android:duration="16" />
+ <item android:drawable="@drawable/ic_rotate_24_01" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_settings_24dp.xml b/packages/SystemUI/res/drawable/ic_settings_24dp.xml
new file mode 100644
index 0000000..a2f7822
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_settings_24dp.xml
@@ -0,0 +1,29 @@
+<!-- Copyright (C) 2014 The Android Open Source Project
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at"+
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+<size
+android:width="24dp"
+android:height="24dp"/>
+
+ <viewport android:viewportWidth="24.0"
+ android:viewportHeight="24.0"/>
+
+
+<path
+ android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z"
+ android:fill="#ffffffff"
+ />
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/notification_header_bg.xml b/packages/SystemUI/res/drawable/notification_header_bg.xml
new file mode 100644
index 0000000..09d0d7d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notification_header_bg.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2014 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true">
+ <shape>
+ <solid android:color="@color/background_color_1_press" />
+ <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" />
+ </shape>
+ </item>
+ <item>
+ <shape>
+ <solid android:color="@color/background_color_1" />
+ <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" />
+ </shape>
+ </item>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_panel_background.xml b/packages/SystemUI/res/drawable/qs_panel_background.xml
new file mode 100644
index 0000000..c324976
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_panel_background.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetLeft="@dimen/notification_side_padding"
+ android:insetRight="@dimen/notification_side_padding">
+ <shape>
+ <solid android:color="@color/system_primary_color" />
+ <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" />
+ </shape>
+</inset>
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_dark.xml b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
new file mode 100644
index 0000000..744795e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1" >
+
+ <size
+ android:height="16dp"
+ android:width="16dp" />
+
+ <viewport
+ android:viewportHeight="100"
+ android:viewportWidth="100" />
+
+ <path
+ android:name="x"
+ android:pathData="M0,0L100,100M0,100L100,0z"
+ android:stroke="@color/recents_task_bar_dark_dismiss_color"
+ android:strokeWidth="8.0"
+ android:strokeLineCap="square" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_light.xml b/packages/SystemUI/res/drawable/recents_dismiss_light.xml
new file mode 100644
index 0000000..96bfbe1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_dismiss_light.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1" >
+
+ <size
+ android:height="16dp"
+ android:width="16dp" />
+
+ <viewport
+ android:viewportHeight="100"
+ android:viewportWidth="100" />
+
+
+ <path
+ android:name="x"
+ android:pathData="M0,0L100,100M0,100L100,0z"
+ android:stroke="@color/recents_task_bar_light_dismiss_color"
+ android:strokeWidth="8.0"
+ android:strokeLineCap="square" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/flip_settings.xml b/packages/SystemUI/res/layout/flip_settings.xml
deleted file mode 100644
index 28d9625..0000000
--- a/packages/SystemUI/res/layout/flip_settings.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<com.android.systemui.statusbar.phone.QuickSettingsContainerView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/quick_settings_container"
- android:padding="@dimen/notification_side_padding"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="#5f000000"
- android:animateLayoutChanges="true"
- android:columnCount="@integer/quick_settings_num_columns" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/heads_up.xml b/packages/SystemUI/res/layout/heads_up.xml
index e4954e7..7d9cfa1 100644
--- a/packages/SystemUI/res/layout/heads_up.xml
+++ b/packages/SystemUI/res/layout/heads_up.xml
@@ -20,7 +20,7 @@
<com.android.systemui.statusbar.policy.HeadsUpNotificationView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
- android:layout_width="@dimen/notification_panel_width"
+ android:layout_width="match_parent"
android:id="@+id/content_holder"
android:background="@drawable/notification_panel_bg"
/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
new file mode 100644
index 0000000..b24d4ad
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/quick_settings_container"
+ android:paddingLeft="@dimen/notification_side_padding"
+ android:paddingRight="@dimen/notification_side_padding"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/qs_panel_background" >
+ <com.android.systemui.qs.QSPanel
+ android:id="@+id/quick_settings_panel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/qs_zen_mode_detail.xml b/packages/SystemUI/res/layout/qs_zen_mode_detail.xml
new file mode 100644
index 0000000..2df6d43
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_zen_mode_detail.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.systemui.qs.tiles.ZenModeDetail xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/system_secondary_color" >
+
+ <com.android.systemui.qs.QSImageView
+ android:id="@android:id/button1"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_alignParentStart="true"
+ android:padding="@dimen/quick_settings_panel_padding" />
+
+ <Switch
+ android:id="@android:id/checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="64dp"
+ android:layout_alignParentEnd="true"
+ android:gravity="center"
+ android:padding="@dimen/quick_settings_panel_padding" />
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="match_parent"
+ android:layout_height="64dp"
+ android:layout_toEndOf="@android:id/button1"
+ android:layout_toStartOf="@android:id/checkbox"
+ android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
+ android:gravity="center_vertical"
+ android:paddingStart="@dimen/quick_settings_panel_padding"
+ android:text="@string/zen_mode_title" />
+
+ <View
+ android:id="@android:id/custom"
+ android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:layout_below="@android:id/title"
+ android:background="#888" />
+
+ <ListView
+ android:id="@android:id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_above="@android:id/button2"
+ android:layout_below="@android:id/custom"
+ android:divider="#00000000"
+ android:dividerHeight="0px" />
+
+ <TextView
+ android:id="@android:id/button2"
+ style="@style/QSBorderless"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
+ android:padding="@dimen/quick_settings_panel_padding"
+ android:text="@string/quick_settings_more_settings"
+ android:textAllCaps="true" />
+
+</com.android.systemui.qs.tiles.ZenModeDetail>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml b/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml
new file mode 100644
index 0000000..a5c8903
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <RadioButton
+ android:id="@android:id/checkbox"
+ android:layout_width="32dp"
+ android:layout_height="64dp"
+ android:layout_alignParentStart="true"
+ android:layout_marginStart="@dimen/quick_settings_panel_padding"
+ android:gravity="center" />
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="match_parent"
+ android:layout_height="64dp"
+ android:layout_toEndOf="@android:id/checkbox"
+ android:layout_toStartOf="@android:id/button1"
+ android:ellipsize="end"
+ android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
+ android:gravity="center_vertical"
+ android:maxLines="1"
+ android:text="@string/accessibility_back" />
+
+ <com.android.systemui.qs.QSImageView
+ android:id="@android:id/button1"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_alignParentEnd="true"
+ android:layout_marginEnd="48dp"
+ android:padding="@dimen/quick_settings_panel_padding"
+ android:paddingRight="0px" />
+
+ <com.android.systemui.qs.QSImageView
+ android:id="@android:id/button2"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_alignParentEnd="true"
+ android:padding="@dimen/quick_settings_panel_padding" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index b7df51d..1efda8c 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -29,7 +29,7 @@
<com.android.systemui.settings.ToggleSlider
android:id="@+id/brightness_slider"
android:layout_width="0dp"
- android:layout_height="40dp"
+ android:layout_height="44dp"
android:layout_gravity="center_vertical"
android:layout_weight="1"
systemui:text="@string/status_bar_settings_auto_brightness_label" />
diff --git a/packages/SystemUI/res/layout/quick_settings_tile.xml b/packages/SystemUI/res/layout/quick_settings_tile.xml
deleted file mode 100644
index 911f6a2..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<com.android.systemui.statusbar.phone.QuickSettingsTileView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/quick_settings_cell_height"
- android:background="@drawable/qs_tile_background" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_alarm.xml b/packages/SystemUI/res/layout/quick_settings_tile_alarm.xml
deleted file mode 100644
index 493c704..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_alarm.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/TextAppearance.QuickSettings.TileView.AllInOne"
- android:id="@+id/alarm_textview"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:gravity="center"
- android:drawableTop="@drawable/ic_qs_alarm_on"
- />
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_basic.xml b/packages/SystemUI/res/layout/quick_settings_tile_basic.xml
deleted file mode 100644
index 16bf49c..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_basic.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="top"
- android:orientation="vertical">
- <ImageView
- android:id="@+id/image"
- android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
- android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
- android:layout_width="@dimen/qs_tile_icon_size"
- android:layout_height="@dimen/qs_tile_icon_size"
- android:layout_gravity="top|center_horizontal"
- android:scaleType="centerInside"
- />
- <TextView
- style="@style/TextAppearance.QuickSettings.TileView"
- android:id="@+id/text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center_horizontal"
- android:gravity="top|center_horizontal"
- />
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
deleted file mode 100644
index 1f39aef..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="top"
- android:orientation="vertical">
- <com.android.systemui.BatteryMeterView
- android:id="@+id/image"
- android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
- android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
- android:layout_width="22dp"
- android:layout_height="32dp"
- android:padding="3dp"
- android:layout_gravity="top|center_horizontal"
- systemui:frameColor="@color/qs_batterymeter_frame_color"
- />
- <TextView
- style="@style/TextAppearance.QuickSettings.TileView"
- android:id="@+id/text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center_horizontal"
- android:gravity="top|center_horizontal"
- />
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_ime.xml b/packages/SystemUI/res/layout/quick_settings_tile_ime.xml
deleted file mode 100644
index 1a31efa5..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_ime.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/TextAppearance.QuickSettings.TileView.AllInOne"
- android:id="@+id/ime_textview"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:gravity="center"
- android:drawableTop="@drawable/ic_qs_ime"
- android:text="@string/quick_settings_ime_label"
- />
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_media.xml b/packages/SystemUI/res/layout/quick_settings_tile_media.xml
deleted file mode 100644
index 355176c6..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_media.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/TextAppearance.QuickSettings.TileView.AllInOne"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:text="@string/quick_settings_media_device_label"
- android:singleLine="true"
- />
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_monitoring.xml b/packages/SystemUI/res/layout/quick_settings_tile_monitoring.xml
deleted file mode 100644
index 4fa48eb..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_monitoring.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="top"
- android:orientation="vertical">
- <ImageView
- android:id="@+id/image"
- android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
- android:layout_marginBottom="@dimen/qs_cawarn_tile_margin_below_icon"
- android:layout_width="@dimen/qs_tile_icon_size"
- android:layout_height="@dimen/qs_tile_icon_size"
- android:layout_gravity="top|center_horizontal"
- android:scaleType="centerInside"
- />
- <TextView
- style="@style/TextAppearance.QuickSettings.CaCertWarning"
- android:id="@+id/text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center_horizontal"
- android:gravity="top|center_horizontal"
- />
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml b/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
deleted file mode 100644
index 6bf31e0..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="top">
- <FrameLayout
- android:id="@+id/rssi_images"
- android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
- android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
- android:layout_width="@dimen/qs_tile_icon_size"
- android:layout_height="@dimen/qs_tile_icon_size"
- android:layout_gravity="top|center_horizontal"
- android:layout_centerHorizontal="true"
- >
- <ImageView
- android:id="@+id/rssi_image"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- />
- <ImageView
- android:id="@+id/rssi_overlay_image"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- />
- </FrameLayout>
- <ImageView
- android:id="@+id/activity_in"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_qs_signal_in"
- android:layout_toRightOf="@id/rssi_images"
- android:layout_alignBottom="@id/rssi_images"
- />
- <ImageView
- android:id="@+id/activity_out"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_qs_signal_out"
- android:layout_toRightOf="@id/rssi_images"
- android:layout_alignBottom="@id/rssi_images"
- />
- <TextView
- style="@style/TextAppearance.QuickSettings.TileView"
- android:id="@+id/rssi_textview"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center_horizontal"
- android:gravity="top|center_horizontal"
- android:text="@string/quick_settings_rssi_label"
- android:layout_centerHorizontal="true"
- android:layout_below="@id/rssi_images"
- android:textAllCaps="@bool/quick_settings_rssi_tile_capitalization"
- />
-</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_user.xml b/packages/SystemUI/res/layout/quick_settings_tile_user.xml
deleted file mode 100644
index 80fc685..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_user.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <ImageView
- android:id="@+id/user_imageview"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:src="@drawable/ic_qs_default_user"
- android:scaleType="centerCrop"
- />
- <TextView
- style="@style/TextAppearance.QuickSettings.TileView.User"
- android:id="@+id/user_textview"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal|bottom"
- android:gravity="center"
- android:text="@string/quick_settings_user_label"
- />
-</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml b/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml
deleted file mode 100644
index e61c595..0000000
--- a/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="top">
- <ImageView
- android:id="@+id/image"
- android:layout_marginTop="@dimen/qs_tile_margin_above_icon"
- android:layout_marginBottom="@dimen/qs_tile_margin_below_icon"
- android:layout_width="@dimen/qs_tile_icon_size"
- android:layout_height="@dimen/qs_tile_icon_size"
- android:layout_gravity="top|center_horizontal"
- android:layout_centerHorizontal="true"
- android:scaleType="centerInside"
- />
- <ImageView
- android:id="@+id/activity_in"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_qs_wifi_in"
- android:layout_toRightOf="@id/image"
- android:layout_alignBottom="@id/image"
- />
- <ImageView
- android:id="@+id/activity_out"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_qs_wifi_out"
- android:layout_toRightOf="@id/image"
- android:layout_alignBottom="@id/image"
- />
- <TextView
- style="@style/TextAppearance.QuickSettings.TileView"
- android:id="@+id/text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center_horizontal"
- android:gravity="top|center_horizontal"
- android:layout_centerHorizontal="true"
- android:layout_below="@id/image"
- />
-</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index f7df18eb..bda6431 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -63,6 +63,13 @@
android:maxLines="2"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
+ <ImageView
+ android:id="@+id/dismiss_task"
+ android:layout_width="@dimen/recents_task_view_application_icon_size"
+ android:layout_height="@dimen/recents_task_view_application_icon_size"
+ android:layout_gravity="center_vertical|end"
+ android:padding="23dp"
+ android:src="@drawable/recents_dismiss_dark" />
</com.android.systemui.recents.views.TaskBarView>
</com.android.systemui.recents.views.TaskView>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 1b35537..585658e 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -77,26 +77,24 @@
<LinearLayout android:id="@+id/system_icon_area"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:orientation="horizontal">
-
- <LinearLayout android:id="@+id/statusIcons"
+ android:orientation="horizontal"
+ >
+ <LinearLayout android:id="@+id/system_icons"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
- android:orientation="horizontal"/>
-
- <LinearLayout
- android:id="@+id/signal_battery_cluster"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingStart="2dp"
- android:orientation="horizontal"
- android:gravity="center"
>
- <include layout="@layout/signal_cluster_view"
+ <LinearLayout android:id="@+id/statusIcons"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"/>
+
+ <include layout="@layout/signal_cluster_view"
android:id="@+id/signal_cluster"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginStart="2dp"
/>
<!-- battery must be padded below to match assets -->
<com.android.systemui.BatteryMeterView
@@ -107,7 +105,6 @@
android:layout_marginStart="4dip"
/>
</LinearLayout>
-
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
android:textAppearance="@style/TextAppearance.StatusBar.Clock"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 3267c36..2ec9935 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -22,7 +22,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:id="@+id/notification_panel"
- android:layout_width="0dp"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
>
@@ -34,15 +34,6 @@
android:layout_gravity="bottom"
/>
- <com.android.keyguard.CarrierText
- android:id="@+id/keyguard_carrier_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="2dp"
- android:layout_marginLeft="8dp"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
<include
layout="@layout/keyguard_status_view"
android:layout_height="wrap_content"
@@ -59,9 +50,8 @@
/>
<com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
+ style="@style/NotificationsQuickSettings"
android:id="@+id/notification_container_parent"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
android:clipToPadding="false"
android:clipChildren="false">
@@ -77,7 +67,7 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<include
- layout="@layout/flip_settings"
+ layout="@layout/qs_panel"
android:layout_marginTop="@dimen/status_bar_header_height_expanded"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
@@ -98,11 +88,7 @@
</com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>
-
- <include layout="@layout/status_bar_expanded_header"
- android:layout_width="match_parent"
- android:layout_height="@dimen/status_bar_header_height"
- />
+ <include layout="@layout/status_bar_expanded_header" />
<include
layout="@layout/keyguard_bottom_area"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 460dd4b..89fa988 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -20,11 +20,12 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:id="@+id/header"
- android:layout_width="match_parent"
+ style="@style/StatusBarHeader"
android:layout_height="@dimen/status_bar_header_height"
- android:orientation="horizontal"
- android:gravity="center_vertical"
+ android:paddingStart="@dimen/notification_side_padding"
+ android:paddingEnd="@dimen/notification_side_padding"
android:baselineAligned="false"
+ android:elevation="10dp"
>
<View
@@ -37,10 +38,12 @@
<RelativeLayout
android:id="@+id/datetime"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:layout_gravity="start"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
android:background="@drawable/ic_notify_button_bg"
android:enabled="false"
>
@@ -48,10 +51,9 @@
android:id="@+id/clock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginEnd="8dp"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
- android:layout_centerVertical="true"
+ systemui:amPmStyle="normal"
/>
<com.android.systemui.statusbar.policy.DateView android:id="@+id/date"
@@ -59,11 +61,49 @@
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
- android:layout_toEndOf="@id/clock"
- android:layout_alignBaseline="@id/clock"
+ android:layout_below="@id/clock"
/>
</RelativeLayout>
+ <com.android.keyguard.CarrierText
+ android:id="@+id/keyguard_carrier_text"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/status_bar_header_height_keyguard"
+ android:layout_marginLeft="8dp"
+ android:gravity="center_vertical"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch"
+ android:layout_width="40dp"
+ android:layout_height="@dimen/status_bar_header_height"
+ android:layout_alignParentEnd="true"
+ android:background="@null"
+ android:scaleType="centerInside"
+ android:padding="6dp"
+ />
+
+ <ImageButton android:id="@+id/settings_button"
+ style="@android:style/Widget.Quantum.Button.Borderless"
+ android:layout_toStartOf="@id/multi_user_switch"
+ android:layout_width="56dp"
+ android:layout_height="@dimen/status_bar_header_height"
+ android:src="@drawable/ic_settings_24dp"
+ android:contentDescription="@string/accessibility_desc_quick_settings"/>
+
+ <FrameLayout android:id="@+id/system_icons_container"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/status_bar_header_height"
+ android:layout_toStartOf="@id/multi_user_switch"
+ android:layout_marginEnd="4dp"
+ />
+
+ <include
+ layout="@layout/quick_settings_brightness_dialog"
+ android:id="@+id/brightness_container"
+ android:layout_width="match_parent"
+ />
+
<TextView
android:id="@+id/header_debug_info"
android:visibility="invisible"
@@ -77,22 +117,4 @@
android:padding="2dp"
/>
- <include layout="@layout/status_bar_flip_button"
- android:id="@+id/header_flipper"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:layout_alignParentEnd="true"/>
-
- <ImageView android:id="@+id/clear_all_button"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:layout_toStartOf="@id/header_flipper"
- android:scaleType="center"
- android:src="@drawable/ic_notify_clear"
- android:background="@drawable/ic_notify_button_bg"
- android:contentDescription="@string/accessibility_clear_all"
- />
-
-
-
</com.android.systemui.statusbar.phone.StatusBarHeaderView>
diff --git a/packages/SystemUI/res/layout/status_bar_flip_button.xml b/packages/SystemUI/res/layout/status_bar_flip_button.xml
deleted file mode 100644
index f4d7033..0000000
--- a/packages/SystemUI/res/layout/status_bar_flip_button.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2014 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/settings_button"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:scaleType="center"
- android:src="@drawable/ic_notify_quicksettings"
- android:background="@drawable/ic_notify_button_bg"
- android:contentDescription="@string/accessibility_desc_quick_settings"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
index e6d7c93..7671c354a 100644
--- a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
+++ b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
@@ -28,6 +28,8 @@
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:button="@null"
+ android:background="@*android:drawable/switch_track_quantum"
+ android:visibility="gone"
/>
<com.android.systemui.settings.ToggleSeekBar
android:id="@+id/slider"
@@ -35,6 +37,7 @@
android:layout_height="wrap_content"
android:layout_toEndOf="@id/toggle"
android:layout_centerVertical="true"
+ android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:paddingStart="20dp"
android:paddingEnd="20dp"
@@ -50,5 +53,6 @@
android:paddingTop="26dp"
android:textColor="#666666"
android:textSize="12sp"
+ android:visibility="gone"
/>
</merge>
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index f9b022c..26616cd 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -35,9 +35,9 @@
android:layout_width="match_parent"
android:layout_height="match_parent" >
<include layout="@layout/status_bar_expanded"
- android:layout_width="@dimen/notification_panel_width"
+ android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_gravity="start|top" />
+ android:visibility="gone" />
</com.android.systemui.statusbar.phone.PanelHolder>
</com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/SystemUI/res/layout/user_switcher_host.xml b/packages/SystemUI/res/layout/user_switcher_host.xml
index bc56cf6..70c5042 100644
--- a/packages/SystemUI/res/layout/user_switcher_host.xml
+++ b/packages/SystemUI/res/layout/user_switcher_host.xml
@@ -22,7 +22,8 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="#dd000000">
+ android:background="#dd000000"
+ android:elevation="12dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 8ec48c8..eb66a59 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Onlangse programme"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Deursoek"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Foon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knoppie vir wissel van invoermetode."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Versoenbaarheid-zoem se knoppie."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoem kleiner na groter skerm."</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 7aaaaf3..a3eca6a 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"የቅርብ ጊዜ መተግበሪያዎች"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"ፈልግ"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"ካሜራ"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"ስልክ"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"የግቤት ስልት አዝራር ቀይር"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"የተኳኋኝአጉላ አዝራር።"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"አነስተኛውን ማያ ወደ ትልቅ አጉላ።"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 1c06615..0060004 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"التطبيقات الحديثة"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"بحث"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"الكاميرا"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"الهاتف"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"زر تبديل طريقة الإدخال."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"زر تكبير/تصغير للتوافق."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"استخدام التكبير/التصغير لتحويل شاشة صغيرة إلى شاشة أكبر"</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"وضع انعكاس اللون"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"وضع التباين المحسن"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"وضع تصحيح الألوان"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"الأخيرة"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"معلومات التطبيق"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"بحث"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"قد تكون الشبكة\nخاضعة للرقابة"</string>
<string name="description_target_search" msgid="3091587249776033139">"بحث"</string>
<string name="description_direction_up" msgid="7169032478259485180">"تمرير لأعلى لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"تمرير لليسار لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"تم إخفاء الإشعار"</item>
- <item quantity="other" msgid="7388721375827338153">"تم إخفاء %d من الإشعارات"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"المس للعرض"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"الرجاء عدم الإزعاج"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d أخرى"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"انقر مرة أخرى للفتح"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"مرر سريعًا لأعلى لإلغاء القفل"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index febcab6..e03a2f9 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Скорошни приложения"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Търсене"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Телефон"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Бутон за превключване на метода на въвеждане."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Бутон за промяна на мащаба с цел съвместимост."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Промяна на мащаба на екрана от по-малък до по-голям."</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 658ece0..e50a155 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Aplicacions recents"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Cerca"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Càmera"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telèfon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botó de canvi del mètode d\'entrada."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botó de zoom de compatibilitat."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Amplia menys com més gran sigui la pantalla."</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index c7d2703..a2d9d9c 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Nové aplikace"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Hledat"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparát"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačítko přepnutí metody zadávání"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačítko úpravy velikosti z důvodu kompatibility"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zvětšit menší obrázek na větší obrazovku."</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index c740051..1e6011c 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Seneste apps"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Søg"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Skift indtastningsmetode-knappen."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knap for kompatibilitetszoom."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom mindre til større skærm."</string>
@@ -184,8 +183,8 @@
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Lysstyrke"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Automatisk rotation"</string>
<string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotation er låst"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Altid stående"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Altid liggende"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Låst i portræt"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Låst i landskab"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Inputmetode"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Placering"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Placering fra"</string>
@@ -199,28 +198,14 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ikke forbundet"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Intet netværk"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi slået fra"</string>
- <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Cast skærm"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Cast-skærm"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Farveinverteringstilstand"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Tilstand for forbedret kontrast"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Farvekorrigeringstilstand"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"SENESTE"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Oplysninger om applikationen"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"søg"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netværket kan\nvære overvåget"</string>
<string name="description_target_search" msgid="3091587249776033139">"Søgning"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Glid op for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Glid til venstre for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Underretningen er skjult"</item>
- <item quantity="other" msgid="7388721375827338153">"%d underretninger er skjult"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Tryk for at vise"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Vil ikke forstyrres"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d mere"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Tryk igen for at åbne"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Stryg for at låse op"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 40ecc49..fd41752 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Kürzlich geöffnete Apps"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Suchen"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefonnummer"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Schaltfläche zum Ändern der Eingabemethode"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Schaltfläche für Kompatibilitätszoom"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom auf einen größeren Bildschirm"</string>
@@ -166,7 +165,7 @@
<string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Daten erneut aktivieren"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Keine Internetverbindung"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string>
- <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS wird gesucht..."</string>
+ <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS wird gesucht"</string>
<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>
@@ -207,22 +206,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Farbinversionsmodus"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Kontrastverbesserungsmodus"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Farbkorrekturmodus"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"Letzte"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-Info"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"Suche"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netzwerk wird\neventuell überwacht."</string>
<string name="description_target_search" msgid="3091587249776033139">"Suche"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach oben schieben"</string>
<string name="description_direction_left" msgid="7207478719805562165">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach links schieben"</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Benachrichtigung ausgeblendet"</item>
- <item quantity="other" msgid="7388721375827338153">"%d Benachrichtigungen ausgeblendet"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Zum Ansehen tippen"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Nicht stören"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d mehr"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Erneut tippen, um Benachrichtigung zu öffnen"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Zum Entsperren nach oben wischen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 0e98ce0..96e2aaa 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Πρόσφατες εφαρμογές"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Αναζήτηση"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Φωτογραφική μηχανή"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Τηλέφωνο"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Κουμπί εναλλαγής μεθόδου εισόδου"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Κουμπί εστίασης συμβατότητας."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Ζουμ από μικρότερη σε μεγαλύτερη οθόνη."</string>
@@ -207,22 +206,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Λειτουργία αναστροφής χρώματος"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Λειτουργία βελτίωσης αντίθεσης"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Λειτουργία διόρθωσης χρώματος"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"ΠΡΟΣΦΑΤΑ"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Πληροφορίες εφαρμογής"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Το δίκτυο μπορεί\nνα παρακολουθείται"</string>
<string name="description_target_search" msgid="3091587249776033139">"Αναζήτηση"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Κύλιση προς τα επάνω για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Κύλιση προς τα αριστερά για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Έγινε απόκρυψη της ειδοποίησης"</item>
- <item quantity="other" msgid="7388721375827338153">"Έγινε απόκρυψη %d ειδοποιήσεων"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Αγγίξτε για εμφάνιση"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Μην ενοχλείτε"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d ακόμη"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Πατήστε ξανά για να ανοίξετε"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Σύρετε για να ξεκλειδώσετε"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index f4098b7..342061e 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Recent apps"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Search"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Phone"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Colour inversion mode"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Enhanced contrast mode"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Colour correction mode"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"RECENTS"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string>
<string name="description_target_search" msgid="3091587249776033139">"Search"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Slide left for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Notification hidden"</item>
- <item quantity="other" msgid="7388721375827338153">"%d notifications hidden"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Touch to show"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Do not disturb"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d more"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Swipe up to unlock"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index f4098b7..342061e 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Recent apps"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Search"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Phone"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Colour inversion mode"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Enhanced contrast mode"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Colour correction mode"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"RECENTS"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string>
<string name="description_target_search" msgid="3091587249776033139">"Search"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Slide left for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Notification hidden"</item>
- <item quantity="other" msgid="7388721375827338153">"%d notifications hidden"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Touch to show"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Do not disturb"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d more"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Swipe up to unlock"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 51198e6..00041a2 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Aplicaciones recientes"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Buscar"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Cámara"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Teléfono"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 1b73e18..2a977ee 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Aplicaciones recientes"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Buscar"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Cámara"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Teléfono"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>
@@ -199,28 +198,14 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"No conectado"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No hay red."</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desactivado"</string>
- <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Enviar contenido a pantalla"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Pantalla de Cast"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modo de inversión de color"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Modo de contraste mejorado"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de corrección de color"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"RECIENTES"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La red se\npuede supervisar"</string>
<string name="description_target_search" msgid="3091587249776033139">"Buscar"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Desliza el dedo hacia arriba para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Desliza el dedo hacia la izquierda para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Notification oculta"</item>
- <item quantity="other" msgid="7388721375827338153">"%d notificaciones ocultas"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Toca para mostrar"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"No molestar"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d más"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Toca de nuevo para abrir"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Desliza el dedo hacia arriba para desbloquear"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 0f95c60..4c42a32 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Hiljutised rakendused"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Otsing"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kaamera"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Sisestusmeetodi vahetamise nupp."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Sobivussuumi nupp."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Suumi suuremale ekraanile vähem."</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index f36d04b..a9c6af7 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"برنامههای اخیر"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"جستجو"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"دوربین"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"تلفن"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"کلید تغییر روش ورود متن."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"دکمه بزرگنمایی سازگار."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"بزرگنمایی از صفحههای کوچک تا بزرگ."</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 4ae3851..8ddf070 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Viimeaikaiset sovellukset"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Haku"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Puhelin"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Syöttötavan vaihtopainike."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Yhteensopivuuszoomaus-painike."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoomaa pienemmältä suuremmalle ruudulle."</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index c55a5fc..69b5acc 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Applications récentes"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Rechercher"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Appareil photo"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Téléphone"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 1121918..85f817b 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Applications récentes"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Rechercher"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Appareil photo"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Téléphoner"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index f9e6aad..3167fe7 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"हाल ही के ऐप्स"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"खोजें"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"कैमरा"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"फ़ोन"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धति बटन स्विच करें."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"संगतता ज़ूम बटन."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"छोटी से बड़ी स्क्रीन पर ज़ूम करें."</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"रंग व्युत्क्रम मोड"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"उन्नत कंट्रास्ट मोड"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"रंग सुधार मोड"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"हाल ही का"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"एप्लिकेशन जानकारी"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"खोज"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"नेटवर्क को\nमॉनीटर किया जा सकता है"</string>
<string name="description_target_search" msgid="3091587249776033139">"खोजें"</string>
<string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए ऊपर स्लाइड करें."</string>
<string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए बाएं स्लाइड करें."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"सूचना छिपी हुई है"</item>
- <item quantity="other" msgid="7388721375827338153">"%d सूचनाएं छिपी हुई हैं"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"दिखाने के लिए स्पर्श करें"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"परेशान न करें"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d और"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"खोलने के लिए पुन: टैप करें"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"अनलॉक करने के लिए ऊपर स्वाइप करें"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 435f701..529f891 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Nedavne aplikacije"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Pretraži"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparat"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za promjenu načina unosa."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Gumb za kompatibilnost zumiranja."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zumiranje manjeg zaslona na veći."</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Način inverzije boje"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Način pojačanog kontrasta"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Način korekcije boje"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"NEDAVNO"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mreža se\nmožda prati"</string>
<string name="description_target_search" msgid="3091587249776033139">"Pretraživanje"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Kliznite prema gore za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Kliznite lijevo za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Obavijest je skrivena"</item>
- <item quantity="other" msgid="7388721375827338153">"Broj skrivenih obavijesti: %d"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Dodirnite za prikaz"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Ne ometaj"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Još %d"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Dodirnite opet za otvaranje"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Prijeđite prstom prema gore za otključavanje"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 7685477..7e064dd 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Legújabb alkalmazás"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Keresés"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Beviteli mód váltása gomb."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kompatibilitási zoom gomb."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kicsinyítsen a nagyobb képernyőhöz."</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Színinvertálás mód"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Kontrasztjavítás mód"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Színjavítás mód"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"LEGUTÓBBIAK"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Az alkalmazás adatai"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"keresés"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Lehet, hogy a\nhálózat felügyelt"</string>
<string name="description_target_search" msgid="3091587249776033139">"Keresés"</string>
<string name="description_direction_up" msgid="7169032478259485180">"A(z) <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> művelethez csúsztassa felfelé."</string>
<string name="description_direction_left" msgid="7207478719805562165">"A(z) <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> művelethez csúsztassa balra."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Értesítés elrejtve"</item>
- <item quantity="other" msgid="7388721375827338153">"%d értesítés elrejtve"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"A megtekintéshez érintse meg"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Ne zavarjanak"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d további"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Koppintson rá ismét a megnyitáshoz"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Húzza felfelé az ujját a feloldáshoz"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 7a8ab10..8c26a8a 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Վերջին ծրագրերը"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Որոնել"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Ֆոտոխցիկ"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Հեռախոս"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Միացնել մուտքագրման եղանակի կոճակը:"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Համատեղելիության խոշորացման կոճակը:"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Դիտափոխել փոքրից ավելի մեծ էկրան:"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index cdb0816..167b101 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Apl terbaru"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Telusuri"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Telepon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tombol beralih metode masukan."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tombol perbesar/perkecil kompatibilitas."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Perbesar dari layar kecil ke besar."</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Mode inversi warna"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Mode kontras yang disempurnakan"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode koreksi warna"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"TERBARU"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Info Aplikasi"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"telusuri"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Jaringan bisa\ndiawasi"</string>
<string name="description_target_search" msgid="3091587249776033139">"Telusuri"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Geser ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Geser ke kiri untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Pemberitahuan disembunyikan"</item>
- <item quantity="other" msgid="7388721375827338153">"%d pemberitahuan disembunyikan"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Sentuh untuk menampilkan"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Jangan ganggu"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d lainnya"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Ketuk lagi untuk membuka"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Gesek ke atas untuk membuka kunci"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 401dbce..6321870 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Applicazioni recenti"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Cerca"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Fotocamera"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefono"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Pulsante per cambiare metodo di immissione."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Pulsante zoom compatibilità."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom inferiore per schermo più grande."</string>
@@ -189,8 +188,8 @@
<string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Bloccato in verticale"</string>
<string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Bloccato in orizzontale"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Metodo di immissione"</string>
- <string name="quick_settings_location_label" msgid="5011327048748762257">"Geolocalizz."</string>
- <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Geolocalizz. non attiva"</string>
+ <string name="quick_settings_location_label" msgid="5011327048748762257">"Geolocalizzazione"</string>
+ <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Posizione non attiva"</string>
<string name="quick_settings_media_device_label" msgid="1302906836372603762">"Dispositivo multimediale"</string>
<string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Solo chiamate di emergenza"</string>
@@ -207,22 +206,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modalità inversione colori"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Modalità di contrasto avanzata"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modalità di correzione del colore"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"MESSAGGI RECENTI"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informazioni sull\'applicazione"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La rete potrebbe\nessere monitorata"</string>
<string name="description_target_search" msgid="3091587249776033139">"Ricerca"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Su per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"A sinistra per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Notifica nascosta"</item>
- <item quantity="other" msgid="7388721375827338153">"%d notifiche nascoste"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Tocca per visualizzare"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Non disturbare"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Altre %d"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Tocca ancora per aprire"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Scorri verso l\'alto per sbloccare"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 08ffc54..e1625076 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"אפליקציות אחרונות"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"חפש"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"מצלמה"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"טלפון"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"לחצן החלפת שיטת קלט."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"לחצן מרחק מתצוגה של תאימות."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"שנה מרחק מתצוגה של מסך קטן לגדול יותר."</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 2caa069..a9e7935 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"最近使ったアプリ"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"検索"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"カメラ"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"電話"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"入力方法の切り替えボタン。"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"互換ズームボタン。"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"小さい画面から大きい画面に拡大。"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 62e40d0..c56864b 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"ბოლოს გამოყენებული აპები"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"ძიება"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"კამერა"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"ტელეფონი"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"შეყვანის მეთოდის გადართვის ღილაკი."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"თავსებადი მასშტაბირების ღილაკი."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"შეცვალეთ პატარა ეკრანი უფრო დიდით."</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 35a6917..a5008b3 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -64,7 +64,7 @@
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"កំពុងរក្សាទុករូបថតអេក្រង់…"</string>
<string name="screenshot_saving_title" msgid="8242282144535555697">"កំពុងរក្សាទុករូបថតអេក្រង់..."</string>
<string name="screenshot_saving_text" msgid="2419718443411738818">"រូបថតអេក្រង់កំពុងត្រូវបានរក្សាទុក។"</string>
- <string name="screenshot_saved_title" msgid="6461865960961414961">"បានចាប់យករូបថតអេក្រង់។"</string>
+ <string name="screenshot_saved_title" msgid="6461865960961414961">"បានចាប់យករូបថតអេក្រង់។"</string>
<string name="screenshot_saved_text" msgid="1152839647677558815">"ប៉ះ ដើម្បីមើលរូបថតអេក្រង់របស់អ្នក។"</string>
<string name="screenshot_failed_title" msgid="705781116746922771">"មិនអាចចាប់យករូបថតអេក្រង់។"</string>
<string name="screenshot_failed_text" msgid="8134011269572415402">"មិនអាចរក្សាទុករូបថតអេក្រង់។ ឧបករណ៍ផ្ទុកអាចកំពុងប្រើ។"</string>
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"កម្មវិធីថ្មីៗ"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"ស្វែងរក"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"ម៉ាស៊ីនថត"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"ទូរស័ព្ទ"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ប្ដូរប៊ូតុងវិធីសាស្ត្របញ្ចូល។"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ប៊ូតុងពង្រីកត្រូវគ្នា។"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ពង្រីក/បង្រួមអេក្រង់ពីទៅធំ"</string>
@@ -141,7 +140,7 @@
<string name="accessibility_remove_notification" msgid="3603099514902182350">"សម្អាតការជូនដំណឹង។"</string>
<string name="accessibility_gps_enabled" msgid="3511469499240123019">"បានបើក GPS ។"</string>
<string name="accessibility_gps_acquiring" msgid="8959333351058967158">"ទទួល GPS ។"</string>
- <string name="accessibility_tty_enabled" msgid="4613200365379426561">"បានបើកម៉ាស៊ីនអង្គុលីលេខ"</string>
+ <string name="accessibility_tty_enabled" msgid="4613200365379426561">"បានបើកម៉ាស៊ីនអង្គុលីលេខ"</string>
<string name="accessibility_ringer_vibrate" msgid="666585363364155055">"កម្មវិធីរោទ៍ញ័រ។"</string>
<string name="accessibility_ringer_silent" msgid="9061243307939135383">"កម្មវិធីរោទ៍ស្ងាត់។"</string>
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> បដិសេធ។"</string>
@@ -188,7 +187,7 @@
<string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"ចាក់សោបញ្ឈរ"</string>
<string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"ចាក់សោផ្ដេក"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"វិធីសាស្ត្របញ្ចូល"</string>
- <string name="quick_settings_location_label" msgid="5011327048748762257">"ទីតាំង"</string>
+ <string name="quick_settings_location_label" msgid="5011327048748762257">"ទីតាំង"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"ទីតាំងបានបិទ"</string>
<string name="quick_settings_media_device_label" msgid="1302906836372603762">"ឧបករណ៍មេឌៀ"</string>
<string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
@@ -209,7 +208,7 @@
<string name="recents_empty_message" msgid="2269156590813544104">"ថ្មីៗ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ព័ត៌មានកម្មវិធី"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ស្វែងរក"</string>
- <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"បណ្ដាញអាច\nត្រូវបានត្រួតពិនិត្យ"</string>
+ <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"បណ្ដាញអាច\nត្រូវបានត្រួតពិនិត្យ"</string>
<string name="description_target_search" msgid="3091587249776033139">"ស្វែងរក"</string>
<string name="description_direction_up" msgid="7169032478259485180">"រុញឡើងលើដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
<string name="description_direction_left" msgid="7207478719805562165">"រុញទៅឆ្វេងដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index d7cd13b..bd7a257 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"최근에 사용한 앱"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"검색"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"카메라"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"전화"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"입력 방법 버튼을 전환합니다."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"호환성 확대/축소 버튼입니다."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"작은 화면을 큰 화면으로 확대합니다."</string>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index 7223773..5755029 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -25,7 +25,7 @@
<integer name="status_bar_recents_bg_gradient_degrees">90</integer>
<!-- The number of columns in the QuickSettings -->
- <integer name="quick_settings_num_columns">6</integer>
+ <integer name="quick_settings_num_columns">4</integer>
<!-- The maximum number of rows in the QuickSettings -->
<integer name="quick_settings_max_rows">2</integer>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 991fb66..59cf520 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"ແອັບຯຫຼ້າສຸດ"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"ຊອກຫາ"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"ກ້ອງ"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"ໂທລະສັບ"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ປຸ່ມສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ປຸ່ມຊູມທີ່ໃຊ້ຮ່ວມກັນໄດ້."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ຊູມຈໍນ້ອຍໄປເປັນຈໍຂະຫນາດໃຫຍ່."</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"ໂໝດສະລັບສີ"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"ໂໝດຄວາມຕ່າງແສງ"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"ໂໝດການແກ້ໄຂສີ"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"ບໍ່ດົນມານີ້"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"ຂໍ້ມູນແອັບພລິເຄຊັນ"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"ຊອກຫາ"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ເຄືອຄ່າຍອາດ\nຖືກຕິດຕາມ"</string>
<string name="description_target_search" msgid="3091587249776033139">"ຊອກຫາ"</string>
<string name="description_direction_up" msgid="7169032478259485180">"ເລື່ອນຂຶ້ນເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"ເລື່ອນໄປທາງຊ້າຍເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"ເຊື່ອງການແຈ້ງເຕືອນແລ້ວ"</item>
- <item quantity="other" msgid="7388721375827338153">"ເຊື່ອງ %d ການແຈ້ງເຕືອນແລ້ວ"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"ແຕະເພື່ອສະແດງ"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"ຫ້າມລົບກວນ"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d ເພີ່ມເຕີມ"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"ແຕະອີກຄັ້ງເພື່ອເປີດ"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"ເລື່ອນຂຶ້ນເພື່ອປົດລັອກ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 87087b4..3fe74b3 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -69,7 +69,7 @@
<string name="screenshot_failed_title" msgid="705781116746922771">"Nepavyko užfiksuoti ekrano kopijos."</string>
<string name="screenshot_failed_text" msgid="8134011269572415402">"Nepavyko išsaugoti ekrano kopijos. Gali būti naudojama atmintis."</string>
<string name="usb_preference_title" msgid="6551050377388882787">"USB failo perdavimo parinktys"</string>
- <string name="use_mtp_button_title" msgid="4333504413563023626">"Įmontuoti kaip medijos leistuvę (MTP)"</string>
+ <string name="use_mtp_button_title" msgid="4333504413563023626">"Įmontuoti kaip medijos grotuvą (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"Įmontuoti kaip fotoaparatą (PTP)"</string>
<string name="installer_cd_button_title" msgid="2312667578562201583">"Įdiegti „Mac“ skirtą „Android“ perkėl. priem. pr."</string>
<string name="accessibility_back" msgid="567011538994429120">"Atgal"</string>
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Naujausios programos"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Ieškoti"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparatas"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefonas"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Perjungti įvesties metodo mygtuką."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Suderinamumo priartinimo mygtukas."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Padidinti ekraną."</string>
@@ -181,7 +180,7 @@
<string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"„Bluetooth“ (<xliff:g id="NUMBER">%d</xliff:g> įreng.)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"„Bluetooth“ išjungta"</string>
- <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Skaistis"</string>
+ <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Šviesumas"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Automatiškai sukti"</string>
<string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Sukimas užrakintas"</string>
<string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Užrakinta stačia padėtis"</string>
@@ -200,27 +199,13 @@
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tinklo nėra"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"„Wi-Fi“ išjungta"</string>
<string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Perduoti ekraną"</string>
- <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Skaistis"</string>
+ <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Šviesumas"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATINIS"</string>
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Spalvų inversijos režimas"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Patobulinto kontrasto režimas"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Spalvų taisymo režimas"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"PASTARIEJI"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Programos informacija"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"paieška"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tinklas gali\nbūti stebimas"</string>
<string name="description_target_search" msgid="3091587249776033139">"Paieška"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Slyskite aukštyn link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Slyskite į kairę link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Pranešimas paslėptas"</item>
- <item quantity="other" msgid="7388721375827338153">"Paslėpta pranešimų: %d"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Palieskite, kad būtų rodoma"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Netrukdyti"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Dar %d"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Palieskite dar kartą, kad atidarytumėte"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Perbraukite aukštyn, kad atrakintumėte"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 04571e7..4230b2e 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Nesen izmantotās lietotnes"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Meklēt"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Tālruņa numurs"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ievades metodes maiņas poga."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Saderības tālummaiņas poga."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Veikt tālummaiņu no mazāka ekrāna uz lielāku."</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Krāsu inversijas režīms"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Uzlabota kontrasta režīms"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Krāsu korekcijas režīms"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"JAUNĀKIE"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informācija par lietojumprogrammu"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"Meklēt"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tīkls var\ntikt uzraudzīts"</string>
<string name="description_target_search" msgid="3091587249776033139">"Meklēt"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Velciet uz augšu, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Velciet pa kreisi, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Paziņojums paslēpts"</item>
- <item quantity="other" msgid="7388721375827338153">"%d paziņojumi paslēpti"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Pieskarieties, lai rādītu"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Netraucēt"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"vēl %d"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Pieskarieties vēlreiz, lai atvērtu"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Velciet uz augšu, lai atbloķētu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 3e7b660..4669d99 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Сүүлийн апп"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Хайх"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Камер"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Утас"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Оруулах аргыг сэлгэх товч."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Тохиромжтой өсгөх товч."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Жижгээс том дэлгэцрүү өсгөх."</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index af50786..60e5527 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Aplikasi terbaharu"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Cari"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Butang tukar kaedah input."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Butang zum keserasian."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Skrin zum lebih kecil kepada lebih besar."</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 9fa68b9..12deaef 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Nylige apper"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Søk"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefonnummer"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bytt knapp for inndatametode."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Zoomknapp for kompatibilitet."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom fra mindre til større skjerm."</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modus for fargeinvertering"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Forbedret kontrastmodus"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modus for fargekorrigering"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"NYLIGE"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformasjon"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"Søk"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nettverket kan\nvære overvåket"</string>
<string name="description_target_search" msgid="3091587249776033139">"Søk"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Dra opp for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Dra til venstre for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Varselet er skjult"</item>
- <item quantity="other" msgid="7388721375827338153">"%d varsler er skjult"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Trykk for å vise"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Ikke forstyrr"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d til"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Trykk på nytt for å åpne"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Sveip oppover for å låse opp"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 8cf16bf..59c64b5 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Recente apps"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Zoeken"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefoon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knop voor wijzigen invoermethode."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knop voor compatibiliteitszoom."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kleiner scherm uitzoomen naar groter scherm."</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modus voor kleurinversie"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Modus voor verbeterd contrast"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modus voor kleurcorrectie"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"RECENTE"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-informatie"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"zoeken"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk kan\nworden gecontroleerd"</string>
<string name="description_target_search" msgid="3091587249776033139">"Zoeken"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Veeg omhoog voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Veeg naar links voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Melding verborgen"</item>
- <item quantity="other" msgid="7388721375827338153">"%d meldingen verborgen"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Raak aan om weer te geven"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Niet storen"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Nog %d"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Tik nogmaals om te openen"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Veeg omhoog om te ontgrendelen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index e51341d..00bea9c 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Ostatnie aplikacje"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Szukaj"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Aparat"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Przycisk przełączania metody wprowadzania."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Przycisk powiększenia na potrzeby zgodności."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Powiększa mniejszy ekran do większego."</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 11843b6..fc25ea8 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Aplicações recentes"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Pesquisar"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Câmara"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Telemóvel"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alternar botão de método de introdução."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão zoom de compatibilidade."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom menor para ecrã maior."</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modo de inversão de cor"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Modo de contraste melhorado"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de correção de cor"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"RECENTES"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações da aplicação"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode ser\nmonitorizada"</string>
<string name="description_target_search" msgid="3091587249776033139">"Pesquisar"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Deslize para cima para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Deslize para a esquerda para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Notificação oculta"</item>
- <item quantity="other" msgid="7388721375827338153">"%d notificações ocultas"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Toque para mostrar"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Não incomodar"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Mais %d"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Toque novamente para abrir"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Deslizar rapidamente com o dedo para cima para desbloquear"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 162d763..2337a7d 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Aplicativos recentes"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Pesquisar"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Câmera"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefone"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alterar botão do método de entrada."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão de zoom da compatibilidade."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aumentar a tela com zoom."</string>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 9f82651..adf54bc 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -126,8 +126,6 @@
<skip />
<!-- no translation found for accessibility_camera_button (8064671582820358152) -->
<skip />
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
<!-- no translation found for accessibility_ime_switch_button (5032926134740456424) -->
<skip />
<!-- no translation found for accessibility_compatibility_zoom_button (8461115318742350699) -->
@@ -380,12 +378,6 @@
<skip />
<!-- no translation found for quick_settings_color_space_label (853443689745584770) -->
<skip />
- <!-- no translation found for recents_empty_message (2269156590813544104) -->
- <skip />
- <!-- no translation found for recents_app_info_button_label (2890317189376000030) -->
- <skip />
- <!-- no translation found for recents_search_bar_label (8074997400187836677) -->
- <skip />
<!-- no translation found for ssl_ca_cert_warning (9005954106902053641) -->
<skip />
<!-- no translation found for description_target_search (3091587249776033139) -->
@@ -394,15 +386,4 @@
<skip />
<!-- no translation found for description_direction_left (7207478719805562165) -->
<skip />
- <!-- no translation found for zen_mode_notification_title:one (7809876956258040354) -->
- <!-- no translation found for zen_mode_notification_title:other (7388721375827338153) -->
- <!-- no translation found for zen_mode_notification_text (8336623711388065713) -->
- <skip />
- <!-- no translation found for zen_mode_title (8793432092004749188) -->
- <skip />
- <!-- no translation found for keyguard_more_overflow_text:other (9180696159506883684) -->
- <!-- no translation found for notification_tap_again (7590196980943943842) -->
- <skip />
- <!-- no translation found for keyguard_unlock (8043466894212841998) -->
- <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 75ba35b..4f2c471 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Aplicaţii recente"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Căutați"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Cameră foto"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Buton pentru comutarea metodei de introducere."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Buton zoom pentru compatibilitate."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Faceţi zoom de la o imagine mai mică la una mai mare."</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 6bdc6f4..837e98e 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Недавние приложения"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Поиск"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Телефон."</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка переключения способа ввода."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабирования (режим совместимости)"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Уменьшение изображения для увеличения свободного места на экране."</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 12c90ec..ae70ed6 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Nové aplikácie"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Hľadať"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparát"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefón"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačidlo prepnutia metódy vstupu."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačidlo úpravy veľkosti z dôvodu kompatibility."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zväčšiť menší obrázok na väčšiu obrazovku."</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 48d7727..a5b3244 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Nedavni programi"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Iskanje"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparat"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za preklop načina vnosa."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Gumb povečave za združljivost."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Povečava manjšega na večji zaslon."</string>
@@ -184,7 +183,7 @@
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Svetlost"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Samodejno vrtenje"</string>
<string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Zaklenjeno vrtenje"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Zaklenjeno na pokončno postavitev"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Zaklenjeno na navpično postavitev"</string>
<string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Zaklenjeno na ležečo postavitev"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Način vnosa"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Lokacija"</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Način inverzije barv"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Način izboljšanega kontrasta"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Način popravljanja barv"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"NEDAVNI"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Podatki o aplikaciji"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"iskanje"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Omrežje je\nlahko spremljano"</string>
<string name="description_target_search" msgid="3091587249776033139">"Iskanje"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Povlecite navzgor za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Povlecite v levo za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Obvestilo je skrito"</item>
- <item quantity="other" msgid="7388721375827338153">"Skritih je toliko obvestil: %d"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Dotaknite se za prikaz"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Ne moti"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"še %d"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Znova se dotaknite, da odprete"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Povlecite, da odklenete"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index dba27a1..0bdccee 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Недавне апликације"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Претражите"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Телефон"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Дугме Промени метод уноса."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Дугме Зум компатибилности."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Зумирање са мањег на већи екран."</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Режим инверзије боје"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Режим унапређеног контраста"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Режим корекције боје"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"НАЈНОВИЈЕ"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информације о апликацији"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"претражи"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежа се можда\nнадгледа"</string>
<string name="description_target_search" msgid="3091587249776033139">"Претрага"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Превуците нагоре за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Превуците улево за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Обавештење је сакривено"</item>
- <item quantity="other" msgid="7388721375827338153">"Сакривена обавештења: %d"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Додирните за приказ"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Не узнемиравај"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Још %d"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Додирните поново да бисте отворили"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Превуците нагоре да бисте откључали"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 0d58ed3..efe7fcb 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Senaste apparna"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Sök"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Mobil"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knapp för byte av inmatningsmetod."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knapp för kompatibilitetszoom."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zooma mindre skärm till större."</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Färginverteringsläge"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Kontrastförbättringsläge"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Färgkorrigeringsläge"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"NYA"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformation"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"sök"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nätverket kan\nvara övervakat"</string>
<string name="description_target_search" msgid="3091587249776033139">"Sök"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Dra uppåt för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Dra åt vänster för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Aviseringen har dolts"</item>
- <item quantity="other" msgid="7388721375827338153">"%d aviseringar har dolts"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Tryck här om du vill visa aviseringar"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Stör ej"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d till"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Tryck igen för att öppna"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Dra uppåt om du vill låsa upp"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index b626f78..2713cf9 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -76,8 +76,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Programu za hivi karibuni"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Tafuta"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Simu"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Swichi kitufe cha mbinu ingizi."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kichupo cha kukuza kwa utangamanifu"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kuza kidogo kwa skrini kubwa."</string>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index fe2224e..6dea81f 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -21,7 +21,7 @@
for different hardware and product builds. -->
<resources>
<!-- The number of columns in the QuickSettings -->
- <integer name="quick_settings_num_columns">3</integer>
+ <integer name="quick_settings_num_columns">4</integer>
<!-- The maximum number of rows in the QuickSettings -->
<integer name="quick_settings_max_rows">4</integer>
diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml
index b7becac..d4a99866 100644
--- a/packages/SystemUI/res/values-sw600dp/styles.xml
+++ b/packages/SystemUI/res/values-sw600dp/styles.xml
@@ -18,4 +18,15 @@
<style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer">
<item name="android:layout_width">480dp</item>
</style>
+
+ <style name="NotificationsQuickSettings">
+ <item name="android:layout_width">@dimen/notification_panel_width</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:layout_gravity">top|center_horizontal</item>
+ </style>
+
+ <style name="StatusBarHeader">
+ <item name="android:layout_width">@dimen/notification_panel_width</item>
+ <item name="android:layout_gravity">center_horizontal</item>
+ </style>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 6cb4a48..4dc3d22 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"แอปพลิเคชันล่าสุด"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"ค้นหา"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"กล้องถ่ายรูป"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"โทรศัพท์"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ปุ่มสลับวิธีการป้อนข้อมูล"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ปุ่มซูมที่ใช้งานร่วมกันได้"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ซูมหน้าจอให้มีขนาดใหญ่ขึ้น"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 17e720e..e50f723 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Kamakailang apps"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Hanapin"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telepono"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ilipat ang button na pamamaraan ng pag-input."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Button ng zoom ng pagiging tugma."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Mag-zoom nang mas maliit sa mas malaking screen."</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 1bf033f5..9100055 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Son uygulamalar"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Ara"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Giriş yöntemini değiştirme düğmesi."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Uyumluluk zum düğmesi."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Daha büyük ekrana daha küçük yakınlaştır."</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index a5284ae..3a474a4 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Останні програми"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Пошук"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Номер телефону"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка перемикання методу введення."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабування сумісності."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Збільшення екрана."</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Режим інверсії кольорів"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Режим посиленого контрасту"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Режим коригування кольору"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"ОСТАННІ"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Інформація про додаток"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мережа може\nвідстежуватися"</string>
<string name="description_target_search" msgid="3091587249776033139">"Пошук"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Проведіть пальцем угору, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Проведіть пальцем ліворуч, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Сповіщення сховано"</item>
- <item quantity="other" msgid="7388721375827338153">"Сховано сповіщень: %d"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Торкніться, щоб показати"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Не турбувати"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Ще %d"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Торкніться знову, щоб відкрити"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Проведіть пальцем угору, щоб розблокувати"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 8df2449..a4aadb3 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Ứng dụng gần đây"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Tìm kiếm"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Máy ảnh"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Điện thoại"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Nút chuyển phương thức nhập."</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Nút thu phóng khả năng tương thích."</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Thu phóng màn hình lớn hơn hoặc nhỏ hơn."</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 8643ca8..a5ae2b7 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"最近运行的应用"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"搜索"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"相机"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"电话"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"输入法切换按钮。"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"兼容性缩放按钮。"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"将小屏幕的图片放大在较大屏幕上显示。"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 9d93094..d229347 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"最近使用的應用程式"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"搜尋"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"相機"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"電話"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>
@@ -207,22 +206,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"色彩反轉模式"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"增強對比模式"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"色彩校準模式"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"近期"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資料"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網絡可能會\n受到監控"</string>
<string name="description_target_search" msgid="3091587249776033139">"搜尋"</string>
<string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
<string name="description_direction_left" msgid="7207478719805562165">"向左滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"已隱藏通知"</item>
- <item quantity="other" msgid="7388721375827338153">"已隱藏 %d 則通知"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"輕觸即可顯示"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"請勿騷擾"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"還有 %d 個"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"再次輕按即可開啟"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"向上快速滑動即可解鎖"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 07b7841..1e3f455 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -78,8 +78,7 @@
<string name="accessibility_recent" msgid="8571350598987952883">"最近使用的應用程式"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"搜尋"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"相機"</string>
- <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
- <skip />
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"電話"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 48a1ace..d676b5c 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -78,7 +78,6 @@
<string name="accessibility_recent" msgid="8571350598987952883">"Izinhlelo zokusebenza zakamuva"</string>
<string name="accessibility_search_light" msgid="1103867596330271848">"Sesha"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"Ikhamela"</string>
- <string name="accessibility_phone_button" msgid="6738112589538563574">"Ifoni"</string>
<string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Vula indlela yokungena yenkinobho"</string>
<string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Inkinobho evumelekile yokusondeza"</string>
<string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Sondeza kancane esikrinini esikhudlwana"</string>
@@ -205,22 +204,8 @@
<string name="quick_settings_inversion_label" msgid="1666358784283020762">"Imodi yokuguqulwa kombala"</string>
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Imodi ethuthukisiwe yokugqama"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Imodi yokulungisa umbala"</string>
- <string name="recents_empty_message" msgid="2269156590813544104">"OKWAKAMUVA"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Ulwazi lohlelo lokusebenza"</string>
- <string name="recents_search_bar_label" msgid="8074997400187836677">"sesha"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Kungenzeka inethiwekhi\niqashiwe"</string>
<string name="description_target_search" msgid="3091587249776033139">"Sesha"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Shelelisela ngenhla ku-<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="7207478719805562165">"Shelelisela ngakwesokunxele ku-<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
- <plurals name="zen_mode_notification_title">
- <item quantity="one" msgid="7809876956258040354">"Isaziso sifihliwe"</item>
- <item quantity="other" msgid="7388721375827338153">"%d izaziso zifihliwe"</item>
- </plurals>
- <string name="zen_mode_notification_text" msgid="8336623711388065713">"Thinta ukuze ubonise"</string>
- <string name="zen_mode_title" msgid="8793432092004749188">"Ungaphazamisi"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d okuningi"</item>
- </plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Thepha futhi ukuze uvule"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Swayiphela phezulu ukuze uvule"</string>
</resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index f5674d2..8fd1206 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -51,6 +51,13 @@
<enum name="end" value="1" />
</attr>
</declare-styleable>
+ <declare-styleable name="Clock">
+ <attr name="amPmStyle" format="enum">
+ <enum name="normal" value="0" />
+ <enum name="small" value="1" />
+ <enum name="gone" value="2" />
+ </attr>
+ </declare-styleable>
<attr name="orientation">
<enum name="horizontal" value="0" />
<enum name="vertical" value="1" />
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 9281265..7de1bd0 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -30,13 +30,20 @@
<drawable name="recents_callout_line">#99ffffff</drawable>
<drawable name="notification_item_background_legacy_color">#ffaaaaaa</drawable>
<drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
- <drawable name="notification_header_bg">#FF000000</drawable>
<color name="notification_panel_scrim_color">#A0000000</color>
<color name="notification_panel_scrim_color_keyguard">#80000000</color>
<color name="batterymeter_frame_color">#66FFFFFF</color><!-- 40% white -->
<color name="batterymeter_charge_color">#FFFFFFFF</color>
<color name="batterymeter_bolt_color">#FFFFFFFF</color>
<color name="qs_batterymeter_frame_color">#FF404040</color>
+ <color name="system_primary_color">#ff263238</color>
+ <color name="system_secondary_color">#ff384248</color>
+ <color name="system_accent_color">#ff7fcac3</color>
+ <color name="system_error_color">#fff0592b</color>
+ <color name="quick_settings_tile_icon_enabled">#ffffffff</color>
+ <color name="quick_settings_tile_icon_disabled">#ffcccccc</color>
+ <color name="quick_settings_tile_divider">#ff888888</color>
+ <color name="quick_settings_tile_text">#FFFFFFFF</color>
<color name="status_bar_clock_color">#FFFFFFFF</color>
<drawable name="notification_item_background_color">#ff111111</drawable>
<drawable name="notification_item_background_color_pressed">#ff454545</drawable>
@@ -53,10 +60,18 @@
<!-- The default recents task bar background color. -->
<color name="recents_task_bar_default_background_color">#e6444444</color>
<!-- The default recents task bar text color. -->
- <color name="recents_task_bar_default_text_color">#ffffffff</color>
+ <color name="recents_task_bar_default_text_color">#ffeeeeee</color>
<!-- The recents task bar light text color to be drawn on top of dark backgrounds. -->
- <color name="recents_task_bar_light_text_color">#ffffffff</color>
+ <color name="recents_task_bar_light_text_color">#ffeeeeee</color>
<!-- The recents task bar dark text color to be drawn on top of light backgrounds. -->
<color name="recents_task_bar_dark_text_color">#ff222222</color>
+ <!-- The recents task bar light dismiss icon color to be drawn on top of dark backgrounds. -->
+ <color name="recents_task_bar_light_dismiss_color">#ffeeeeee</color>
+ <!-- The recents task bar dark dismiss icon color to be drawn on top of light backgrounds. -->
+ <color name="recents_task_bar_dark_dismiss_color">#ff333333</color>
+ <!-- Our quantum color palette (deep teal) -->
+ <color name="primary_color">#ff7fcac3</color>
+ <color name="background_color_1">#ff384248</color>
+ <color name="background_color_1_press">#ff54656e</color>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c0376f0..21eb41c 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -119,7 +119,7 @@
<!-- The animation duration for animating in the info pane. -->
<integer name="recents_animate_task_view_info_pane_duration">150</integer>
<!-- The animation duration for animating the removal of a task view. -->
- <integer name="recents_animate_task_view_remove_duration">150</integer>
+ <integer name="recents_animate_task_view_remove_duration">250</integer>
<!-- The minimum alpha for the dim applied to cards that go deeper into the stack. -->
<integer name="recents_max_task_stack_view_dim">96</integer>
<!-- Transposes the search bar layout in landscape -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c6fdc16..79612e0 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -153,11 +153,14 @@
<dimen name="close_handle_underlap">32dp</dimen>
<!-- Height of the status bar header bar -->
- <dimen name="status_bar_header_height">48dp</dimen>
+ <dimen name="status_bar_header_height">56dp</dimen>
<!-- Height of the status bar header bar when expanded -->
<dimen name="status_bar_header_height_expanded">144dp</dimen>
+ <!-- Height of the status bar header bar when on Keyguard -->
+ <dimen name="status_bar_header_height_keyguard">40dp</dimen>
+
<!-- Gravity for the notification panel -->
<!-- 0x37 = fill_horizontal|top -->
<integer name="notification_panel_layout_gravity">0x37</integer>
@@ -196,9 +199,6 @@
<!-- Quick Settings CA Cert Warning tile geometry: gap between icon and text -->
<dimen name="qs_cawarn_tile_margin_below_icon">3dp</dimen>
- <!-- The width of the notification panel window: match_parent below sw600dp -->
- <dimen name="notification_panel_width">-1dp</dimen>
-
<!-- used by DessertCase -->
<dimen name="dessert_case_cell_size">192dp</dimen>
@@ -224,7 +224,7 @@
<dimen name="recents_task_view_z_increment">5dp</dimen>
<!-- The amount to translate when animating the removal of a task. -->
- <dimen name="recents_task_view_remove_anim_translation_x">75dp</dimen>
+ <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen>
<!-- The amount of space a user has to scroll to dismiss any info panes. -->
<dimen name="recents_task_stack_scroll_dismiss_info_pane_distance">50dp</dimen>
@@ -243,7 +243,10 @@
<dimen name="top_stack_peek_amount">12dp</dimen>
<!-- Space reserved for the cards behind the top card in the bottom stack -->
- <dimen name="bottom_stack_peek_amount">18dp</dimen>
+ <dimen name="bottom_stack_peek_amount">12dp</dimen>
+
+ <!-- The height of the area before the bottom stack in which the notifications slow down -->
+ <dimen name="bottom_stack_slow_down_length">12dp</dimen>
<!-- The side padding of the notifications-->
<dimen name="notification_side_padding">8dp</dimen>
@@ -251,8 +254,11 @@
<!-- Z distance between notifications if they are in the stack -->
<dimen name="z_distance_between_notifications">2dp</dimen>
+ <!-- The padding between the individual notification cards when dimmed. -->
+ <dimen name="notification_padding_dimmed">0dp</dimen>
+
<!-- The padding between the individual notification cards. -->
- <dimen name="notification_padding">3dp</dimen>
+ <dimen name="notification_padding">4dp</dimen>
<!-- The total height of the stack in its collapsed size (i.e. when quick settings is open) -->
<dimen name="collapsed_stack_height">94dp</dimen>
@@ -265,6 +271,10 @@
<dimen name="quick_settings_tmp_scrim_stroke_width">8dp</dimen>
<dimen name="quick_settings_tmp_scrim_text_size">30dp</dimen>
+ <dimen name="quick_settings_panel_padding">16dp</dimen>
+ <dimen name="quick_settings_tile_icon_outline">2dp</dimen>
+ <dimen name="quick_settings_tile_text_size">12sp</dimen>
+ <dimen name="quick_settings_tile_divider_height">1dp</dimen>
<dimen name="notifications_top_padding">8dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 3f0a60f..a50a0ac 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -503,11 +503,15 @@
<!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] -->
<string name="quick_settings_brightness_dialog_auto_brightness_label">AUTO</string>
<!-- QuickSettings: Label for the toggle that controls whether display inversion is enabled. [CHAR LIMIT=NONE] -->
- <string name="quick_settings_inversion_label">Color inversion mode</string>
- <!-- QuickSettings: Label for the toggle that controls whether display contrast enhancement is enabled. [CHAR LIMIT=NONE] -->
- <string name="quick_settings_contrast_label">Enhanced contrast mode</string>
+ <string name="quick_settings_inversion_label">Invert colors</string>
<!-- QuickSettings: Label for the toggle that controls whether display color correction is enabled. [CHAR LIMIT=NONE] -->
<string name="quick_settings_color_space_label">Color correction mode</string>
+ <!-- QuickSettings: Control panel: Label for button that navigates to settings. [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_more_settings">More settings</string>
+ <!-- QuickSettings: Tethering. [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_tethering_label">Tethering</string>
+ <!-- QuickSettings: Hotspot. [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_hotspot_label">Hotspot</string>
<!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
<string name="recents_empty_message">RECENTS</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 8ab646d..1273e74 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -69,8 +69,7 @@
<style name="TextAppearance.StatusBar.Expanded" parent="@*android:style/TextAppearance.StatusBar" />
<style name="TextAppearance.StatusBar.Expanded.Clock">
- <item name="android:textSize">32dp</item>
- <item name="android:fontFamily">sans-serif-light</item>
+ <item name="android:textSize">18dp</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">#ffffff</item>
</style>
@@ -78,8 +77,7 @@
<style name="TextAppearance.StatusBar.Expanded.Date">
<item name="android:textSize">12dp</item>
<item name="android:textStyle">normal</item>
- <item name="android:textColor">#cccccc</item>
- <item name="android:textAllCaps">true</item>
+ <item name="android:textColor">#afb3b6</item>
</style>
<style name="TextAppearance.StatusBar.Expanded.Network" parent="@style/TextAppearance.StatusBar.Expanded.Date">
@@ -138,6 +136,7 @@
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:padding">16dp</item>
+ <item name="android:layout_alignParentBottom">true</item>
</style>
<style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer" />
@@ -169,6 +168,28 @@
<item name="android:textSize">14dp</item>
</style>
- <style name="systemui_theme" parent="@android:style/Theme.DeviceDefault" />
+ <style name="systemui_theme" parent="@android:style/Theme.DeviceDefault">
+ <item name="android:colorPrimary">@color/primary_color</item>
+ </style>
+ <style name="NotificationsQuickSettings">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">match_parent</item>
+ </style>
+
+ <style name="StatusBarHeader">
+ <item name="android:layout_width">match_parent</item>
+ </style>
+
+ <style name="QSWhiteTheme" parent="@android:style/Theme.DeviceDefault">
+ <item name="android:colorControlNormal">#ffffffff</item>
+ <item name="android:colorControlActivated">#ffffffff</item>
+ </style>
+
+ <style name="QSAccentTheme" parent="@android:style/Theme.DeviceDefault">
+ <item name="android:colorControlNormal">@color/system_accent_color</item>
+ <item name="android:colorControlActivated">@color/system_accent_color</item>
+ </style>
+
+ <style name="QSBorderless" parent="@android:style/Widget.Quantum.Button.Borderless" />
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index f812e8c..e73e904 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -807,7 +807,6 @@
*/
public void setOccluded(boolean isOccluded) {
if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded);
- mUpdateMonitor.sendKeyguardVisibilityChanged(!isOccluded);
mHandler.removeMessages(SET_OCCLUDED);
Message msg = mHandler.obtainMessage(SET_OCCLUDED, (isOccluded ? 1 : 0), 0);
mHandler.sendMessage(msg);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/CircularClipper.java b/packages/SystemUI/src/com/android/systemui/qs/CircularClipper.java
new file mode 100644
index 0000000..16ee3b0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/CircularClipper.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.view.View;
+
+/** Helper for view-level circular clip animations. **/
+public class CircularClipper {
+
+ private final View mTarget;
+
+ private ValueAnimator mAnimator;
+
+ public CircularClipper(View target) {
+ mTarget = target;
+ }
+
+ public void animateCircularClip(int x, int y, boolean in, AnimatorListener listener) {
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
+ final int w = mTarget.getWidth() - x;
+ final int h = mTarget.getHeight() - y;
+ int r = (int) Math.ceil(Math.sqrt(x * x + y * y));
+ r = (int) Math.max(r, Math.ceil(Math.sqrt(w * w + y * y)));
+ r = (int) Math.max(r, Math.ceil(Math.sqrt(w * w + h * h)));
+ r = (int) Math.max(r, Math.ceil(Math.sqrt(x * x + h * h)));
+
+ mAnimator = mTarget.createRevealAnimator(x, y, 0, r);
+ mAnimator.removeAllListeners();
+ if (listener != null) {
+ mAnimator.addListener(listener);
+ }
+ if (in) {
+ mAnimator.addListener(mVisibleOnStart);
+ mAnimator.start();
+ } else {
+ mAnimator.addListener(mGoneOnEnd);
+ mAnimator.reverse();
+ }
+ }
+
+ private final AnimatorListenerAdapter mVisibleOnStart = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mTarget.setVisibility(View.VISIBLE);
+ }
+ };
+
+ private final AnimatorListenerAdapter mGoneOnEnd = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTarget.setVisibility(View.GONE);
+ };
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java b/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java
new file mode 100644
index 0000000..05c8ee3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
+
+/** Canvas that forwards calls to another canvas. Can be subclassed to transform drawing calls.
+ * Temporary solution to runtime modification of a single drawable shape into two
+ * enabled & disabled versions. See QSImageView. **/
+public class FilterCanvas extends Canvas {
+ private final Canvas mCanvas;
+
+ public FilterCanvas(Canvas c) {
+ mCanvas = c;
+ }
+
+ @Override
+ public void drawPath(Path path, Paint paint) {
+ mCanvas.drawPath(path, paint);
+ }
+
+ @Override
+ public int getSaveCount() {
+ return mCanvas.getSaveCount();
+ }
+
+ @Override
+ public int save() {
+ return mCanvas.save();
+ }
+
+ @Override
+ public void translate(float dx, float dy) {
+ mCanvas.translate(dx, dy);
+ }
+
+ @Override
+ public boolean clipRect(int left, int top, int right, int bottom) {
+ return mCanvas.clipRect(left, top, right, bottom);
+ }
+
+ @Override
+ public boolean clipRect(Rect rect) {
+ return mCanvas.clipRect(rect);
+ }
+
+ @Override
+ public void concat(Matrix matrix) {
+ mCanvas.concat(matrix);
+ }
+
+ @Override
+ public void restoreToCount(int saveCount) {
+ mCanvas.restoreToCount(saveCount);
+ }
+
+ @Override
+ public void drawRect(Rect r, Paint paint) {
+ mCanvas.drawRect(r, paint);
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java b/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java
new file mode 100644
index 0000000..1e15b9f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings.Global;
+
+import com.android.systemui.statusbar.policy.Disposable;
+
+/** Helper for managing a global setting. **/
+public abstract class GlobalSetting extends ContentObserver implements Disposable {
+ private final Context mContext;
+ private final String mSettingName;
+
+ protected abstract void handleValueChanged(int value);
+
+ public GlobalSetting(Context context, Handler handler, String settingName) {
+ super(handler);
+ mContext = context;
+ mSettingName = settingName;
+ mContext.getContentResolver().registerContentObserver(
+ Global.getUriFor(mSettingName), false, this);
+ }
+
+ public int getValue() {
+ return Global.getInt(mContext.getContentResolver(), mSettingName, 0);
+ }
+
+ public void setValue(int value) {
+ Global.putInt(mContext.getContentResolver(), mSettingName, value);
+ }
+
+ @Override
+ public void dispose() {
+ mContext.getContentResolver().unregisterContentObserver(this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ handleValueChanged(getValue());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java b/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java
new file mode 100644
index 0000000..ed67560
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Path;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.VectorDrawable;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+
+/** ImageView that performs runtime modification of vector drawables (using FilterCanvas). **/
+public class QSImageView extends ImageView {
+
+ private final int mOutlineWidth;
+ private final int mColorEnabled;
+ private final int mColorDisabled;
+ private FilterCanvas mFilterCanvas;
+ private Canvas mCanvas;
+ private boolean mEnabledVersion = true;
+ private boolean mFilter;
+
+ public QSImageView(Context context) {
+ this(context, null);
+ }
+
+ public QSImageView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ final Resources res = context.getResources();
+ mOutlineWidth = res.getDimensionPixelSize(R.dimen.quick_settings_tile_icon_outline);
+ mColorEnabled = res.getColor(R.color.quick_settings_tile_icon_enabled);
+ mColorDisabled = res.getColor(R.color.quick_settings_tile_icon_disabled);
+ }
+
+ public void setEnabledVersion(boolean enabledVersion) {
+ mEnabledVersion = enabledVersion;
+ invalidate();
+ }
+
+ @Override
+ public void setImageDrawable(Drawable drawable) {
+ mFilter = drawable instanceof VectorDrawable;
+ super.setImageDrawable(drawable);
+ }
+
+ @Override
+ public void setImageResource(int resId) {
+ setImageDrawable(mContext.getDrawable(resId));
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mFilter) {
+ if (canvas != mCanvas) {
+ mCanvas = canvas;
+ mFilterCanvas = new QSFilterCanvas(canvas);
+ }
+ super.draw(mFilterCanvas);
+ } else {
+ super.draw(canvas);
+ }
+ }
+
+ private class QSFilterCanvas extends FilterCanvas {
+ public QSFilterCanvas(Canvas c) {
+ super(c);
+ }
+
+ @Override
+ public void drawPath(Path path, Paint paint) {
+ if (mEnabledVersion) {
+ paint.setColor(mColorEnabled);
+ } else {
+ paint.setStyle(Style.STROKE);
+ paint.setStrokeJoin(Paint.Join.ROUND);
+ paint.setColor(mColorDisabled);
+ paint.setStrokeWidth(mOutlineWidth);
+ }
+ super.drawPath(path, paint);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
new file mode 100644
index 0000000..afb5483
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+
+/** View that represents the quick settings tile panel. **/
+public class QSPanel extends ViewGroup {
+ private static final float TILE_ASPECT = 1.4f;
+ private static final float LARGE_TILE_FACTOR = 1.1f;
+
+ private final Context mContext;
+ private final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
+ private final FrameLayout mDetail;
+ private final CircularClipper mClipper;
+ private final H mHandler = new H();
+
+ private int mColumns;
+ private int mCellWidth;
+ private int mCellHeight;
+ private int mLargeCellWidth;
+ private int mLargeCellHeight;
+
+ private TileRecord mDetailRecord;
+
+ public QSPanel(Context context) {
+ this(context, null);
+ }
+
+ public QSPanel(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+
+ mDetail = new FrameLayout(mContext);
+ mDetail.setVisibility(GONE);
+ mDetail.setClickable(true);
+ addView(mDetail);
+ mClipper = new CircularClipper(mDetail);
+ updateResources();
+ }
+
+ public void updateResources() {
+ final int columns = Math.max(1,
+ mContext.getResources().getInteger(R.integer.quick_settings_num_columns));
+ if (mColumns != columns) {
+ mColumns = columns;
+ postInvalidate();
+ }
+ }
+
+ public void setExpanded(boolean expanded) {
+ if (!expanded) {
+ showDetail(false /*show*/, mDetailRecord);
+ }
+ for (TileRecord r : mRecords) {
+ r.tile.setShown(expanded);
+ }
+ }
+
+ private void showDetail(boolean show, TileRecord r) {
+ mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0, r).sendToTarget();
+ }
+
+ private void setTileVisibility(View v, boolean visible) {
+ mHandler.obtainMessage(H.SET_TILE_VISIBILITY, visible ? 1 : 0, 0, v).sendToTarget();
+ }
+
+ private void handleSetTileVisibility(View v, boolean visible) {
+ v.setVisibility(visible ? VISIBLE : GONE);
+ }
+
+ public void addTile(final QSTile<?> tile) {
+ final TileRecord r = new TileRecord();
+ r.tile = tile;
+ r.tileView = tile.createTileView(mContext);
+ r.tileView.setVisibility(View.GONE);
+ r.tile.setCallback(new QSTile.Callback() {
+ @Override
+ public void onStateChanged(QSTile.State state) {
+ setTileVisibility(r.tileView, state.visible);
+ r.tileView.onStateChanged(state);
+ }
+ @Override
+ public void onShowDetail(boolean show) {
+ QSPanel.this.showDetail(show, r);
+ }
+ });
+ final View.OnClickListener click = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ r.tile.click();
+ }
+ };
+ final View.OnClickListener clickSecondary = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ r.tile.secondaryClick();
+ }
+ };
+ r.tileView.init(click, clickSecondary);
+ mRecords.add(r);
+
+ addView(r.tileView);
+ }
+
+ private void handleShowDetail(TileRecord r, boolean show) {
+ AnimatorListener listener = null;
+ if (show) {
+ if (mDetailRecord != null) return;
+ final View detail = r.tile.createDetailView(mContext, mDetail);
+ if (detail == null) return;
+ mDetailRecord = r;
+ mDetail.removeAllViews();
+ mDetail.bringToFront();
+ mDetail.addView(detail);
+ } else {
+ if (mDetailRecord == null) return;
+ listener = mTeardownDetailWhenDone;
+ }
+ int x = r.tileView.getLeft() + r.tileView.getWidth() / 2;
+ int y = r.tileView.getTop() + r.tileView.getHeight() / 2;
+ mClipper.animateCircularClip(x, y, show, listener);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int width = MeasureSpec.getSize(widthMeasureSpec);
+ mCellWidth = width / mColumns;
+ mCellHeight = (int)(mCellWidth / TILE_ASPECT);
+ mLargeCellWidth = (int)(mCellWidth * LARGE_TILE_FACTOR);
+ mLargeCellHeight = (int)(mCellHeight * LARGE_TILE_FACTOR);
+ int r = 0;
+ int c = 0;
+ int rows = 0;
+ for (TileRecord record : mRecords) {
+ if (record.tileView.getVisibility() == GONE) continue;
+ record.row = r;
+ record.col = c;
+ rows = r + 1;
+ c++;
+ if (c == mColumns /*end of normal column*/ || r == 0 && c == 2 /*end of 1st column*/) {
+ c = 0;
+ r++;
+ }
+ }
+
+ for (TileRecord record : mRecords) {
+ if (record.tileView.getVisibility() == GONE) continue;
+ record.tileView.setDual(record.row == 0);
+ final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth;
+ final int ch = record.row == 0 ? mLargeCellHeight : mCellHeight;
+ record.tileView.measure(exactly(cw), exactly(ch));
+ }
+ final int actualHeight = rows == 0 ? 0 : getRowTop(rows);
+ mDetail.measure(exactly(width), exactly(actualHeight));
+ setMeasuredDimension(width, actualHeight);
+ }
+
+ private static int exactly(int size) {
+ return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ final int w = mCellWidth * mColumns;
+ for (TileRecord record : mRecords) {
+ if (record.tileView.getVisibility() == GONE) continue;
+ final int cols = getColumnCount(record.row);
+ final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth;
+ final int extra = (w - cw * cols) / (cols + 1);
+ final int left = record.col * cw + (record.col + 1) * extra;
+ final int top = getRowTop(record.row);
+ record.tileView.layout(left, top,
+ left + record.tileView.getMeasuredWidth(),
+ top + record.tileView.getMeasuredHeight());
+ }
+ mDetail.layout(0, 0, mDetail.getMeasuredWidth(), mDetail.getMeasuredHeight());
+ }
+
+ private int getRowTop(int row) {
+ if (row <= 0) return 0;
+ return mLargeCellHeight + (row - 1) * mCellHeight;
+ }
+
+ private int getColumnCount(int row) {
+ int cols = 0;
+ for (TileRecord record : mRecords) {
+ if (record.tileView.getVisibility() == GONE) continue;
+ if (record.row == row) cols++;
+ }
+ return cols;
+ }
+
+ private class H extends Handler {
+ private static final int SHOW_DETAIL = 1;
+ private static final int SET_TILE_VISIBILITY = 2;
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == SHOW_DETAIL) {
+ handleShowDetail((TileRecord)msg.obj, msg.arg1 != 0);
+ } else if (msg.what == SET_TILE_VISIBILITY) {
+ handleSetTileVisibility((View)msg.obj, msg.arg1 != 0);
+ }
+ }
+ }
+
+ private static final class TileRecord {
+ QSTile<?> tile;
+ QSTileView tileView;
+ int row;
+ int col;
+ }
+
+ private final AnimatorListenerAdapter mTeardownDetailWhenDone = new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ mDetail.removeAllViews();
+ mDetailRecord = null;
+ };
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
new file mode 100644
index 0000000..05f308d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.VectorDrawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.qs.QSTile.State;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.Disposable;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.TetheringController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Base quick-settings tile, extend this to create a new tile.
+ *
+ * State management done on a looper provided by the host. Tiles should update state in
+ * handleUpdateState. Callbacks affecting state should use refreshState to trigger another
+ * state update pass on tile looper.
+ */
+public abstract class QSTile<TState extends State> implements Disposable {
+ private final String TAG = "QSTile." + getClass().getSimpleName();
+
+ protected final Host mHost;
+ protected final Context mContext;
+ protected final H mHandler;
+ protected final Handler mUiHandler = new Handler(Looper.getMainLooper());
+
+ private Callback mCallback;
+ protected final TState mState = newTileState();
+ private final TState mTmpState = newTileState();
+
+ abstract protected TState newTileState();
+ abstract protected void handleClick();
+ abstract protected void handleUpdateState(TState state, Object arg);
+
+ protected QSTile(Host host) {
+ mHost = host;
+ mContext = host.getContext();
+ mHandler = new H(host.getLooper());
+ }
+
+ public Host getHost() {
+ return mHost;
+ }
+
+ public QSTileView createTileView(Context context) {
+ return new QSTileView(context);
+ }
+
+ public View createDetailView(Context context, ViewGroup root) {
+ return null; // optional
+ }
+
+ // safe to call from any thread
+
+ public void setCallback(Callback callback) {
+ mHandler.obtainMessage(H.SET_CALLBACK, callback).sendToTarget();
+ }
+
+ public void click() {
+ mHandler.sendEmptyMessage(H.CLICK);
+ }
+
+ public void secondaryClick() {
+ mHandler.sendEmptyMessage(H.SECONDARY_CLICK);
+ }
+
+ public void showDetail(boolean show) {
+ mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0).sendToTarget();
+ }
+
+ protected final void refreshState() {
+ refreshState(null);
+ }
+
+ protected final void refreshState(Object arg) {
+ mHandler.obtainMessage(H.REFRESH_STATE, arg).sendToTarget();
+ }
+
+ public void userSwitch(int newUserId) {
+ mHandler.obtainMessage(H.USER_SWITCH, newUserId).sendToTarget();
+ }
+
+ public void setShown(boolean shown) {
+ mHandler.obtainMessage(H.SHOWN, shown ? 1 : 0, 0).sendToTarget();
+ }
+
+ // call only on tile worker looper
+
+ private void handleSetCallback(Callback callback) {
+ mCallback = callback;
+ handleRefreshState(null);
+ }
+
+ protected void handleSecondaryClick() {
+ // optional
+ }
+
+ protected void handleShown(boolean shown) {
+ // optional, discouraged
+ }
+
+ protected void handleRefreshState(Object arg) {
+ handleUpdateState(mTmpState, arg);
+ final boolean changed = mTmpState.copyTo(mState);
+ if (changed) {
+ handleStateChanged();
+ }
+ }
+
+ private void handleStateChanged() {
+ if (mCallback != null) {
+ mCallback.onStateChanged(mState);
+ }
+ }
+
+ private void handleShowDetail(boolean show) {
+ if (mCallback != null) {
+ mCallback.onShowDetail(show);
+ }
+ }
+
+ protected void handleUserSwitch(int newUserId) {
+ handleRefreshState(null);
+ }
+
+ protected final class H extends Handler {
+ private static final int SET_CALLBACK = 1;
+ private static final int CLICK = 2;
+ private static final int SECONDARY_CLICK = 3;
+ private static final int REFRESH_STATE = 4;
+ private static final int SHOW_DETAIL = 5;
+ private static final int USER_SWITCH = 6;
+ private static final int SHOWN = 7;
+
+ private H(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ String name = null;
+ try {
+ if (msg.what == SET_CALLBACK) {
+ name = "handleSetCallback";
+ handleSetCallback((QSTile.Callback)msg.obj);
+ } else if (msg.what == CLICK) {
+ name = "handleClick";
+ handleClick();
+ } else if (msg.what == SECONDARY_CLICK) {
+ name = "handleSecondaryClick";
+ handleSecondaryClick();
+ } else if (msg.what == REFRESH_STATE) {
+ name = "handleRefreshState";
+ handleRefreshState(msg.obj);
+ } else if (msg.what == SHOW_DETAIL) {
+ name = "handleShowDetail";
+ handleShowDetail(msg.arg1 != 0);
+ } else if (msg.what == USER_SWITCH) {
+ name = "handleUserSwitch";
+ handleUserSwitch(msg.arg1);
+ } else if (msg.what == SHOWN) {
+ name = "handleShown";
+ handleShown(msg.arg1 != 0);
+ }
+ } catch (Throwable t) {
+ final String error = "Error in " + name;
+ Log.w(TAG, error, t);
+ mHost.warn(error, t);
+ }
+ }
+ }
+
+ public interface Callback {
+ void onStateChanged(State state);
+ void onShowDetail(boolean show);
+ }
+
+ public interface Host {
+ void startSettingsActivity(Intent intent);
+ void warn(String message, Throwable t);
+ void collapsePanels();
+ Looper getLooper();
+ Context getContext();
+ VectorDrawable getVectorDrawable(int resId);
+ BluetoothController getBluetoothController();
+ LocationController getLocationController();
+ RotationLockController getRotationLockController();
+ List<QSTile<?>> getTiles();
+ NetworkController getNetworkController();
+ ZenModeController getZenModeController();
+ TetheringController getTetheringController();
+ CastController getCastController();
+ }
+
+ public static class State {
+ public boolean visible;
+ public int iconId;
+ public Drawable icon;
+ public String label;
+ public String contentDescription;
+
+ public boolean copyTo(State other) {
+ if (other == null) throw new IllegalArgumentException();
+ if (!other.getClass().equals(getClass())) throw new IllegalArgumentException();
+ final boolean changed = other.visible != visible
+ || other.iconId != iconId
+ || !Objects.equals(other.icon, icon)
+ || !Objects.equals(other.label, label)
+ || !Objects.equals(other.contentDescription, contentDescription);
+ other.visible = visible;
+ other.iconId = iconId;
+ other.icon = icon;
+ other.label = label;
+ other.contentDescription = contentDescription;
+ return changed;
+ }
+
+ @Override
+ public String toString() {
+ return toStringBuilder().toString();
+ }
+
+ protected StringBuilder toStringBuilder() {
+ final StringBuilder sb = new StringBuilder( getClass().getSimpleName()).append('[');
+ sb.append("visible=").append(visible);
+ sb.append(",iconId=").append(iconId);
+ sb.append(",icon=").append(icon);
+ sb.append(",label=").append(label);
+ sb.append(",contentDescription=").append(contentDescription);
+ return sb.append(']');
+ }
+ }
+
+ public static class BooleanState extends State {
+ public boolean value;
+
+ @Override
+ public boolean copyTo(State other) {
+ final BooleanState o = (BooleanState) other;
+ final boolean changed = super.copyTo(other) || o.value != value;
+ o.value = value;
+ return changed;
+ }
+
+ @Override
+ protected StringBuilder toStringBuilder() {
+ final StringBuilder rt = super.toStringBuilder();
+ rt.insert(rt.length() - 1, ",value=" + value);
+ return rt;
+ }
+ }
+
+ public static final class SignalState extends State {
+ public boolean enabled;
+ public boolean connected;
+ public boolean activityIn;
+ public boolean activityOut;
+ public int overlayIconId;
+
+ @Override
+ public boolean copyTo(State other) {
+ final SignalState o = (SignalState) other;
+ final boolean changed = o.enabled != enabled
+ || o.connected != connected || o.activityIn != activityIn
+ || o.activityOut != activityOut
+ || o.overlayIconId != overlayIconId;
+ o.enabled = enabled;
+ o.connected = connected;
+ o.activityIn = activityIn;
+ o.activityOut = activityOut;
+ o.overlayIconId = overlayIconId;
+ return super.copyTo(other) || changed;
+ }
+
+ @Override
+ protected StringBuilder toStringBuilder() {
+ final StringBuilder rt = super.toStringBuilder();
+ rt.insert(rt.length() - 1, ",enabled=" + enabled);
+ rt.insert(rt.length() - 1, ",connected=" + connected);
+ rt.insert(rt.length() - 1, ",activityIn=" + activityIn);
+ rt.insert(rt.length() - 1, ",activityOut=" + activityOut);
+ rt.insert(rt.length() - 1, ",overlayIconId=" + overlayIconId);
+ return rt;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
new file mode 100644
index 0000000..17a95fb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView.ScaleType;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile.State;
+
+/** View that represents a standard quick settings tile. **/
+public class QSTileView extends ViewGroup {
+ private static final Typeface CONDENSED = Typeface.create("sans-serif-condensed",
+ Typeface.NORMAL);
+ private static final int VERTICAL_PADDING_FACTOR = 8; // internal padding 1/8 the cell height
+
+ protected final Context mContext;
+ private final View mIcon;
+ private final View mDivider;
+ private final TextView mLabel;
+ private final H mHandler = new H();
+
+ private boolean mDual;
+ private OnClickListener mClickPrimary;
+ private OnClickListener mClickSecondary;
+
+ public QSTileView(Context context) {
+ super(context);
+
+ mContext = context;
+ final Resources res = context.getResources();
+ mLabel = new TextView(mContext);
+ mLabel.setId(android.R.id.title);
+ mLabel.setTextColor(res.getColor(R.color.quick_settings_tile_text));
+ mLabel.setGravity(Gravity.CENTER);
+ mLabel.setTypeface(CONDENSED);
+ mLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+ res.getDimensionPixelSize(R.dimen.quick_settings_tile_text_size));
+ addView(mLabel);
+ setClipChildren(false);
+
+ mIcon = createIcon();
+ addView(mIcon);
+
+ mDivider = new View(mContext);
+ mDivider.setBackgroundColor(res.getColor(R.color.quick_settings_tile_divider));
+ final int dh = res.getDimensionPixelSize(R.dimen.quick_settings_tile_divider_height);
+ mDivider.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, dh));
+ addView(mDivider);
+
+ setClickable(true);
+ setBackground(getSelectableBackground());
+ }
+
+ public void setDual(boolean dual) {
+ mDual = dual;
+ if (mDual) {
+ setOnClickListener(mClickPrimary);
+ mLabel.setClickable(true);
+ mLabel.setOnClickListener(mClickSecondary);
+ } else {
+ mLabel.setClickable(false);
+ setOnClickListener(mClickPrimary);
+ }
+ mDivider.setVisibility(dual ? VISIBLE : GONE);
+ postInvalidate();
+ }
+
+ public void init(OnClickListener clickPrimary, OnClickListener clickSecondary) {
+ mClickPrimary = clickPrimary;
+ mClickSecondary = clickSecondary;
+ }
+
+ protected View createIcon() {
+ QSImageView icon = new QSImageView(mContext);
+ icon.setId(android.R.id.icon);
+ icon.setScaleType(ScaleType.CENTER_INSIDE);
+ return icon;
+ }
+
+ private Drawable getSelectableBackground() {
+ final int[] attrs = new int[] { android.R.attr.selectableItemBackground};
+ final TypedArray ta = mContext.obtainStyledAttributes(attrs);
+ final Drawable d = ta.getDrawable(0);
+ ta.recycle();
+ return d;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int w = MeasureSpec.getSize(widthMeasureSpec);
+ final int h = MeasureSpec.getSize(heightMeasureSpec);
+ final int p = h / VERTICAL_PADDING_FACTOR;
+ final int iconSpec = exactly((int)mLabel.getTextSize() * 2);
+ mIcon.measure(iconSpec, iconSpec);
+ mLabel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h, MeasureSpec.AT_MOST));
+ mLabel.measure(widthMeasureSpec, exactly(mLabel.getMeasuredHeight() + p * 2));
+ if (mDual) {
+ mDivider.measure(widthMeasureSpec, exactly(mDivider.getLayoutParams().height));
+ }
+ setMeasuredDimension(w, h);
+ }
+
+ private static int exactly(int size) {
+ return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ final int w = getMeasuredWidth();
+ final int h = getMeasuredHeight();
+ final int p = h / VERTICAL_PADDING_FACTOR;
+ final int contentHeight = p + mIcon.getMeasuredHeight() + mLabel.getMeasuredHeight()
+ + (mDual ? (p + mDivider.getMeasuredHeight()) : 0);
+
+ int top = (h - contentHeight) / 2 + p;
+ final int iconLeft = (w - mIcon.getMeasuredWidth()) / 2;
+ layout(mIcon, iconLeft, top);
+ top = mIcon.getBottom();
+ if (mDual) {
+ top += p;
+ layout(mDivider, 0, top);
+ top = mDivider.getBottom();
+ }
+ layout(mLabel, 0, top);
+ }
+
+ private static void layout(View child, int left, int top) {
+ child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
+ }
+
+ protected void handleStateChanged(QSTile.State state) {
+ if (mIcon instanceof QSImageView) {
+ QSImageView qsiv = (QSImageView) mIcon;
+ if (state.icon != null) {
+ qsiv.setImageDrawable(state.icon);
+ } else if (state.iconId > 0) {
+ qsiv.setImageResource(state.iconId);
+ }
+ if (state.icon != null && state instanceof QSTile.BooleanState) {
+ qsiv.setEnabledVersion(((QSTile.BooleanState)state).value);
+ }
+ }
+ mLabel.setText(state.label);
+ setContentDescription(state.contentDescription);
+ }
+
+ public void onStateChanged(QSTile.State state) {
+ mHandler.obtainMessage(H.STATE_CHANGED, state).sendToTarget();
+ }
+
+ private class H extends Handler {
+ private static final int STATE_CHANGED = 1;
+ public H() {
+ super(Looper.getMainLooper());
+ }
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == STATE_CHANGED) {
+ handleStateChanged((State) msg.obj);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
new file mode 100644
index 0000000..4debaa9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings.Secure;
+
+import com.android.systemui.statusbar.policy.Disposable;
+
+/** Helper for managing a secure setting. **/
+public abstract class SecureSetting extends ContentObserver implements Disposable {
+ private final Context mContext;
+ private final String mSettingName;
+
+ protected abstract void handleValueChanged(int value);
+
+ public SecureSetting(Context context, Handler handler, String settingName) {
+ super(handler);
+ mContext = context;
+ mSettingName = settingName;
+ rebindForCurrentUser();
+ }
+
+ public void rebindForCurrentUser() {
+ mContext.getContentResolver().registerContentObserver(
+ Secure.getUriFor(mSettingName), false, this);
+ }
+
+ public int getValue() {
+ return Secure.getInt(mContext.getContentResolver(), mSettingName, 0);
+ }
+
+ public void setValue(int value) {
+ Secure.putInt(mContext.getContentResolver(), mSettingName, value);
+ }
+
+ @Override
+ public void dispose() {
+ mContext.getContentResolver().unregisterContentObserver(this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ handleValueChanged(getValue());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
new file mode 100644
index 0000000..7b6c544
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile.SignalState;
+
+/** View that represents a custom quick settings tile for displaying signal info (wifi/cell). **/
+public final class SignalTileView extends QSTileView {
+ private static final long DEFAULT_DURATION = new ValueAnimator().getDuration();
+ private static final long SHORT_DURATION = DEFAULT_DURATION / 3;
+
+ private FrameLayout mIconFrame;
+ private ImageView mSignal;
+ private ImageView mOverlay;
+ private ImageView mIn;
+ private ImageView mOut;
+
+ public SignalTileView(Context context) {
+ super(context);
+
+ mIn = new ImageView(context);
+ mIn.setImageResource(R.drawable.ic_qs_signal_in);
+ addView(mIn);
+
+ mOut = new ImageView(context);
+ mOut.setImageResource(R.drawable.ic_qs_signal_out);
+ addView(mOut);
+ }
+
+ @Override
+ protected View createIcon() {
+ mIconFrame = new FrameLayout(mContext);
+ mSignal = new ImageView(mContext);
+ mIconFrame.addView(mSignal);
+ mOverlay = new ImageView(mContext);
+ mIconFrame.addView(mOverlay);
+ return mIconFrame;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int hs = MeasureSpec.makeMeasureSpec(mIconFrame.getMeasuredHeight(), MeasureSpec.EXACTLY);
+ int ws = MeasureSpec.makeMeasureSpec(mIconFrame.getMeasuredHeight(), MeasureSpec.AT_MOST);
+ mIn.measure(ws, hs);
+ mOut.measure(ws, hs);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ layoutIndicator(mIn);
+ layoutIndicator(mOut);
+ }
+
+ private void layoutIndicator(View indicator) {
+ indicator.layout(
+ mIconFrame.getRight(),
+ mIconFrame.getBottom() - indicator.getMeasuredHeight(),
+ mIconFrame.getRight() + indicator.getMeasuredWidth(),
+ mIconFrame.getBottom());
+ }
+
+ @Override
+ protected void handleStateChanged(QSTile.State state) {
+ super.handleStateChanged(state);
+ final SignalState s = (SignalState) state;
+ mSignal.setImageDrawable(null); // force refresh
+ mSignal.setImageResource(s.iconId);
+ if (s.overlayIconId > 0) {
+ mOverlay.setVisibility(VISIBLE);
+ mOverlay.setImageDrawable(null); // force refresh
+ mOverlay.setImageResource(s.overlayIconId);
+ } else {
+ mOverlay.setVisibility(GONE);
+ }
+ setVisibility(mIn, s.activityIn);
+ setVisibility(mOut, s.activityOut);
+ }
+
+ private void setVisibility(View view, boolean visible) {
+ final float newAlpha = visible ? 1 : 0;
+ if (view.getAlpha() != newAlpha) {
+ view.animate()
+ .setDuration(visible ? SHORT_DURATION : DEFAULT_DURATION)
+ .alpha(newAlpha)
+ .withLayer()
+ .start();
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
new file mode 100644
index 0000000..5fe8422
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.provider.Settings.Global;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.GlobalSetting;
+import com.android.systemui.qs.QSTile;
+
+/** Quick settings tile: Airplane mode **/
+public class AirplaneModeTile extends QSTile<QSTile.BooleanState> {
+ private final GlobalSetting mSetting;
+
+ public AirplaneModeTile(Host host) {
+ super(host);
+
+ mSetting = new GlobalSetting(mContext, mHandler, Global.AIRPLANE_MODE_ON) {
+ @Override
+ protected void handleValueChanged(int value) {
+ handleRefreshState(value);
+ }
+ };
+
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ mContext.registerReceiver(mReceiver, filter);
+ refreshState();
+ }
+
+ @Override
+ protected BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ @Override
+ public void handleClick() {
+ setEnabled(!mState.value);
+ }
+
+ private void setEnabled(boolean enabled) {
+ mSetting.setValue(enabled ? 1 : 0);
+ final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ intent.putExtra("state", enabled);
+ mContext.sendBroadcast(intent);
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ final int value = arg instanceof Integer ? (Integer)arg : mSetting.getValue();
+ final boolean airplaneMode = value != 0;
+ state.value = airplaneMode;
+ state.visible = true;
+ state.label = mContext.getString(R.string.quick_settings_airplane_mode_label);
+ state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_airplane);
+ if (airplaneMode) {
+ state.iconId = R.drawable.ic_qs_airplane_on;
+ state.contentDescription = mContext.getString(
+ R.string.accessibility_quick_settings_airplane,
+ mContext.getString(R.string.accessibility_desc_on));
+ } else {
+ state.iconId = R.drawable.ic_qs_airplane_off;
+ state.contentDescription = mContext.getString(
+ R.string.accessibility_quick_settings_airplane,
+ mContext.getString(R.string.accessibility_desc_off));
+ }
+ }
+
+ public void dispose() {
+ mSetting.dispose();
+ mContext.unregisterReceiver(mReceiver);
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())) {
+ refreshState();
+ }
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
new file mode 100644
index 0000000..60a6047
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
+import android.content.Intent;
+import android.provider.Settings;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.BluetoothController;
+
+/** Quick settings tile: Bluetooth **/
+public class BluetoothTile extends QSTile<QSTile.BooleanState> {
+ private static final Intent BLUETOOTH_SETTINGS = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
+
+ private final BluetoothController mController;
+
+ public BluetoothTile(Host host) {
+ super(host);
+ mController = host.getBluetoothController();
+ mController.addStateChangedCallback(mCallback);
+ }
+
+ @Override
+ protected BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ @Override
+ public void dispose() {
+ mController.removeStateChangedCallback(mCallback);
+ }
+
+ @Override
+ protected void handleClick() {
+ final boolean isEnabled = (Boolean)mState.value;
+ mController.setBluetoothEnabled(!isEnabled);
+ }
+
+ @Override
+ protected void handleSecondaryClick() {
+ mHost.startSettingsActivity(BLUETOOTH_SETTINGS);
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ final boolean supported = mController.isBluetoothSupported();
+ final boolean enabled = mController.isBluetoothEnabled();
+ final boolean connected = mController.isBluetoothConnected();
+ state.visible = supported;
+ state.value = enabled;
+ state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_bluetooth);
+ final String stateContentDescription;
+ if (enabled) {
+ if (connected) {
+ state.iconId = R.drawable.ic_qs_bluetooth_on;
+ stateContentDescription = mContext.getString(R.string.accessibility_desc_connected);
+ } else {
+ state.iconId = R.drawable.ic_qs_bluetooth_not_connected;
+ stateContentDescription = mContext.getString(R.string.accessibility_desc_on);
+ }
+ state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
+ } else {
+ state.iconId = R.drawable.ic_qs_bluetooth_off;
+ state.label = mContext.getString(R.string.quick_settings_bluetooth_off_label);
+ stateContentDescription = mContext.getString(R.string.accessibility_desc_off);
+ }
+ state.contentDescription = mContext.getString(
+ R.string.accessibility_quick_settings_bluetooth, stateContentDescription);
+ }
+
+ private final BluetoothStateChangeCallback mCallback = new BluetoothStateChangeCallback() {
+ @Override
+ public void onBluetoothStateChange(boolean on) {
+ refreshState();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
new file mode 100644
index 0000000..0e9b9a7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.app.ActivityManagerNative;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.os.RemoteException;
+import android.provider.Settings.Global;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.GlobalSetting;
+import com.android.systemui.qs.QSTile;
+
+/** Quick settings tile: Bug report **/
+public class BugreportTile extends QSTile<QSTile.State> {
+
+ private final GlobalSetting mSetting;
+
+ public BugreportTile(Host host) {
+ super(host);
+ mSetting = new GlobalSetting(mContext, mHandler, Global.BUGREPORT_IN_POWER_MENU) {
+ @Override
+ protected void handleValueChanged(int value) {
+ handleRefreshState(null);
+ }
+ };
+ }
+
+ @Override
+ protected State newTileState() {
+ return new State();
+ }
+
+ @Override
+ public void dispose() {
+ mSetting.dispose();
+ }
+
+ @Override
+ protected void handleClick() {
+ mHost.collapsePanels();
+ mUiHandler.post(mShowDialog);
+ }
+
+ @Override
+ protected void handleUpdateState(State state, Object pushArg) {
+ state.visible = mSetting.getValue() != 0;
+ state.iconId = com.android.internal.R.drawable.stat_sys_adb;
+ state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_bugreport);
+ state.label = mContext.getString(com.android.internal.R.string.bugreport_title);
+ }
+
+ private final Runnable mShowDialog = new Runnable() {
+ @Override
+ public void run() {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+ builder.setPositiveButton(com.android.internal.R.string.report, new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ // Add a little delay before executing, to give the
+ // dialog a chance to go away before it takes a
+ // screenshot.
+ mHandler.postDelayed(new Runnable() {
+ @Override public void run() {
+ try {
+ ActivityManagerNative.getDefault().requestBugReport();
+ } catch (RemoteException e) {
+ }
+ }
+ }, 500);
+ }
+ }
+ });
+ builder.setMessage(com.android.internal.R.string.bugreport_message);
+ builder.setTitle(com.android.internal.R.string.bugreport_title);
+ builder.setCancelable(true);
+ final Dialog dialog = builder.create();
+ dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ try {
+ WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
+ } catch (RemoteException e) {
+ }
+ dialog.show();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
new file mode 100644
index 0000000..a3eaa2c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.app.Dialog;
+import android.content.Intent;
+import android.media.MediaRouter;
+import android.provider.Settings;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.internal.app.MediaRouteDialogPresenter;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.CastController;
+
+/** Quick settings tile: Cast **/
+public class CastTile extends QSTile<QSTile.BooleanState> {
+ private static final Intent WIFI_DISPLAY_SETTINGS =
+ new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS);
+
+ private final CastController mController;
+
+ private boolean mShown;
+
+ public CastTile(Host host) {
+ super(host);
+ mController = host.getCastController();
+ if (mController != null) {
+ mController.addCallback(mCallback);
+ }
+ }
+
+ @Override
+ protected BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ @Override
+ public void dispose() {
+ if (mController == null) return;
+ mController.removeCallback(mCallback);
+ }
+
+ @Override
+ protected void handleUserSwitch(int newUserId) {
+ super.handleUserSwitch(newUserId);
+ if (mController == null) return;
+ mController.setCurrentUserId(newUserId);
+ }
+
+ @Override
+ protected void handleShown(boolean shown) {
+ if (mShown == shown) return;
+ if (mController == null) return;
+ mShown = shown;
+ mController.setDiscovering(mShown);
+ }
+
+ @Override
+ protected void handleClick() {
+ mHost.collapsePanels();
+ mUiHandler.post(mShowDialog);
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ state.visible = true;
+ state.label = mContext
+ .getString(R.string.quick_settings_remote_display_no_connection_label);
+ state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_cast);
+ if (arg instanceof CallbackInfo) {
+ final CallbackInfo cb = (CallbackInfo) arg;
+ if (cb.connectedRouteName != null) {
+ state.value = !cb.connecting;
+ }
+ }
+ }
+
+ private static class CallbackInfo {
+ boolean enabled;
+ boolean connecting;
+ String connectedRouteName;
+ }
+
+ private final CastController.Callback mCallback = new CastController.Callback() {
+ @Override
+ public void onStateChanged(boolean enabled, boolean connecting,
+ String connectedRouteName) {
+ final CallbackInfo info = new CallbackInfo(); // TODO pool
+ info.enabled = enabled;
+ info.connecting = connecting;
+ info.connectedRouteName = connectedRouteName;
+ refreshState(info);
+ }
+ };
+
+ private final Runnable mShowDialog = new Runnable() {
+ private Dialog mDialog;
+ @Override
+ public void run() {
+ mDialog = MediaRouteDialogPresenter.createDialog(mContext,
+ MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mDialog.dismiss();
+ mHost.startSettingsActivity(WIFI_DISPLAY_SETTINGS);
+ }
+ });
+ mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+ mDialog.show();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
new file mode 100644
index 0000000..86a4e79
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.QSTileView;
+import com.android.systemui.qs.SignalTileView;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+
+/** Quick settings tile: Cellular **/
+public class CellularTile extends QSTile<QSTile.SignalState> {
+ private static final Intent CELLULAR_SETTINGS = new Intent().setComponent(new ComponentName(
+ "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
+
+ private final NetworkController mController;
+
+ public CellularTile(Host host) {
+ super(host);
+ mController = host.getNetworkController();
+ mController.addNetworkSignalChangedCallback(mCallback);
+ }
+
+ @Override
+ protected SignalState newTileState() {
+ return new SignalState();
+ }
+
+ @Override
+ public void dispose() {
+ mController.removeNetworkSignalChangedCallback(mCallback);
+ }
+
+ @Override
+ public QSTileView createTileView(Context context) {
+ return new SignalTileView(context);
+ }
+
+ @Override
+ protected void handleClick() {
+ mHost.startSettingsActivity(CELLULAR_SETTINGS);
+ }
+
+ @Override
+ protected void handleUpdateState(SignalState state, Object arg) {
+ state.visible = mController.hasMobileDataFeature();
+ if (!state.visible) return;
+ final CallbackInfo cb = (CallbackInfo) arg;
+ if (cb == null) return;
+
+ final Resources r = mContext.getResources();
+ state.iconId = cb.enabled && (cb.mobileSignalIconId > 0)
+ ? cb.mobileSignalIconId
+ : R.drawable.ic_qs_signal_no_signal;
+ state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiEnabled
+ ? cb.dataTypeIconId
+ : 0;
+ state.activityIn = cb.enabled && cb.activityIn;
+ state.activityOut = cb.enabled && cb.activityOut;
+
+ state.label = cb.enabled
+ ? removeTrailingPeriod(cb.enabledDesc)
+ : r.getString(R.string.quick_settings_rssi_emergency_only);
+
+ final String signalContentDesc = cb.enabled && (cb.mobileSignalIconId > 0)
+ ? cb.signalContentDescription
+ : r.getString(R.string.accessibility_no_signal);
+ final String dataContentDesc = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiEnabled
+ ? cb.dataContentDescription
+ : r.getString(R.string.accessibility_no_data);
+ state.contentDescription = r.getString(
+ R.string.accessibility_quick_settings_mobile,
+ signalContentDesc, dataContentDesc,
+ state.label);
+ }
+
+ // Remove the period from the network name
+ public static String removeTrailingPeriod(String string) {
+ if (string == null) return null;
+ final int length = string.length();
+ if (string.endsWith(".")) {
+ return string.substring(0, length - 1);
+ }
+ return string;
+ }
+
+ private static final class CallbackInfo {
+ boolean enabled;
+ boolean wifiEnabled;
+ int mobileSignalIconId;
+ String signalContentDescription;
+ int dataTypeIconId;
+ String dataContentDescription;
+ boolean activityIn;
+ boolean activityOut;
+ String enabledDesc;
+ }
+
+ private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() {
+ private boolean mWifiEnabled;
+
+ @Override
+ public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
+ boolean activityIn, boolean activityOut,
+ String wifiSignalContentDescriptionId, String description) {
+ mWifiEnabled = enabled;
+ }
+
+ @Override
+ public void onMobileDataSignalChanged(boolean enabled,
+ int mobileSignalIconId,
+ String mobileSignalContentDescriptionId, int dataTypeIconId,
+ boolean activityIn, boolean activityOut,
+ String dataTypeContentDescriptionId, String description) {
+ final CallbackInfo info = new CallbackInfo(); // TODO pool?
+ info.enabled = enabled;
+ info.wifiEnabled = mWifiEnabled;
+ info.mobileSignalIconId = mobileSignalIconId;
+ info.signalContentDescription = mobileSignalContentDescriptionId;
+ info.dataTypeIconId = dataTypeIconId;
+ info.dataContentDescription = dataTypeContentDescriptionId;
+ info.activityIn = activityIn;
+ info.activityOut = activityOut;
+ info.enabledDesc = description;
+ refreshState(info);
+ }
+
+ @Override
+ public void onAirplaneModeChanged(boolean enabled) {
+ // noop
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
new file mode 100644
index 0000000..66740af
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.provider.Settings.Secure;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.SecureSetting;
+
+/** Quick settings tile: Invert colors **/
+public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
+
+ private final SecureSetting mSetting;
+
+ private boolean mVisible;
+
+ public ColorInversionTile(Host host) {
+ super(host);
+
+ mSetting = new SecureSetting(mContext, mHandler,
+ Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) {
+ @Override
+ protected void handleValueChanged(int value) {
+ handleRefreshState(value);
+ }
+ };
+
+ refreshState();
+ }
+
+ @Override
+ protected BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ @Override
+ public void dispose() {
+ mSetting.dispose();
+ }
+
+ @Override
+ protected void handleUserSwitch(int newUserId) {
+ mSetting.rebindForCurrentUser();
+ }
+
+ @Override
+ protected void handleClick() {
+ mSetting.setValue(mState.value ? 0 : 1);
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
+ final boolean enabled = value != 0;
+ if (enabled) {
+ mVisible = true;
+ }
+ state.visible = mVisible;
+ state.value = enabled;
+ state.label = mContext.getString(R.string.quick_settings_inversion_label);
+ state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_invert_colors);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
new file mode 100644
index 0000000..1a67afc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.Intent;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.TetheringController;
+
+/** Quick settings tile: Hotspot **/
+public class HotspotTile extends QSTile<QSTile.State> {
+ private static final Intent TETHER_SETTINGS = new Intent()
+ .setClassName("com.android.settings", "com.android.settings.TetherSettings");
+
+ // TODO: implement. see com.android.settings.TetherSettings
+
+ private final TetheringController mController;
+
+ public HotspotTile(Host host) {
+ super(host);
+ mController = host.getTetheringController();
+ }
+
+ @Override
+ protected State newTileState() {
+ return new State();
+ }
+
+ @Override
+ public void dispose() {
+
+ }
+
+ @Override
+ protected void handleClick() {
+ mHost.startSettingsActivity(TETHER_SETTINGS);
+ }
+
+ @Override
+ protected void handleUpdateState(State state, Object arg) {
+ state.visible = mController != null;
+ state.label = mContext.getString(R.string.quick_settings_hotspot_label);
+ state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_hotspot);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
new file mode 100644
index 0000000..176e05c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.graphics.drawable.AnimationDrawable;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.LocationController.LocationSettingsChangeCallback;
+
+/** Quick settings tile: Location **/
+public class LocationTile extends QSTile<QSTile.BooleanState> {
+
+ private final LocationController mController;
+
+ public LocationTile(Host host) {
+ super(host);
+ mController = host.getLocationController();
+ mController.addSettingsChangedCallback(mCallback);
+ }
+
+ @Override
+ protected BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ public void dispose() {
+ mController.removeSettingsChangedCallback(mCallback);
+ }
+
+ @Override
+ protected void handleClick() {
+ final boolean wasEnabled = (Boolean) mState.value;
+ final boolean changed = mController.setLocationEnabled(!wasEnabled);
+ if (!wasEnabled && changed) {
+ // If we've successfully switched from location off to on, close the
+ // notifications tray to show the network location provider consent dialog.
+ mHost.collapsePanels();
+ }
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ final boolean locationEnabled = mController.isLocationEnabled();
+ state.visible = true;
+ if (state.value != locationEnabled) {
+ state.value = locationEnabled;
+ final AnimationDrawable d = (AnimationDrawable) mContext.getDrawable(locationEnabled
+ ? R.drawable.ic_location_on_anim
+ : R.drawable.ic_location_off_anim);
+ state.icon = d;
+ mUiHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ d.start();
+ }
+ });
+ }
+ //state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_location);
+ if (locationEnabled) {
+ if (state.icon == null) state.iconId = R.drawable.ic_location_24_01;
+ state.label = mContext.getString(R.string.quick_settings_location_label);
+ state.contentDescription = mContext.getString(
+ R.string.accessibility_quick_settings_location,
+ mContext.getString(R.string.accessibility_desc_on));
+ } else {
+ if (state.icon == null) state.iconId = R.drawable.ic_location_24_11;
+ state.label = mContext.getString(R.string.quick_settings_location_off_label);
+ state.contentDescription = mContext.getString(
+ R.string.accessibility_quick_settings_location,
+ mContext.getString(R.string.accessibility_desc_off));
+ }
+ }
+
+ private final LocationSettingsChangeCallback mCallback = new LocationSettingsChangeCallback() {
+ @Override
+ public void onLocationSettingsChanged(boolean enabled) {
+ refreshState();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java
new file mode 100644
index 0000000..36a579c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+
+/** Quick settings tile: Ringer mode **/
+public class RingerModeTile extends QSTile<RingerModeTile.IntState> {
+
+ private final AudioManager mAudioManager;
+
+ public RingerModeTile(Host host) {
+ super(host);
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
+ mContext.registerReceiver(mReceiver, filter);
+ }
+
+ @Override
+ protected IntState newTileState() {
+ return new IntState();
+ }
+
+ @Override
+ public void dispose() {
+ mContext.unregisterReceiver(mReceiver);
+ }
+
+ @Override
+ protected void handleClick() {
+ final int oldValue = (Integer) mState.value;
+ final int newValue =
+ oldValue == AudioManager.RINGER_MODE_NORMAL ? AudioManager.RINGER_MODE_VIBRATE
+ : oldValue == AudioManager.RINGER_MODE_VIBRATE ? AudioManager.RINGER_MODE_SILENT
+ : AudioManager.RINGER_MODE_NORMAL;
+
+ mAudioManager.setRingerMode(newValue);
+ }
+
+ @Override
+ protected void handleUpdateState(IntState state, Object arg) {
+ final int ringerMode = mAudioManager.getRingerMode();
+ state.visible = true;
+ state.value = ringerMode;
+ if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
+ state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_vibrate);
+ state.label = "Vibrate";
+ } else if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
+ state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_silent);
+ state.label = "Silent";
+ } else {
+ state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_audible);
+ state.label = "Audible";
+ }
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(intent.getAction())) {
+ refreshState();
+ }
+ }
+ };
+
+ public static class IntState extends QSTile.State {
+ public int value;
+
+ @Override
+ public boolean copyTo(State other) {
+ final IntState o = (IntState) other;
+ final boolean changed = o.value != value;
+ o.value = value;
+ return super.copyTo(other) || changed;
+ }
+
+ @Override
+ protected StringBuilder toStringBuilder() {
+ final StringBuilder rt = super.toStringBuilder();
+ rt.insert(rt.length() - 1, ",value=" + value);
+ return rt;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
new file mode 100644
index 0000000..d075299
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.res.Configuration;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.Drawable;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
+
+/** Quick settings tile: Rotation **/
+public class RotationLockTile extends QSTile<QSTile.BooleanState> {
+
+ private final RotationLockController mController;
+
+ public RotationLockTile(Host host) {
+ super(host);
+ mController = host.getRotationLockController();
+ if (mController == null) return;
+ mController.addRotationLockControllerCallback(mCallback);
+ }
+
+ @Override
+ protected BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ public void dispose() {
+ if (mController == null) return;
+ mController.removeRotationLockControllerCallback(mCallback);
+ }
+
+ @Override
+ protected void handleClick() {
+ if (mController == null) return;
+ mController.setRotationLocked(!mState.value);
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ if (mController == null) return;
+ final boolean rotationLocked = mController.isRotationLocked();
+ state.visible = mController.isRotationLockAffordanceVisible();
+ if (state.value != rotationLocked) {
+ state.value = rotationLocked;
+ final AnimationDrawable d = (AnimationDrawable) mContext.getDrawable(rotationLocked
+ ? R.drawable.ic_rotate_locked_anim
+ : R.drawable.ic_rotate_unlocked_anim);
+ state.icon = d;
+ mUiHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ d.start();
+ }
+ });
+ }
+ if (rotationLocked) {
+ final int lockOrientation = mController.getRotationLockOrientation();
+ final int label = lockOrientation == Configuration.ORIENTATION_PORTRAIT
+ ? R.string.quick_settings_rotation_locked_portrait_label
+ : lockOrientation == Configuration.ORIENTATION_LANDSCAPE
+ ? R.string.quick_settings_rotation_locked_landscape_label
+ : R.string.quick_settings_rotation_locked_label;
+ state.label = mContext.getString(label);
+ if (state.icon == null) {
+ state.icon = mContext.getDrawable(R.drawable.ic_rotate_24_15);
+ }
+ } else {
+ state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
+ if (state.icon == null) {
+ state.icon = mContext.getDrawable(R.drawable.ic_rotate_24_01);
+ }
+ }
+ }
+
+ private final RotationLockControllerCallback mCallback = new RotationLockControllerCallback() {
+ @Override
+ public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
+ refreshState();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
new file mode 100644
index 0000000..e08a6fa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.provider.Settings;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.QSTileView;
+import com.android.systemui.qs.SignalTileView;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+
+/** Quick settings tile: Wifi **/
+public class WifiTile extends QSTile<QSTile.SignalState> {
+ private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
+
+ private final NetworkController mController;
+
+ public WifiTile(Host host) {
+ super(host);
+ mController = host.getNetworkController();
+ mController.addNetworkSignalChangedCallback(mCallback);
+ }
+
+ @Override
+ protected SignalState newTileState() {
+ return new SignalState();
+ }
+
+ @Override
+ public void dispose() {
+ mController.removeNetworkSignalChangedCallback(mCallback);
+ }
+
+ @Override
+ public QSTileView createTileView(Context context) {
+ return new SignalTileView(context);
+ }
+
+ @Override
+ protected void handleClick() {
+ mController.setWifiEnabled(!mState.enabled);
+ }
+
+ @Override
+ protected void handleSecondaryClick() {
+ mHost.startSettingsActivity(WIFI_SETTINGS);
+ }
+
+ @Override
+ protected void handleUpdateState(SignalState state, Object arg) {
+ if (arg == null) return;
+ state.visible = true;
+ CallbackInfo cb = (CallbackInfo) arg;
+
+ boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null);
+ boolean wifiNotConnected = (cb.wifiSignalIconId > 0) && (cb.enabledDesc == null);
+ state.enabled = wifiConnected;
+ state.connected = wifiConnected;
+ state.activityIn = cb.enabled && cb.activityIn;
+ state.activityOut = cb.enabled && cb.activityOut;
+ final String signalContentDescription;
+ final Resources r = mContext.getResources();
+ if (wifiConnected) {
+ state.iconId = cb.wifiSignalIconId;
+ state.label = removeDoubleQuotes(cb.enabledDesc);
+ signalContentDescription = cb.wifiSignalContentDescription;
+ } else if (wifiNotConnected) {
+ state.iconId = R.drawable.ic_qs_wifi_0;
+ state.label = r.getString(R.string.quick_settings_wifi_label);
+ signalContentDescription = r.getString(R.string.accessibility_no_wifi);
+ } else {
+ state.iconId = R.drawable.ic_qs_wifi_no_network;
+ state.label = r.getString(R.string.quick_settings_wifi_off_label);
+ signalContentDescription = r.getString(R.string.accessibility_wifi_off);
+ }
+ state.contentDescription = mContext.getString(
+ R.string.accessibility_quick_settings_wifi,
+ signalContentDescription,
+ state.connected ? state.label : "");
+ }
+
+ private static String removeDoubleQuotes(String string) {
+ if (string == null) return null;
+ final int length = string.length();
+ if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
+ return string.substring(1, length - 1);
+ }
+ return string;
+ }
+
+ private static final class CallbackInfo {
+ boolean enabled;
+ int wifiSignalIconId;
+ String enabledDesc;
+ boolean activityIn;
+ boolean activityOut;
+ String wifiSignalContentDescription;
+ }
+
+ private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() {
+ @Override
+ public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
+ boolean activityIn, boolean activityOut,
+ String wifiSignalContentDescriptionId, String description) {
+ final CallbackInfo info = new CallbackInfo();
+ info.enabled = enabled;
+ info.wifiSignalIconId = wifiSignalIconId;
+ info.enabledDesc = description;
+ info.activityIn = activityIn;
+ info.activityOut = activityOut;
+ info.wifiSignalContentDescription = wifiSignalContentDescriptionId;
+ refreshState(info);
+ }
+
+ @Override
+ public void onMobileDataSignalChanged(boolean enabled,
+ int mobileSignalIconId,
+ String mobileSignalContentDescriptionId, int dataTypeIconId,
+ boolean activityIn, boolean activityOut,
+ String dataTypeContentDescriptionId, String description) {
+ // noop
+ }
+
+ @Override
+ public void onAirplaneModeChanged(boolean enabled) {
+ // noop
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java
new file mode 100644
index 0000000..dceb856
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.service.notification.Condition;
+import android.util.AttributeSet;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ListView;
+import android.widget.RadioButton;
+import android.widget.RelativeLayout;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSImageView;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import java.util.HashSet;
+
+/** Quick settings control panel: Zen mode **/
+public class ZenModeDetail extends RelativeLayout {
+ private static final String TAG = "ZenModeDetail";
+ private static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+ private static final int[] MINUTES = new int[] { 15, 30, 45, 60, 120, 180, 240 };
+
+ private final H mHandler = new H();
+
+ private int mMinutesIndex = 3;
+ private Context mContext;
+ private ZenModeTile mTile;
+ private QSTile.Host mHost;
+ private ZenModeController mController;
+
+ private Switch mSwitch;
+ private ConditionAdapter mAdapter;
+
+ public ZenModeDetail(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public void init(ZenModeTile tile) {
+ mTile = tile;
+ mHost = mTile.getHost();
+ mContext = getContext();
+ mController = mHost.getZenModeController();
+
+ final QSImageView close = (QSImageView) findViewById(android.R.id.button1);
+ close.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_close));
+ close.setEnabledVersion(true);
+ close.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mTile.showDetail(false);
+ }
+ });
+ mSwitch = (Switch) findViewById(android.R.id.checkbox);
+ mSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ mController.setZen(isChecked);
+ }
+ });
+ mSwitch.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final boolean isChecked = mSwitch.isChecked();
+ mController.setZen(isChecked);
+ if (!isChecked) {
+ mTile.showDetail(false);
+ }
+ }
+ });
+
+ final View moreSettings = findViewById(android.R.id.button2);
+ moreSettings.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mHost.startSettingsActivity(ZEN_SETTINGS);
+ mTile.showDetail(false);
+ }
+ });
+ final ListView conditions = (ListView) findViewById(android.R.id.content);
+ mAdapter = new ConditionAdapter(mContext);
+ conditions.setAdapter(mAdapter);
+ mAdapter.add(updateTimeCondition());
+
+ updateZen(mController.isZen());
+ }
+
+ private Condition updateTimeCondition() {
+ final int minutes = MINUTES[mMinutesIndex];
+ final long millis = System.currentTimeMillis() + minutes * 60 * 1000;
+ final Uri id = new Uri.Builder().scheme(Condition.SCHEME).authority("android")
+ .appendPath("countdown").appendPath(Long.toString(millis)).build();
+ final int num = minutes < 60 ? minutes : minutes / 60;
+ final String units = minutes < 60 ? "minutes" : minutes == 60 ? "hour" : "hours";
+ return new Condition(id, "For " + num + " " + units, "", "", 0, Condition.STATE_TRUE,
+ Condition.FLAG_RELEVANT_NOW);
+ }
+
+ private void editTimeCondition(int delta) {
+ final int i = mMinutesIndex + delta;
+ if (i < 0 || i >= MINUTES.length) return;
+ mMinutesIndex = i;
+ mAdapter.remove(mAdapter.getItem(0));
+ final Condition c = updateTimeCondition();
+ mAdapter.insert(c, 0);
+ select(c);
+ }
+
+ private void select(Condition condition) {
+ mController.select(condition);
+ }
+
+ private void updateZen(boolean zen) {
+ mHandler.obtainMessage(H.UPDATE_ZEN, zen ? 1 : 0, 0).sendToTarget();
+ }
+
+ private void updateConditions(Condition[] conditions) {
+ if (conditions == null) return;
+ mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget();
+ }
+
+ private void handleUpdateZen(boolean zen) {
+ mSwitch.setChecked(zen);
+ }
+
+ private void handleUpdateConditions(Condition[] conditions) {
+ for (int i = mAdapter.getCount() - 1; i > 0; i--) {
+ mAdapter.remove(mAdapter.getItem(i));
+ }
+ for (Condition condition : conditions) {
+ mAdapter.add(condition);
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mController.addCallback(mCallback);
+ mController.requestConditions(true);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mController.removeCallback(mCallback);
+ mController.requestConditions(false);
+ }
+
+ private final class H extends Handler {
+ private static final int UPDATE_ZEN = 1;
+ private static final int UPDATE_CONDITIONS = 2;
+
+ public H() {
+ super(Looper.getMainLooper());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == UPDATE_ZEN) {
+ handleUpdateZen(msg.arg1 == 1);
+ } else if (msg.what == UPDATE_CONDITIONS) {
+ handleUpdateConditions((Condition[])msg.obj);
+ }
+ }
+ }
+
+ private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
+ @Override
+ public void onZenChanged(boolean zen) {
+ updateZen(zen);
+ }
+ public void onConditionsChanged(Condition[] conditions) {
+ updateConditions(conditions);
+ }
+ };
+
+ private final class ConditionAdapter extends ArrayAdapter<Condition> {
+ private final LayoutInflater mInflater;
+ private final HashSet<RadioButton> mRadioButtons = new HashSet<RadioButton>();
+
+ public ConditionAdapter(Context context) {
+ super(context, 0);
+ mInflater = LayoutInflater.from(new ContextThemeWrapper(context, R.style.QSWhiteTheme));
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final Condition condition = getItem(position);
+ final boolean enabled = condition.state == Condition.STATE_TRUE;
+
+ final View row = convertView != null ? convertView : mInflater
+ .inflate(R.layout.qs_zen_mode_detail_condition, parent, false);
+ final RadioButton rb = (RadioButton) row.findViewById(android.R.id.checkbox);
+ mRadioButtons.add(rb);
+ rb.setEnabled(enabled);
+ rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (isChecked) {
+ for (RadioButton otherButton : mRadioButtons) {
+ if (otherButton == rb) continue;
+ otherButton.setChecked(false);
+ }
+ select(condition);
+ }
+ }
+ });
+ final TextView title = (TextView) row.findViewById(android.R.id.title);
+ title.setText(condition.summary);
+ title.setEnabled(enabled);
+ title.setAlpha(enabled ? 1 : .5f);
+ final QSImageView button1 = (QSImageView) row.findViewById(android.R.id.button1);
+ button1.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_minus));
+ button1.setEnabledVersion(true);
+ button1.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ rb.setChecked(true);
+ editTimeCondition(-1);
+ }
+ });
+
+ final QSImageView button2 = (QSImageView) row.findViewById(android.R.id.button2);
+ button2.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_plus));
+ button2.setEnabledVersion(true);
+ button2.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ rb.setChecked(true);
+ editTimeCondition(1);
+ }
+ });
+ title.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ rb.setChecked(true);
+ }
+ });
+ if (position != 0) {
+ button1.setVisibility(View.GONE);
+ button2.setVisibility(View.GONE);
+ }
+ if (position == 0 && mRadioButtons.size() == 1) {
+ rb.setChecked(true);
+ }
+ return row;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java
new file mode 100644
index 0000000..83918e8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.Context;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+/** Quick settings tile: Zen mode **/
+public class ZenModeTile extends QSTile<QSTile.BooleanState> {
+ private final ZenModeController mController;
+
+ public ZenModeTile(Host host) {
+ super(host);
+ mController = host.getZenModeController();
+ mController.addCallback(mCallback);
+ }
+
+ @Override
+ public View createDetailView(Context context, ViewGroup root) {
+ final Context themedContext = new ContextThemeWrapper(mContext, R.style.QSAccentTheme);
+ final ZenModeDetail v = (ZenModeDetail) LayoutInflater.from(themedContext)
+ .inflate(R.layout.qs_zen_mode_detail, root, false);
+ v.init(this);
+ return v;
+ }
+
+ @Override
+ protected BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ @Override
+ public void dispose() {
+ mController.removeCallback(mCallback);
+ }
+
+ @Override
+ protected void handleClick() {
+ final boolean newZen = !mState.value;
+ mController.setZen(newZen);
+ if (newZen) {
+ showDetail(true);
+ }
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ final boolean zen = arg instanceof Boolean ? (Boolean)arg : mController.isZen();
+ state.value = zen;
+ state.visible = true;
+ state.iconId = R.drawable.stat_sys_zen_limited;
+ state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_zen);
+ state.label = mContext.getString(R.string.zen_mode_title);
+ }
+
+ private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
+ @Override
+ public void onZenChanged(boolean zen) {
+ refreshState(zen);
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 3ef8316..19a1b11 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -255,15 +255,10 @@
/** Loads the first task thumbnail */
Bitmap loadFirstTaskThumbnail() {
SystemServicesProxy ssp = mSystemServicesProxy;
- List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(1,
- UserHandle.CURRENT.getIdentifier());
- for (ActivityManager.RecentTaskInfo t : tasks) {
- // Skip tasks in the home stack
- if (ssp.isInHomeStack(t.persistentId)) {
- return null;
- }
+ List<ActivityManager.RunningTaskInfo> tasks = ssp.getRunningTasks(1);
- return ssp.getTaskThumbnail(t.persistentId);
+ for (ActivityManager.RunningTaskInfo t : tasks) {
+ return ssp.getTaskThumbnail(t.id);
}
return null;
}
@@ -286,17 +281,6 @@
return (tasks.size() > 1);
}
- /** Returns whether the base intent of the top task stack was launched with the flag
- * Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS. */
- boolean isTopTaskExcludeFromRecents(List<ActivityManager.RecentTaskInfo> tasks) {
- if (tasks.size() > 0) {
- ActivityManager.RecentTaskInfo t = tasks.get(0);
- Console.log(t.baseIntent.toString());
- return (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
- }
- return false;
- }
-
/** Converts from the device rotation to the degree */
float getDegreesForRotation(int value) {
switch (value) {
@@ -416,16 +400,14 @@
}
// Otherwise, Recents is not the front-most activity and we should animate into it. If
- // the activity at the root of the top task stack is excluded from recents, or if that
- // task stack is in the home stack, then we just do a simple transition. Otherwise, we
- // animate to the rects defined by the Recents service, which can differ depending on the
- // number of items in the list.
+ // the activity at the root of the top task stack in the home stack, then we just do a
+ // simple transition. Otherwise, we animate to the rects defined by the Recents service,
+ // which can differ depending on the number of items in the list.
List<ActivityManager.RecentTaskInfo> recentTasks =
- ssp.getRecentTasks(4, UserHandle.CURRENT.getIdentifier());
+ ssp.getRecentTasks(2, UserHandle.CURRENT.getIdentifier());
Rect taskRect = hasMultipleRecentsTask(recentTasks) ? mMultipleCountFirstTaskRect :
mSingleCountFirstTaskRect;
- boolean isTaskExcludedFromRecents = isTopTaskExcludeFromRecents(recentTasks);
- boolean useThumbnailTransition = !isTopTaskHome && !isTaskExcludedFromRecents &&
+ boolean useThumbnailTransition = !isTopTaskHome &&
hasValidTaskRects();
if (useThumbnailTransition) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java b/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
deleted file mode 100644
index 95ab8e8..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.android.systemui.recents;
-
-import android.animation.TimeInterpolator;
-
-/**
- * A pre-baked bezier-curved interpolator for quantum-paper transitions.
- */
-public class BakedBezierInterpolator implements TimeInterpolator {
- public static final BakedBezierInterpolator INSTANCE = new BakedBezierInterpolator();
-
- /**
- * Use the INSTANCE variable instead of instantiating.
- */
- private BakedBezierInterpolator() {
- super();
- }
-
- /**
- * Lookup table values.
- * Generated using a Bezier curve from (0,0) to (1,1) with control points:
- * P0 (0,0)
- * P1 (0.4, 0)
- * P2 (0.2, 1.0)
- * P3 (1.0, 1.0)
- *
- * Values sampled with x at regular intervals between 0 and 1.
- */
- private static final float[] VALUES = new float[] {
- 0.0f, 0.0002f, 0.0009f, 0.0019f, 0.0036f, 0.0059f, 0.0086f, 0.0119f, 0.0157f, 0.0209f,
- 0.0257f, 0.0321f, 0.0392f, 0.0469f, 0.0566f, 0.0656f, 0.0768f, 0.0887f, 0.1033f, 0.1186f,
- 0.1349f, 0.1519f, 0.1696f, 0.1928f, 0.2121f, 0.237f, 0.2627f, 0.2892f, 0.3109f, 0.3386f,
- 0.3667f, 0.3952f, 0.4241f, 0.4474f, 0.4766f, 0.5f, 0.5234f, 0.5468f, 0.5701f, 0.5933f,
- 0.6134f, 0.6333f, 0.6531f, 0.6698f, 0.6891f, 0.7054f, 0.7214f, 0.7346f, 0.7502f, 0.763f,
- 0.7756f, 0.7879f, 0.8f, 0.8107f, 0.8212f, 0.8326f, 0.8415f, 0.8503f, 0.8588f, 0.8672f,
- 0.8754f, 0.8833f, 0.8911f, 0.8977f, 0.9041f, 0.9113f, 0.9165f, 0.9232f, 0.9281f, 0.9328f,
- 0.9382f, 0.9434f, 0.9476f, 0.9518f, 0.9557f, 0.9596f, 0.9632f, 0.9662f, 0.9695f, 0.9722f,
- 0.9753f, 0.9777f, 0.9805f, 0.9826f, 0.9847f, 0.9866f, 0.9884f, 0.9901f, 0.9917f, 0.9931f,
- 0.9944f, 0.9955f, 0.9964f, 0.9973f, 0.9981f, 0.9986f, 0.9992f, 0.9995f, 0.9998f, 1.0f, 1.0f
- };
-
- private static final float STEP_SIZE = 1.0f / (VALUES.length - 1);
-
- @Override
- public float getInterpolation(float input) {
- if (input >= 1.0f) {
- return 1.0f;
- }
-
- if (input <= 0f) {
- return 0f;
- }
-
- int position = Math.min(
- (int)(input * (VALUES.length - 1)),
- VALUES.length - 2);
-
- float quantized = position * STEP_SIZE;
- float difference = input - quantized;
- float weight = difference / STEP_SIZE;
-
- return VALUES[position] + weight * (VALUES[position + 1] - VALUES[position]);
- }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 1d6a76c..90998da 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -32,7 +32,7 @@
// Enables the use of theme colors as the task bar background
public static final boolean EnableTaskBarThemeColors = true;
// Enables the info pane on long-press
- public static final boolean EnableInfoPane = true;
+ public static final boolean EnableInfoPane = false;
// Enables the search bar layout
public static final boolean EnableSearchLayout = true;
// Enables the dynamic shadows behind each task
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 463cf74..9afc1cb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -23,6 +23,8 @@
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.util.TypedValue;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import com.android.systemui.R;
@@ -42,6 +44,8 @@
public float animationPxMovementPerSecond;
+ public Interpolator defaultBezierInterpolator;
+
public int filteringCurrentViewsMinAnimDuration;
public int filteringNewViewsMinAnimDuration;
public int taskBarEnterAnimDuration;
@@ -121,7 +125,6 @@
res.getDimensionPixelSize(R.dimen.recents_task_view_z_increment);
searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
-
taskBarViewDefaultBackgroundColor =
res.getColor(R.color.recents_task_bar_default_background_color);
taskBarViewDefaultTextColor =
@@ -131,6 +134,9 @@
taskBarViewDarkTextColor =
res.getColor(R.color.recents_task_bar_dark_text_color);
+ defaultBezierInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.fast_out_slow_in);
+
// Update the search widget id
SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0);
searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index c64ca54..1ca0476 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -35,7 +35,6 @@
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
@@ -362,7 +361,7 @@
return mSystemServicesProxy;
}
- private List<ActivityManager.RecentTaskInfo> getRecentTasks(Context context) {
+ private List<ActivityManager.RecentTaskInfo> getRecentTasks() {
long t1 = System.currentTimeMillis();
SystemServicesProxy ssp = mSystemServicesProxy;
@@ -375,23 +374,6 @@
Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|tasks]", "" + tasks.size());
- // Remove home/recents tasks
- Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
- while (iter.hasNext()) {
- ActivityManager.RecentTaskInfo t = iter.next();
-
- // Skip tasks in the home stack
- if (ssp.isInHomeStack(t.persistentId)) {
- iter.remove();
- continue;
- }
- // Skip tasks from this Recents package
- if (t.baseIntent.getComponent().getPackageName().equals(context.getPackageName())) {
- iter.remove();
- continue;
- }
- }
-
return tasks;
}
@@ -408,7 +390,7 @@
// Get the recent tasks
SystemServicesProxy ssp = mSystemServicesProxy;
- List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(context);
+ List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks();
// Add each task to the task stack
t1 = System.currentTimeMillis();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index 0d3ee38..8d82883 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -30,7 +30,6 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
-import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -40,6 +39,7 @@
import android.util.Pair;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.Random;
@@ -54,7 +54,7 @@
IPackageManager mIpm;
UserManager mUm;
SearchManager mSm;
- String mPackage;
+ String mRecentsPackage;
ComponentName mAssistComponent;
Bitmap mDummyIcon;
@@ -67,7 +67,7 @@
mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
mIpm = AppGlobals.getPackageManager();
mSm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
- mPackage = context.getPackageName();
+ mRecentsPackage = context.getPackageName();
// Resolve the assist intent
Intent assist = mSm.getAssistIntent(context, false);
@@ -83,14 +83,14 @@
}
/** Returns a list of the recents tasks */
- public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
+ public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId) {
if (mAm == null) return null;
// If we are mocking, then create some recent tasks
if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
ArrayList<ActivityManager.RecentTaskInfo> tasks =
new ArrayList<ActivityManager.RecentTaskInfo>();
- int count = Math.min(numTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount);
+ int count = Math.min(numLatestTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount);
for (int i = 0; i < count; i++) {
// Create a dummy component name
int packageIndex = i % Constants.DebugFlags.App.SystemServicesProxyMockPackageCount;
@@ -114,9 +114,43 @@
return tasks;
}
- return mAm.getRecentTasksForUser(numTasks,
+ // Remove home/recents/excluded tasks
+ int minNumTasksToQuery = 10;
+ int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks);
+ List<ActivityManager.RecentTaskInfo> tasks = mAm.getRecentTasksForUser(numTasksToQuery,
ActivityManager.RECENT_IGNORE_UNAVAILABLE |
- ActivityManager.RECENT_INCLUDE_PROFILES, userId);
+ ActivityManager.RECENT_INCLUDE_PROFILES |
+ ActivityManager.RECENT_WITH_EXCLUDED, userId);
+ boolean isFirstValidTask = true;
+ Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
+ while (iter.hasNext()) {
+ ActivityManager.RecentTaskInfo t = iter.next();
+
+ // NOTE: The order of these checks happens in the expected order of the traversal of the
+ // tasks
+
+ // Skip tasks from this Recents package
+ if (t.baseIntent.getComponent().getPackageName().equals(mRecentsPackage)) {
+ iter.remove();
+ continue;
+ }
+ // Check the first non-recents task, include this task even if it is marked as excluded
+ // from recents. In other words, only remove excluded tasks if it is not the first task
+ boolean isExcluded = (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+ == Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+ if (isExcluded && !isFirstValidTask) {
+ iter.remove();
+ continue;
+ }
+ isFirstValidTask = false;
+ // Skip tasks in the home stack
+ if (isInHomeStack(t.persistentId)) {
+ iter.remove();
+ continue;
+ }
+ }
+
+ return tasks.subList(0, Math.min(tasks.size(), numLatestTasks));
}
/** Returns a list of the running tasks */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
index b602f84..46e6ee9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
@@ -18,6 +18,7 @@
import android.graphics.Color;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
/* Common code */
public class Utilities {
@@ -54,12 +55,15 @@
0.0722f * Color.blue(color));
}
- /** Returns the ideal text color to draw on top of a specified background color. */
- public static int getIdealTextColorForBackgroundColor(int color) {
- RecentsConfiguration configuration = RecentsConfiguration.getInstance();
+ /** Returns the ideal color to draw on top of a specified background color. */
+ public static int getIdealColorForBackgroundColor(int color, int lightRes, int darkRes) {
int greyscale = colorToGreyscale(color);
- return (greyscale < 128) ? configuration.taskBarViewLightTextColor :
- configuration.taskBarViewDarkTextColor;
-
+ return (greyscale < 128) ? lightRes : darkRes;
+ }
+ /** Returns the ideal drawable to draw on top of a specified background color. */
+ public static Drawable getIdealResourceForBackgroundColor(int color, Drawable lightRes,
+ Drawable darkRes) {
+ int greyscale = colorToGreyscale(color);
+ return (greyscale < 128) ? lightRes : darkRes;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
index c6cb812..07caa1b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
@@ -16,7 +16,10 @@
package com.android.systemui.recents.views;
+import android.animation.ValueAnimator;
import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -32,9 +35,13 @@
class TaskBarView extends FrameLayout {
Task mTask;
+ ImageView mDismissButton;
ImageView mApplicationIcon;
TextView mActivityDescription;
+ Drawable mLightDismissDrawable;
+ Drawable mDarkDismissDrawable;
+
public TaskBarView(Context context) {
this(context, null);
}
@@ -49,6 +56,9 @@
public TaskBarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ Resources res = context.getResources();
+ mLightDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_light);
+ mDarkDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_dark);
}
@Override
@@ -56,6 +66,28 @@
// Initialize the icon and description views
mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
mActivityDescription = (TextView) findViewById(R.id.activity_description);
+ mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
+ }
+
+ /** Synchronizes this bar view's properties with the task's transform */
+ void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
+ TaskViewTransform toTransform, int duration) {
+ RecentsConfiguration config = RecentsConfiguration.getInstance();
+ if (duration > 0) {
+ if (animateFromTransform != null) {
+ mDismissButton.setAlpha(animateFromTransform.dismissAlpha);
+ }
+ mDismissButton.animate()
+ .alpha(toTransform.dismissAlpha)
+ .setStartDelay(0)
+ .setDuration(duration)
+ .setInterpolator(config.defaultBezierInterpolator)
+ .withLayer()
+ .start();
+ } else {
+ mDismissButton.setAlpha(toTransform.dismissAlpha);
+ }
+ mDismissButton.invalidate();
}
/** Binds the bar view to the task */
@@ -74,7 +106,10 @@
int tint = t.colorPrimary;
if (Constants.DebugFlags.App.EnableTaskBarThemeColors && tint != 0) {
setBackgroundColor(tint);
- mActivityDescription.setTextColor(Utilities.getIdealTextColorForBackgroundColor(tint));
+ mActivityDescription.setTextColor(Utilities.getIdealColorForBackgroundColor(tint,
+ configuration.taskBarViewLightTextColor, configuration.taskBarViewDarkTextColor));
+ mDismissButton.setImageDrawable(Utilities.getIdealResourceForBackgroundColor(tint,
+ mLightDismissDrawable, mDarkDismissDrawable));
} else {
setBackgroundColor(configuration.taskBarViewDefaultBackgroundColor);
mActivityDescription.setTextColor(configuration.taskBarViewDefaultTextColor);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
index c6c29a6..f1c362a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
@@ -30,7 +30,6 @@
import android.widget.Button;
import android.widget.FrameLayout;
import com.android.systemui.R;
-import com.android.systemui.recents.BakedBezierInterpolator;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.Utilities;
@@ -111,7 +110,8 @@
int duration = Utilities.calculateTranslationAnimationDuration((int) mMaxClipRadius);
mCircularClipAnimator = ObjectAnimator.ofFloat(this, "circularClipRadius", toRadius);
mCircularClipAnimator.setDuration(duration);
- mCircularClipAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
+ mCircularClipAnimator.setInterpolator(
+ RecentsConfiguration.getInstance().defaultBezierInterpolator);
mCircularClipAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -143,7 +143,7 @@
.scaleX(1f)
.scaleY(1f)
.setDuration(duration)
- .setInterpolator(BakedBezierInterpolator.INSTANCE)
+ .setInterpolator(RecentsConfiguration.getInstance().defaultBezierInterpolator)
.withLayer()
.start();
}
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 55c38a9..b64225e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -37,7 +37,6 @@
import android.widget.FrameLayout;
import android.widget.OverScroller;
import com.android.systemui.R;
-import com.android.systemui.recents.BakedBezierInterpolator;
import com.android.systemui.recents.Console;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
@@ -170,6 +169,9 @@
transform.translationY = (int) (boundedT * overlapHeight - scaleYOffset);
}
+ // Set the alphas
+ transform.dismissAlpha = Math.max(-1f, Math.min(0f, t)) + 1f;
+
// Update the rect and visibility
transform.rect.set(mTaskRect);
if (t < -(numPeekCards + 1)) {
@@ -338,7 +340,7 @@
mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll);
mScrollAnimator.setDuration(Utilities.calculateTranslationAnimationDuration(newScroll -
curScroll, 250));
- mScrollAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
+ mScrollAnimator.setInterpolator(RecentsConfiguration.getInstance().defaultBezierInterpolator);
mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
@@ -1036,6 +1038,15 @@
}
}
+ @Override
+ public void onTaskDismissed(TaskView tv) {
+ Task task = tv.getTask();
+ // Remove the task from the view
+ mStack.removeTask(task);
+ // Notify the callback that we've removed the task and it can clean up after it
+ mCb.onTaskRemoved(task);
+ }
+
/**** View.OnClickListener Implementation ****/
@Override
@@ -1095,6 +1106,7 @@
@Override
public void onComponentRemoved(Set<ComponentName> cns) {
+ RecentsConfiguration config = RecentsConfiguration.getInstance();
// For other tasks, just remove them directly if they no longer exist
ArrayList<Task> tasks = mStack.getTasks();
for (int i = tasks.size() - 1; i >= 0; i--) {
@@ -1477,13 +1489,7 @@
@Override
public void onChildDismissed(View v) {
TaskView tv = (TaskView) v;
- Task task = tv.getTask();
-
- // Remove the task from the view
- mSv.mStack.removeTask(task);
-
- // Notify the callback that we've removed the task and it can clean up after it
- mSv.mCb.onTaskRemoved(task);
+ mSv.onTaskDismissed(tv);
// Disable HW layers
mSv.decHwLayersRefCount("swipeComplete");
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 b03f389..5fad629 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -31,7 +31,6 @@
import android.view.animation.AccelerateInterpolator;
import android.widget.FrameLayout;
import com.android.systemui.R;
-import com.android.systemui.recents.BakedBezierInterpolator;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.model.Task;
@@ -46,6 +45,7 @@
public void onTaskInfoPanelShown(TaskView tv);
public void onTaskInfoPanelHidden(TaskView tv);
public void onTaskAppInfoClicked(TaskView tv);
+ public void onTaskDismissed(TaskView tv);
// public void onTaskViewReboundToTask(TaskView tv, Task t);
}
@@ -143,6 +143,10 @@
int minZ = config.taskViewTranslationZMinPx;
int incZ = config.taskViewTranslationZIncrementPx;
+ // Update the bar view
+ mBarView.updateViewPropertiesToTaskTransform(animateFromTransform, toTransform, duration);
+
+ // Update this task view
if (duration > 0) {
if (animateFromTransform != null) {
setTranslationY(animateFromTransform.translationY);
@@ -161,7 +165,7 @@
.scaleY(toTransform.scale)
.alpha(toTransform.alpha)
.setDuration(duration)
- .setInterpolator(BakedBezierInterpolator.INSTANCE)
+ .setInterpolator(config.defaultBezierInterpolator)
.withLayer()
.setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
@@ -221,8 +225,8 @@
mBarView.setAlpha(0f);
mBarView.animate()
.alpha(1f)
- .setStartDelay(235)
- .setInterpolator(BakedBezierInterpolator.INSTANCE)
+ .setStartDelay(250)
+ .setInterpolator(config.defaultBezierInterpolator)
.setDuration(config.taskBarEnterAnimDuration)
.withLayer()
.start();
@@ -234,7 +238,7 @@
mBarView.animate()
.alpha(0f)
.setStartDelay(0)
- .setInterpolator(BakedBezierInterpolator.INSTANCE)
+ .setInterpolator(config.defaultBezierInterpolator)
.setDuration(config.taskBarExitAnimDuration)
.withLayer()
.withEndAction(new Runnable() {
@@ -252,7 +256,7 @@
animate().translationX(config.taskViewRemoveAnimTranslationXPx)
.alpha(0f)
.setStartDelay(0)
- .setInterpolator(BakedBezierInterpolator.INSTANCE)
+ .setInterpolator(config.defaultBezierInterpolator)
.setDuration(config.taskViewRemoveAnimDuration)
.withLayer()
.withEndAction(new Runnable() {
@@ -310,7 +314,7 @@
mInfoView.animate()
.alpha(0f)
.setDuration(config.taskViewInfoPaneAnimDuration)
- .setInterpolator(BakedBezierInterpolator.INSTANCE)
+ .setInterpolator(config.defaultBezierInterpolator)
.withLayer()
.withEndAction(new Runnable() {
@Override
@@ -380,6 +384,7 @@
mInfoView.rebindToTask(mTask, reloadingTaskData);
// Rebind any listeners
mBarView.mApplicationIcon.setOnClickListener(this);
+ mBarView.mDismissButton.setOnClickListener(this);
mInfoView.mAppInfoButton.setOnClickListener(this);
}
mTaskDataLoaded = true;
@@ -405,6 +410,15 @@
hideInfoPane();
} else if (v == mBarView.mApplicationIcon) {
mCb.onTaskIconClicked(this);
+ } else if (v == mBarView.mDismissButton) {
+ // Animate out the view and call the callback
+ final TaskView tv = this;
+ animateRemoval(new Runnable() {
+ @Override
+ public void run() {
+ mCb.onTaskDismissed(tv);
+ }
+ });
} else if (v == mInfoView.mAppInfoButton) {
mCb.onTaskAppInfoClicked(this);
}
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 0748bbb..e6391a8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -24,6 +24,7 @@
public int translationY = 0;
public float scale = 1f;
public float alpha = 1f;
+ public float dismissAlpha = 1f;
public boolean visible = false;
public Rect rect = new Rect();
float t;
@@ -36,6 +37,7 @@
translationY = o.translationY;
scale = o.scale;
alpha = o.alpha;
+ dismissAlpha = o.dismissAlpha;
visible = o.visible;
rect.set(o.rect);
t = o.t;
@@ -44,6 +46,6 @@
@Override
public String toString() {
return "TaskViewTransform y: " + translationY + " scale: " + scale + " alpha: " + alpha +
- " visible: " + visible + " rect: " + rect;
+ " visible: " + visible + " rect: " + rect + " dismissAlpha: " + dismissAlpha;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index 327e715..a770f58 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -28,7 +28,6 @@
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
import android.widget.ImageView;
import java.util.ArrayList;
@@ -36,6 +35,12 @@
public class BrightnessController implements ToggleSlider.Listener {
private static final String TAG = "StatusBar.BrightnessController";
+ /**
+ * {@link android.provider.Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ} uses the range [-1, 1].
+ * Using this factor, it is converted to [0, BRIGHTNESS_ADJ_RESOLUTION] for the SeekBar.
+ */
+ private static final float BRIGHTNESS_ADJ_RESOLUTION = 100;
+
private final int mMinimumBacklight;
private final int mMaximumBacklight;
@@ -51,6 +56,8 @@
private ArrayList<BrightnessStateChangeCallback> mChangeCallbacks =
new ArrayList<BrightnessStateChangeCallback>();
+ private boolean mAutomatic;
+
public interface BrightnessStateChangeCallback {
public void onBrightnessLevelChanged();
}
@@ -62,6 +69,8 @@
Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE);
private final Uri BRIGHTNESS_URI =
Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
+ private final Uri BRIGHTNESS_ADJ_URI =
+ Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ);
public BrightnessObserver(Handler handler) {
super(handler);
@@ -77,7 +86,10 @@
if (selfChange) return;
if (BRIGHTNESS_MODE_URI.equals(uri)) {
updateMode();
- } else if (BRIGHTNESS_URI.equals(uri)) {
+ updateSlider();
+ } else if (BRIGHTNESS_URI.equals(uri) && !mAutomatic) {
+ updateSlider();
+ } else if (BRIGHTNESS_ADJ_URI.equals(uri) && mAutomatic) {
updateSlider();
} else {
updateMode();
@@ -97,6 +109,9 @@
cr.registerContentObserver(
BRIGHTNESS_URI,
false, this, UserHandle.USER_ALL);
+ cr.registerContentObserver(
+ BRIGHTNESS_ADJ_URI,
+ false, this, UserHandle.USER_ALL);
}
public void stopObserving() {
@@ -119,7 +134,6 @@
}
};
mBrightnessObserver = new BrightnessObserver(mHandler);
- mBrightnessObserver.startObserving();
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mMinimumBacklight = pm.getMinimumScreenBrightnessSetting();
@@ -128,13 +142,6 @@
mAutomaticAvailable = context.getResources().getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available);
mPower = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
-
- // Update the slider and mode before attaching the listener so we don't receive the
- // onChanged notifications for the initial values.
- updateMode();
- updateSlider();
-
- control.setOnChangedListener(this);
}
public void addStateChangedCallback(BrightnessStateChangeCallback cb) {
@@ -150,18 +157,29 @@
// Do nothing
}
+ public void registerCallbacks() {
+ mBrightnessObserver.startObserving();
+ mUserTracker.startTracking();
+
+ // Update the slider and mode before attaching the listener so we don't receive the
+ // onChanged notifications for the initial values.
+ updateMode();
+ updateSlider();
+
+ mControl.setOnChangedListener(this);
+ }
+
/** Unregister all call backs, both to and from the controller */
public void unregisterCallbacks() {
mBrightnessObserver.stopObserving();
mChangeCallbacks.clear();
mUserTracker.stopTracking();
+ mControl.setOnChangedListener(null);
}
public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value) {
- setMode(automatic ? Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
- : Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
- updateIcon(automatic);
- if (!automatic) {
+ updateIcon(mAutomatic);
+ if (!mAutomatic) {
final int val = value + mMinimumBacklight;
setBrightness(val);
if (!tracking) {
@@ -173,6 +191,18 @@
}
});
}
+ } else {
+ final float adj = value / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1;
+ setBrightnessAdj(adj);
+ if (!tracking) {
+ AsyncTask.execute(new Runnable() {
+ public void run() {
+ Settings.System.putFloatForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adj,
+ UserHandle.USER_CURRENT);
+ }
+ });
+ }
}
for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
@@ -193,6 +223,13 @@
}
}
+ private void setBrightnessAdj(float adj) {
+ try {
+ mPower.setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(adj);
+ } catch (RemoteException ex) {
+ }
+ }
+
private void updateIcon(boolean automatic) {
if (mIcon != null) {
mIcon.setImageResource(automatic ?
@@ -205,15 +242,12 @@
private void updateMode() {
if (mAutomaticAvailable) {
int automatic;
- try {
- automatic = Settings.System.getIntForUser(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS_MODE,
- UserHandle.USER_CURRENT);
- } catch (SettingNotFoundException snfe) {
- automatic = 0;
- }
- mControl.setChecked(automatic != 0);
- updateIcon(automatic != 0);
+ automatic = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
+ UserHandle.USER_CURRENT);
+ mAutomatic = automatic != Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
+ updateIcon(mAutomatic);
} else {
mControl.setChecked(false);
updateIcon(false /*automatic*/);
@@ -222,16 +256,20 @@
/** Fetch the brightness from the system settings and update the slider */
private void updateSlider() {
- int value;
- try {
- value = Settings.System.getIntForUser(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS,
+ if (mAutomatic) {
+ float value = Settings.System.getFloatForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0,
UserHandle.USER_CURRENT);
- } catch (SettingNotFoundException ex) {
- value = mMaximumBacklight;
+ mControl.setMax((int) BRIGHTNESS_ADJ_RESOLUTION);
+ mControl.setValue((int) ((value + 1) * BRIGHTNESS_ADJ_RESOLUTION / 2f));
+ } else {
+ int value;
+ value = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS, mMaximumBacklight,
+ UserHandle.USER_CURRENT);
+ mControl.setMax(mMaximumBacklight - mMinimumBacklight);
+ mControl.setValue(value - mMinimumBacklight);
}
- mControl.setMax(mMaximumBacklight - mMinimumBacklight);
- mControl.setValue(value - mMinimumBacklight);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
index bd5e5e8..27881c4 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
@@ -92,6 +92,7 @@
mBrightnessController = new BrightnessController(getContext(),
(ImageView) findViewById(R.id.brightness_icon),
(ToggleSlider) findViewById(R.id.brightness_slider));
+ mBrightnessController.registerCallbacks();
dismissBrightnessDialog(mBrightnessDialogLongTimeout);
mBrightnessController.addStateChangedCallback(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
index 036bd4f..f8ff616 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
@@ -29,9 +29,6 @@
private int mCurrentUserId;
public CurrentUserTracker(Context context) {
- IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
- context.registerReceiver(this, filter);
- mCurrentUserId = ActivityManager.getCurrentUser();
mContext = context;
}
@@ -50,6 +47,12 @@
}
}
+ public void startTracking() {
+ mCurrentUserId = ActivityManager.getCurrentUser();
+ IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
+ mContext.registerReceiver(this, filter);
+ }
+
public void stopTracking() {
mContext.unregisterReceiver(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
index 7d38058..4b78072 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
@@ -62,7 +62,6 @@
mToggle = (CompoundButton) findViewById(R.id.toggle);
mToggle.setOnCheckedChangeListener(mCheckListener);
- mToggle.setBackground(res.getDrawable(R.drawable.status_bar_toggle_button));
mSlider = (SeekBar) findViewById(R.id.slider);
mSlider.setOnSeekBarChangeListener(mSeekListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 281bd2d..4bd0e1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -112,7 +112,7 @@
* @return The desired notification height.
*/
public int getIntrinsicHeight() {
- return mActualHeight;
+ return getHeight();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
new file mode 100644
index 0000000..0606a94
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+
+/**
+ * Utility class to calculate general fling animation when the finger is released.
+ */
+public class FlingAnimationUtils {
+
+ private static final float LINEAR_OUT_SLOW_IN_Y2 = 0.35f;
+ private static final float MAX_LENGTH_SECONDS = 0.4f;
+ private static final float MIN_VELOCITY_DP_PER_SECOND = 250;
+
+ /**
+ * Crazy math. http://en.wikipedia.org/wiki/B%C3%A9zier_curve
+ */
+ private static final float LINEAR_OUT_SLOW_IN_START_GRADIENT = 1/LINEAR_OUT_SLOW_IN_Y2;
+
+ private Interpolator mLinearOutSlowIn;
+ private Interpolator mFastOutSlowIn;
+ private float mMinVelocityPxPerSecond;
+
+ public FlingAnimationUtils(Context ctx) {
+ mLinearOutSlowIn = new PathInterpolator(0, 0, LINEAR_OUT_SLOW_IN_Y2, 1);
+ mFastOutSlowIn
+ = AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_slow_in);
+ mMinVelocityPxPerSecond
+ = MIN_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
+ }
+
+ /**
+ * Applies the interpolator and length to the animator, such that the fling animation is
+ * consistent with the finger motion.
+ *
+ * @param animator the animator to apply
+ * @param currValue the current value
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
+ */
+ public void apply(ValueAnimator animator, float currValue, float endValue, float velocity) {
+ float diff = Math.abs(endValue - currValue);
+ float velAbs = Math.abs(velocity);
+ float durationSeconds = LINEAR_OUT_SLOW_IN_START_GRADIENT * diff / velAbs;
+ if (durationSeconds <= MAX_LENGTH_SECONDS) {
+ animator.setInterpolator(mLinearOutSlowIn);
+ } else if (velAbs >= mMinVelocityPxPerSecond) {
+
+ // Cross fade between fast-out-slow-in and linear interpolator with current velocity.
+ durationSeconds = MAX_LENGTH_SECONDS;
+ VelocityInterpolator velocityInterpolator
+ = new VelocityInterpolator(durationSeconds, velAbs, diff);
+ InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
+ velocityInterpolator, mLinearOutSlowIn, mLinearOutSlowIn);
+ animator.setInterpolator(superInterpolator);
+ } else {
+
+ // Just use a normal interpolator which doesn't take the velocity into account.
+ durationSeconds = MAX_LENGTH_SECONDS;
+ animator.setInterpolator(mFastOutSlowIn);
+ }
+ animator.setDuration((long) (durationSeconds * 1000));
+ }
+
+ /**
+ * An interpolator which interpolates two interpolators with an interpolator.
+ */
+ private static final class InterpolatorInterpolator implements Interpolator {
+
+ private Interpolator mInterpolator1;
+ private Interpolator mInterpolator2;
+ private Interpolator mCrossfader;
+
+ InterpolatorInterpolator(Interpolator interpolator1, Interpolator interpolator2,
+ Interpolator crossfader) {
+ mInterpolator1 = interpolator1;
+ mInterpolator2 = interpolator2;
+ mCrossfader = crossfader;
+ }
+
+ @Override
+ public float getInterpolation(float input) {
+ float t = mCrossfader.getInterpolation(input);
+ return (1 - t) * mInterpolator1.getInterpolation(input)
+ + t * mInterpolator2.getInterpolation(input);
+ }
+ }
+
+ /**
+ * An interpolator which interpolates with a fixed velocity.
+ */
+ private static final class VelocityInterpolator implements Interpolator {
+
+ private float mDurationSeconds;
+ private float mVelocity;
+ private float mDiff;
+
+ private VelocityInterpolator(float durationSeconds, float velocity, float diff) {
+ mDurationSeconds = durationSeconds;
+ mVelocity = velocity;
+ mDiff = diff;
+ }
+
+ @Override
+ public float getInterpolation(float input) {
+ float time = input * mDurationSeconds;
+ return time * mVelocity / mDiff;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
index 864c597..451c5c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
@@ -34,21 +34,6 @@
}
@Override
- public void setActualHeight(int currentHeight, boolean notifyListeners) {
- // noop
- }
-
- @Override
- public int getActualHeight() {
- return getHeight();
- }
-
- @Override
- public void setClipTopAmount(int clipTopAmount) {
- // noop
- }
-
- @Override
protected void onFinishInflate() {
super.onFinishInflate();
mIconsView = (NotificationOverflowIconsView) findViewById(R.id.overflow_icons_view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 89da08f..2bc6f9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -28,19 +28,19 @@
import android.widget.LinearLayout;
import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl;
// Intimately tied to the design of res/layout/signal_cluster_view.xml
public class SignalClusterView
extends LinearLayout
- implements NetworkController.SignalCluster {
+ implements NetworkControllerImpl.SignalCluster {
static final boolean DEBUG = false;
static final String TAG = "SignalClusterView";
static final PorterDuffColorFilter PROBLEM_FILTER
= new PorterDuffColorFilter(0xffab653b, PorterDuff.Mode.SRC_ATOP);
- NetworkController mNC;
+ NetworkControllerImpl mNC;
private boolean mWifiVisible = false;
private int mWifiStrengthId = 0;
@@ -67,7 +67,7 @@
super(context, attrs, defStyle);
}
- public void setNetworkController(NetworkController nc) {
+ public void setNetworkController(NetworkControllerImpl nc) {
if (DEBUG) Log.d(TAG, "NetworkController=" + nc);
mNC = nc;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index a3cf0f2..869edff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -27,7 +27,7 @@
import com.android.systemui.DemoMode;
import com.android.systemui.R;
import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.LocationControllerImpl;
public class DemoStatusIcons extends LinearLayout implements DemoMode {
private final LinearLayout mStatusIcons;
@@ -74,9 +74,9 @@
}
String location = args.getString("location");
if (location != null) {
- int iconId = location.equals("show") ? LocationController.LOCATION_STATUS_ICON_ID
+ int iconId = location.equals("show") ? LocationControllerImpl.LOCATION_STATUS_ICON_ID
: 0;
- updateSlot(LocationController.LOCATION_STATUS_ICON_PLACEHOLDER, null, iconId);
+ updateSlot(LocationControllerImpl.LOCATION_STATUS_ICON_PLACEHOLDER, null, iconId);
}
String alarm = args.getString("alarm");
if (alarm != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 1ffb4ee..d8e1766 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -160,4 +161,9 @@
return false;
}
}
+
+ public boolean interceptMediaKey(KeyEvent event) {
+ ensureView();
+ return mKeyguardView.interceptMediaKey(event);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
new file mode 100644
index 0000000..c26f15e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Canvas;
+import android.graphics.Path;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.ContactsContract;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+
+import com.android.systemui.R;
+import com.android.systemui.settings.UserSwitcherHostView;
+import com.android.systemui.statusbar.policy.UserInfoController;
+
+/**
+ * Image button for the multi user switcher.
+ */
+public class MultiUserSwitch extends ImageButton implements View.OnClickListener,
+ UserInfoController.OnUserInfoChangedListener {
+
+ private ViewGroup mOverlayParent;
+
+ public MultiUserSwitch(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ setOnClickListener(this);
+ }
+
+ public void setOverlayParent(ViewGroup parent) {
+ mOverlayParent = parent;
+ }
+
+ @Override
+ public void onClick(View v) {
+ final UserManager um = UserManager.get(getContext());
+ if (um.isUserSwitcherEnabled()) {
+ final UserSwitcherHostView switcher =
+ (UserSwitcherHostView) LayoutInflater.from(getContext()).inflate(
+ R.layout.user_switcher_host, mOverlayParent, false);
+ switcher.setFinishRunnable(new Runnable() {
+ @Override
+ public void run() {
+ mOverlayParent.removeView(switcher);
+ }
+ });
+ switcher.refreshUsers();
+ mOverlayParent.addView(switcher);
+ } else {
+ Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
+ getContext(), v, ContactsContract.Profile.CONTENT_URI,
+ ContactsContract.QuickContact.MODE_LARGE, null);
+ getContext().startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ }
+ }
+
+ public void setUserInfoController(UserInfoController userInfoController) {
+ userInfoController.addListener(this);
+ }
+
+ @Override
+ public void onUserInfoChanged(String name, Drawable picture) {
+ setImageDrawable(picture);
+ }
+}
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 f63ba9c..b9f5ab2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -24,12 +24,15 @@
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
+import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import android.widget.LinearLayout;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
@@ -42,7 +45,7 @@
PhoneStatusBar mStatusBar;
private StatusBarHeaderView mHeader;
- private QuickSettingsContainerView mQsContainer;
+ private View mQsContainer;
private View mKeyguardStatusView;
private ObservableScrollView mScrollView;
private View mStackScrollerContainer;
@@ -51,15 +54,21 @@
private int mNotificationTopPadding;
private boolean mAnimateNextTopPaddingChange;
- private Interpolator mExpansionInterpolator;
-
private int mTrackingPointer;
private VelocityTracker mVelocityTracker;
private boolean mTracking;
+
+ /**
+ * Whether we are currently handling a motion gesture in #onInterceptTouchEvent, but haven't
+ * intercepted yet.
+ */
+ private boolean mIntercepting;
private boolean mQsExpanded;
private float mInitialHeightOnTouch;
private float mInitialTouchX;
private float mInitialTouchY;
+ private float mLastTouchX;
+ private float mLastTouchY;
private float mQsExpansionHeight;
private int mQsMinExpansionHeight;
private int mQsMaxExpansionHeight;
@@ -68,6 +77,8 @@
private int mStackScrollerIntrinsicPadding;
private boolean mQsExpansionEnabled = true;
private ValueAnimator mQsExpansionAnimator;
+ private FlingAnimationUtils mFlingAnimationUtils;
+ private int mStatusBarMinHeight;
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -93,9 +104,10 @@
super.onFinishInflate();
mHeader = (StatusBarHeaderView) findViewById(R.id.header);
mHeader.getBackgroundView().setOnClickListener(this);
+ mHeader.setOverlayParent(this);
mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
mStackScrollerContainer = findViewById(R.id.notification_container_parent);
- mQsContainer = (QuickSettingsContainerView) findViewById(R.id.quick_settings_container);
+ mQsContainer = findViewById(R.id.quick_settings_container);
mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
mScrollView.setListener(this);
mNotificationStackScroller = (NotificationStackScrollLayout)
@@ -104,8 +116,9 @@
mNotificationTopPadding = getResources().getDimensionPixelSize(
R.dimen.notifications_top_padding);
mMinStackHeight = getResources().getDimensionPixelSize(R.dimen.collapsed_stack_height);
- mExpansionInterpolator = AnimationUtils.loadInterpolator(
- getContext(), android.R.interpolator.fast_out_slow_in);
+ mFlingAnimationUtils = new FlingAnimationUtils(getContext());
+ mStatusBarMinHeight = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height);
}
@Override
@@ -144,7 +157,6 @@
public void setQsExpansionEnabled(boolean qsExpansionEnabled) {
mQsExpansionEnabled = qsExpansionEnabled;
- mHeader.setExpansionEnabled(qsExpansionEnabled);
}
public void closeQs() {
@@ -193,6 +205,7 @@
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
+ mIntercepting = true;
mInitialTouchY = y;
mInitialTouchX = x;
initVelocityTracker();
@@ -215,6 +228,16 @@
case MotionEvent.ACTION_MOVE:
final float h = y - mInitialTouchY;
trackMovement(event);
+ if (mTracking) {
+
+ // Already tracking because onOverscrolled was called. We need to update here
+ // so we don't stop for a frame until the next touch event gets handled in
+ // onTouchEvent.
+ setQsExpansion(h + mInitialHeightOnTouch);
+ trackMovement(event);
+ mIntercepting = false;
+ return true;
+ }
if (Math.abs(h) > mTouchSlop && Math.abs(h) > Math.abs(x - mInitialTouchX)
&& shouldIntercept(mInitialTouchX, mInitialTouchY, h)) {
onQsExpansionStarted();
@@ -222,14 +245,41 @@
mInitialTouchY = y;
mInitialTouchX = x;
mTracking = true;
+ mIntercepting = false;
return true;
}
break;
+
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ trackMovement(event);
+ if (mTracking) {
+ flingWithCurrentVelocity();
+ mTracking = false;
+ }
+ mIntercepting = false;
+ break;
}
return !mQsExpanded && super.onInterceptTouchEvent(event);
}
@Override
+ public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+
+ // Block request so we can still intercept the scrolling when QS is expanded.
+ if (!mQsExpanded) {
+ super.requestDisallowInterceptTouchEvent(disallowIntercept);
+ }
+ }
+
+ private void flingWithCurrentVelocity() {
+ float vel = getCurrentVelocity();
+
+ // TODO: Better logic whether we should expand or not.
+ flingSettings(vel, vel > 0);
+ }
+
+ @Override
public boolean onTouchEvent(MotionEvent event) {
// TODO: Handle doublefinger swipe to notifications again. Look at history for a reference
// implementation.
@@ -278,12 +328,7 @@
mTracking = false;
mTrackingPointer = -1;
trackMovement(event);
-
- float vel = getCurrentVelocity();
-
- // TODO: Better logic whether we should expand or not.
- flingSettings(vel, vel > 0);
-
+ flingWithCurrentVelocity();
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
@@ -297,11 +342,26 @@
return mQsExpanded || super.onTouchEvent(event);
}
+ @Override
+ public void onOverscrolled(int amount) {
+ if (mIntercepting) {
+ onQsExpansionStarted(amount);
+ mInitialHeightOnTouch = mQsExpansionHeight;
+ mInitialTouchY = mLastTouchY;
+ mInitialTouchX = mLastTouchX;
+ mTracking = true;
+ }
+ }
+
private void onQsExpansionStarted() {
+ onQsExpansionStarted(0);
+ }
+
+ private void onQsExpansionStarted(int overscrollAmount) {
cancelAnimation();
// Reset scroll position and apply that position to the expanded height.
- float height = mQsExpansionHeight - mScrollView.getScrollY();
+ float height = mQsExpansionHeight - mScrollView.getScrollY() - overscrollAmount;
mScrollView.scrollTo(0, 0);
setQsExpansion(height);
}
@@ -359,6 +419,8 @@
private void trackMovement(MotionEvent event) {
if (mVelocityTracker != null) mVelocityTracker.addMovement(event);
+ mLastTouchX = event.getX();
+ mLastTouchY = event.getY();
}
private void initVelocityTracker() {
@@ -382,13 +444,9 @@
}
}
private void flingSettings(float vel, boolean expand) {
-
- // TODO: Actually use velocity.
-
float target = expand ? mQsMaxExpansionHeight : mQsMinExpansionHeight;
ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target);
- animator.setDuration(EXPANSION_ANIMATION_LENGTH);
- animator.setInterpolator(mExpansionInterpolator);
+ mFlingAnimationUtils.apply(animator, mQsExpansionHeight, target, vel);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
@@ -412,11 +470,8 @@
if (!mQsExpansionEnabled) {
return false;
}
- View headerView = mStatusBar.getBarState() == StatusBarState.KEYGUARD && !mQsExpanded
- ? mKeyguardStatusView
- : mHeader;
- boolean onHeader = x >= headerView.getLeft() && x <= headerView.getRight()
- && y >= headerView.getTop() && y <= headerView.getBottom();
+ boolean onHeader = x >= mHeader.getLeft() && x <= mHeader.getRight()
+ && y >= mHeader.getTop() && y <= mHeader.getBottom();
if (mQsExpanded) {
return onHeader || (mScrollView.isScrolledToBottom() && yDiff < 0);
} else {
@@ -425,6 +480,35 @@
}
@Override
+ public void setVisibility(int visibility) {
+ int oldVisibility = getVisibility();
+ super.setVisibility(visibility);
+ if (visibility != oldVisibility) {
+ reparentStatusIcons(visibility == VISIBLE);
+ }
+ }
+
+ /**
+ * When the notification panel gets expanded, we need to move the status icons in the header
+ * card.
+ */
+ private void reparentStatusIcons(boolean toHeader) {
+ if (mStatusBar == null) {
+ return;
+ }
+ LinearLayout systemIcons = mStatusBar.getSystemIcons();
+ if (systemIcons.getParent() != null) {
+ ((ViewGroup) systemIcons.getParent()).removeView(systemIcons);
+ }
+ if (toHeader) {
+ mHeader.attachSystemIcons(systemIcons);
+ } else {
+ mHeader.onSystemIconsDetached();
+ mStatusBar.reattachSystemIcons();
+ }
+ }
+
+ @Override
protected boolean isScrolledToBottom() {
if (!isInSettings()) {
return mNotificationStackScroller.isScrolledToBottom();
@@ -439,7 +523,9 @@
int notificationMarginBottom = mStackScrollerContainer.getPaddingBottom();
int emptyBottomMargin = notificationMarginBottom
+ mNotificationStackScroller.getEmptyBottomMargin();
- return maxPanelHeight - emptyBottomMargin;
+ int maxHeight = maxPanelHeight - emptyBottomMargin;
+ maxHeight = Math.max(maxHeight, mStatusBarMinHeight);
+ return maxHeight;
}
return super.getMaxPanelHeight();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
index 46484f3..ba0b66e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
@@ -27,6 +27,7 @@
public class ObservableScrollView extends ScrollView {
private Listener mListener;
+ private int mLastOverscrollAmount;
public ObservableScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -58,7 +59,25 @@
}
}
+ @Override
+ protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY,
+ int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY,
+ boolean isTouchEvent) {
+ mLastOverscrollAmount = Math.max(0, scrollY + deltaY - getMaxScrollY());
+ return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY,
+ maxOverScrollX, maxOverScrollY, isTouchEvent);
+ }
+
+ @Override
+ protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
+ super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
+ if (mListener != null && mLastOverscrollAmount > 0) {
+ mListener.onOverscrolled(mLastOverscrollAmount);
+ }
+ }
+
public interface Listener {
void onScrollChanged();
+ void onOverscrolled(int amount);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 324d6f3..8800625 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -224,6 +224,5 @@
public void onTrackingStopped(PanelView panel) {
mTracking = false;
- panelExpansionChanged(panel, panel.getExpandedFraction());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java
index c229a09..d7f34d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java
@@ -77,12 +77,6 @@
event.getActionMasked(), (int) event.getX(), (int) event.getY());
}
}
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- PanelBar.LOG("PanelHolder got touch in open air, closing panels");
- mBar.collapseAllPanels(true);
- break;
- }
return false;
}
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 92eee4e..23b0594 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -29,7 +29,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
@@ -69,6 +68,7 @@
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@@ -93,6 +93,8 @@
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.qs.QSPanel;
+import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper;
@@ -106,12 +108,15 @@
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
+import com.android.systemui.statusbar.policy.CastControllerImpl;
import com.android.systemui.statusbar.policy.DateView;
import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.LocationControllerImpl;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl;
+import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
+import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
@@ -180,11 +185,14 @@
PhoneStatusBarPolicy mIconPolicy;
// These are no longer handled by the policy, because we need custom strategies for them
- BluetoothController mBluetoothController;
+ BluetoothControllerImpl mBluetoothController;
BatteryController mBatteryController;
- LocationController mLocationController;
- NetworkController mNetworkController;
- RotationLockController mRotationLockController;
+ LocationControllerImpl mLocationController;
+ NetworkControllerImpl mNetworkController;
+ RotationLockControllerImpl mRotationLockController;
+ UserInfoController mUserInfoController;
+ ZenModeControllerImpl mZenModeController;
+ CastControllerImpl mCastController;
int mNaturalBarHeight = -1;
int mIconSize = -1;
@@ -205,6 +213,7 @@
// right-hand icons
LinearLayout mSystemIconArea;
+ LinearLayout mSystemIcons;
// left-hand icons
LinearLayout mStatusIcons;
@@ -221,16 +230,14 @@
int mNotificationPanelGravity;
int mNotificationPanelMarginBottomPx;
float mNotificationPanelMinHeightFrac;
- boolean mNotificationPanelIsFullScreenWidth;
TextView mNotificationPanelDebugText;
// settings
- QuickSettings mQS;
View mFlipSettingsView;
- QuickSettingsContainerView mSettingsContainer;
+ private QSPanel mQSPanel;
// top bar
- View mNotificationPanelHeader;
+ StatusBarHeaderView mHeader;
View mKeyguardStatusView;
KeyguardBottomAreaView mKeyguardBottomArea;
boolean mLeaveOpenOnKeyguardHide;
@@ -240,8 +247,6 @@
String mKeyguardHotwordPhrase = "";
int mKeyguardMaxNotificationCount;
View mDateTimeView;
- View mClearButton;
- ImageView mHeaderFlipper;
// carrier/wifi label
private TextView mCarrierLabel;
@@ -249,7 +254,6 @@
private int mCarrierLabelHeight;
private TextView mEmergencyCallLabel;
private int mStatusBarHeaderHeight;
- private View mKeyguardCarrierLabel;
private boolean mShowCarrierInPanel = false;
@@ -554,8 +558,6 @@
mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
R.id.notification_panel);
mNotificationPanel.setStatusBar(this);
- mNotificationPanelIsFullScreenWidth =
- (mNotificationPanel.getLayoutParams().width == ViewGroup.LayoutParams.MATCH_PARENT);
// make the header non-responsive to clicks
mNotificationPanel.findViewById(R.id.header).setOnTouchListener(
@@ -609,6 +611,7 @@
mPixelFormat = PixelFormat.OPAQUE;
mSystemIconArea = (LinearLayout) mStatusBarView.findViewById(R.id.system_icon_area);
+ mSystemIcons = (LinearLayout) mStatusBarView.findViewById(R.id.system_icons);
mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons);
mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons);
mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon);
@@ -627,39 +630,30 @@
(NotificationOverflowContainer) LayoutInflater.from(mContext).inflate(
R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
mKeyguardIconOverflowContainer.setOnActivatedListener(this);
- mKeyguardCarrierLabel = mStatusBarWindow.findViewById(R.id.keyguard_carrier_text);
mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
mStackScroller.addView(mKeyguardIconOverflowContainer);
mExpandedContents = mStackScroller;
- mNotificationPanelHeader = mStatusBarWindow.findViewById(R.id.header);
+ mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
+ mHeader.setActivityStarter(this);
mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
mKeyguardBottomArea =
(KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
mKeyguardBottomArea.setActivityStarter(this);
mKeyguardIndicationTextView = (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
R.id.keyguard_indication_text);
- mClearButton = mStatusBarWindow.findViewById(R.id.clear_all_button);
- mClearButton.setOnClickListener(mClearButtonListener);
- mClearButton.setAlpha(0f);
- mClearButton.setVisibility(View.INVISIBLE);
- mClearButton.setEnabled(false);
mDateView = (DateView)mStatusBarWindow.findViewById(R.id.date);
- mDateTimeView = mNotificationPanelHeader.findViewById(R.id.datetime);
+ mDateTimeView = mHeader.findViewById(R.id.datetime);
if (mDateTimeView != null) {
mDateTimeView.setOnClickListener(mClockClickListener);
mDateTimeView.setEnabled(true);
}
- mHeaderFlipper = (ImageView) mStatusBarWindow.findViewById(R.id.header_flipper);
-
- if (!mNotificationPanelIsFullScreenWidth) {
- mNotificationPanel.setSystemUiVisibility(
- View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS |
- View.STATUS_BAR_DISABLE_CLOCK);
- }
+ mNotificationPanel.setSystemUiVisibility(
+ View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS |
+ View.STATUS_BAR_DISABLE_CLOCK);
mTicker = new MyTicker(context, mStatusBarView);
@@ -672,14 +666,16 @@
setAreThereNotifications();
// Other icons
- mLocationController = new LocationController(mContext); // will post a notification
+ mLocationController = new LocationControllerImpl(mContext); // will post a notification
mBatteryController = new BatteryController(mContext);
- mNetworkController = new NetworkController(mContext);
- mBluetoothController = new BluetoothController(mContext);
- if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)
- || QuickSettings.DEBUG_GONE_TILES) {
- mRotationLockController = new RotationLockController(mContext);
+ mNetworkController = new NetworkControllerImpl(mContext);
+ mBluetoothController = new BluetoothControllerImpl(mContext);
+ if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) {
+ mRotationLockController = new RotationLockControllerImpl(mContext);
}
+ mUserInfoController = new UserInfoController(mContext);
+ mZenModeController = new ZenModeControllerImpl(mContext, mHandler);
+ mCastController = new CastControllerImpl(mContext);
final SignalClusterView signalCluster =
(SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);
@@ -728,25 +724,23 @@
// updateCarrierLabelVisibility(false);
}
- // Quick Settings needs a container to survive
- mSettingsContainer = (QuickSettingsContainerView)
- mStatusBarWindow.findViewById(R.id.quick_settings_container);
- mFlipSettingsView = mSettingsContainer;
- if (mSettingsContainer != null) {
- mQS = new QuickSettings(mContext, mSettingsContainer);
- if (!mNotificationPanelIsFullScreenWidth) {
- mSettingsContainer.setSystemUiVisibility(
- View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS
- | View.STATUS_BAR_DISABLE_SYSTEM_INFO);
+ // Set up the quick settings tile panel
+ mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
+ if (mQSPanel != null) {
+ final QSTileHost qsh = new QSTileHost(mContext, this,
+ mBluetoothController, mLocationController, mRotationLockController,
+ mNetworkController, mZenModeController, null /*tethering*/,
+ mCastController);
+ for (QSTile<?> tile : qsh.getTiles()) {
+ mQSPanel.addTile(tile);
}
- mQS.setService(this);
- mQS.setBar(mStatusBarView);
- mQS.setup(mNetworkController, mBluetoothController, mBatteryController,
- mLocationController, mRotationLockController);
- } else {
- mQS = null; // fly away, be free
+ mHeader.setQSPanel(mQSPanel);
}
+ // User info. Trigger first load.
+ mHeader.setUserInfoController(mUserInfoController);
+ mUserInfoController.reloadUserInfo();
+
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mBroadcastReceiver.onReceive(mContext,
new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));
@@ -1118,19 +1112,6 @@
if (mNavigationBarView != null) {
mNavigationBarView.setLayoutDirection(layoutDirection);
}
-
- if (mClearButton != null && mClearButton instanceof ImageView) {
- // Force asset reloading
- ((ImageView)mClearButton).setImageDrawable(null);
- ((ImageView)mClearButton).setImageResource(R.drawable.ic_notify_clear);
- }
-
- if (mHeaderFlipper != null) {
- // Force asset reloading
- mHeaderFlipper.setImageDrawable(null);
- mHeaderFlipper.setImageResource(R.drawable.ic_notify_quicksettings);
- }
-
refreshAllStatusBarIcons();
}
@@ -1301,38 +1282,6 @@
+ " any=" + any + " clearable=" + clearable);
}
- if (mFlipSettingsView != null
- && mFlipSettingsView.getVisibility() == View.VISIBLE
- && mStackScroller.getVisibility() != View.VISIBLE) {
- // the flip settings panel is unequivocally showing; we should not be shown
- mClearButton.setVisibility(View.INVISIBLE);
- } else if (mClearButton.isShown()) {
- if (clearable != (mClearButton.getAlpha() == 1.0f)) {
- ObjectAnimator clearAnimation = ObjectAnimator.ofFloat(
- mClearButton, "alpha", clearable ? 1.0f : 0.0f).setDuration(250);
- clearAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mClearButton.getAlpha() <= 0.0f) {
- mClearButton.setVisibility(View.INVISIBLE);
- }
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- if (mClearButton.getAlpha() <= 0.0f) {
- mClearButton.setVisibility(View.VISIBLE);
- }
- }
- });
- clearAnimation.start();
- }
- } else {
- mClearButton.setAlpha(clearable ? 1.0f : 0.0f);
- mClearButton.setVisibility(clearable ? View.VISIBLE : View.INVISIBLE);
- }
- mClearButton.setEnabled(clearable);
-
final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
final boolean showDot = (any&&!areLightsOn());
if (showDot != (nlo.getAlpha() == 1.0f)) {
@@ -1528,7 +1477,7 @@
}
}
- public Handler getHandler() {
+ private Handler getHandler() {
return mHandler;
}
@@ -1571,6 +1520,17 @@
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
}
+ private final Runnable mAnimateCollapsePanels = new Runnable() {
+ @Override
+ public void run() {
+ animateCollapsePanels();
+ }
+ };
+
+ public void postAnimateCollapsePanels() {
+ mHandler.post(mAnimateCollapsePanels);
+ }
+
public void animateCollapsePanels(int flags) {
if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
return;
@@ -1648,7 +1608,7 @@
final int FLIP_DURATION_IN = 225;
final int FLIP_DURATION = (FLIP_DURATION_IN + FLIP_DURATION_OUT);
- Animator mScrollViewAnim, mFlipSettingsViewAnim, mClearButtonAnim;
+ Animator mScrollViewAnim, mClearButtonAnim;
@Override
public void animateExpandNotificationsPanel() {
@@ -1719,7 +1679,6 @@
mStatusBarView.collapseAllPanels(/*animate=*/ false);
// reset things to their proper state
- if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
if (mScrollViewAnim != null) mScrollViewAnim.cancel();
if (mClearButtonAnim != null) mClearButtonAnim.cancel();
@@ -1917,13 +1876,7 @@
private void checkBarModes() {
if (mDemoMode) return;
- int sbMode = mStatusBarMode;
- if (panelsEnabled() && (mInteractingWindows & StatusBarManager.WINDOW_STATUS_BAR) != 0
- && mState != StatusBarState.KEYGUARD) {
- // if panels are expandable, force the status bar opaque on any interaction
- sbMode = MODE_OPAQUE;
- }
- checkBarMode(sbMode, mStatusBarWindowState, mStatusBarView.getBarTransitions());
+ checkBarMode(mStatusBarMode, mStatusBarWindowState, mStatusBarView.getBarTransitions());
if (mNavigationBarView != null) {
checkBarMode(mNavigationBarMode,
mNavigationBarWindowState, mNavigationBarView.getBarTransitions());
@@ -2047,7 +2000,6 @@
}
setNavigationIconHints(flags);
- if (mQS != null) mQS.setImeWindowStatus(vis > 0);
}
@Override
@@ -2446,15 +2398,8 @@
* meantime, just update the things that we know change.
*/
void updateResources() {
- final Context context = mContext;
- final Resources res = context.getResources();
-
- if (mClearButton instanceof TextView) {
- ((TextView)mClearButton).setText(context.getText(R.string.status_bar_clear_all_button));
- }
-
- // Update the QuickSettings container
- if (mQS != null) mQS.updateResources();
+ // Update the quick setting tiles
+ if (mQSPanel != null) mQSPanel.updateResources();
loadDimens();
}
@@ -2613,10 +2558,29 @@
|| (mDisabled & StatusBarManager.DISABLE_SEARCH) != 0;
}
- public void startSettingsActivity(String action) {
- if (mQS != null) {
- mQS.startSettingsActivity(action);
+ public void postStartSettingsActivity(final Intent intent) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ handleStartSettingsActivity(intent, true /*onlyProvisioned*/);
+ }
+ });
+ }
+
+ private void handleStartSettingsActivity(Intent intent, boolean onlyProvisioned) {
+ if (onlyProvisioned && !isDeviceProvisioned()) return;
+ try {
+ // Dismiss the lock screen when Settings starts.
+ ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+ } catch (RemoteException e) {
}
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ animateCollapsePanels();
+ }
+
+ public void startSettingsActivity(String action) {
+ postStartSettingsActivity(new Intent(action));
}
private static class FastColorDrawable extends Drawable {
@@ -2771,22 +2735,19 @@
private void updateKeyguardState() {
if (mState == StatusBarState.KEYGUARD) {
mKeyguardStatusView.setVisibility(View.VISIBLE);
- mKeyguardBottomArea.setVisibility(View.VISIBLE);
mKeyguardIndicationTextView.setVisibility(View.VISIBLE);
mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
- mKeyguardCarrierLabel.setVisibility(View.VISIBLE);
- mNotificationPanelHeader.setVisibility(View.GONE);
-
mNotificationPanel.closeQs();
- mSettingsContainer.setKeyguardShowing(true);
} else {
mKeyguardStatusView.setVisibility(View.GONE);
- mKeyguardBottomArea.setVisibility(View.GONE);
mKeyguardIndicationTextView.setVisibility(View.GONE);
- mKeyguardCarrierLabel.setVisibility(View.GONE);
- mNotificationPanelHeader.setVisibility(View.VISIBLE);
-
- mSettingsContainer.setKeyguardShowing(false);
+ }
+ if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
+ mKeyguardBottomArea.setVisibility(View.VISIBLE);
+ mHeader.setKeyguardShowing(true);
+ } else {
+ mKeyguardBottomArea.setVisibility(View.GONE);
+ mHeader.setKeyguardShowing(false);
}
updateStackScrollerState();
@@ -2807,6 +2768,11 @@
}
}
+ public boolean interceptMediaKey(KeyEvent event) {
+ return mState == StatusBarState.KEYGUARD
+ && mStatusBarKeyguardViewManager.interceptMediaKey(event);
+ }
+
public boolean onMenuPressed() {
return mState == StatusBarState.KEYGUARD && mStatusBarKeyguardViewManager.onMenuPressed();
}
@@ -2913,9 +2879,7 @@
/**
* If secure with redaction: Show bouncer, go to unlocked shade.
*
- * <p>If secure without redaction: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
- *
- * <p>Otherwise go directly to unlocked shade.</p>
+ * <p>If secure without redaction or no security: Go to {@link StatusBarState#SHADE_LOCKED}.</p>
*
* @param expandView The view to expand after going to the shade.
*/
@@ -2927,13 +2891,10 @@
if (isLockscreenPublicMode() && !userAllowsPrivateNotificationsInPublic(mCurrentUserId)) {
mLeaveOpenOnKeyguardHide = true;
showBouncer();
- } else if (mStatusBarKeyguardViewManager.isSecure()) {
+ } else {
mNotificationPanel.animateNextTopPaddingChange();
setBarState(StatusBarState.SHADE_LOCKED);
updateKeyguardState();
- } else {
- mLeaveOpenOnKeyguardHide = true;
- mStatusBarKeyguardViewManager.dismiss();
}
}
@@ -2943,4 +2904,15 @@
public ViewGroup getQuickSettingsOverlayParent() {
return mNotificationPanel;
}
+
+ public LinearLayout getSystemIcons() {
+ return mSystemIcons;
+ }
+
+ /**
+ * Reattaches the system icons to its normal parent in collapsed status bar.
+ */
+ public void reattachSystemIcons() {
+ mSystemIconArea.addView(mSystemIcons, 0);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index e6de057..084bfcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -63,7 +63,7 @@
}
@Override
- public void onAttachedToWindow() {
+ public void onFinishInflate() {
mBarTransitions.init();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
new file mode 100644
index 0000000..1fe3be5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.VectorDrawable;
+import android.os.HandlerThread;
+import android.os.Looper;
+
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.tiles.AirplaneModeTile;
+import com.android.systemui.qs.tiles.BluetoothTile;
+import com.android.systemui.qs.tiles.BugreportTile;
+import com.android.systemui.qs.tiles.CastTile;
+import com.android.systemui.qs.tiles.CellularTile;
+import com.android.systemui.qs.tiles.ColorInversionTile;
+import com.android.systemui.qs.tiles.LocationTile;
+import com.android.systemui.qs.tiles.RingerModeTile;
+import com.android.systemui.qs.tiles.RotationLockTile;
+import com.android.systemui.qs.tiles.HotspotTile;
+import com.android.systemui.qs.tiles.WifiTile;
+import com.android.systemui.qs.tiles.ZenModeTile;
+import com.android.systemui.settings.CurrentUserTracker;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.TetheringController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Platform implementation of the quick settings tile host **/
+public class QSTileHost implements QSTile.Host {
+
+ private final Context mContext;
+ private final PhoneStatusBar mStatusBar;
+ private final BluetoothController mBluetooth;
+ private final LocationController mLocation;
+ private final RotationLockController mRotation;
+ private final NetworkController mNetwork;
+ private final ZenModeController mZen;
+ private final TetheringController mTethering;
+ private final CastController mCast;
+ private final Looper mLooper;
+ private final CurrentUserTracker mUserTracker;
+ private final ArrayList<QSTile<?>> mTiles = new ArrayList<QSTile<?>>();
+
+ public QSTileHost(Context context, PhoneStatusBar statusBar,
+ BluetoothController bluetooth, LocationController location,
+ RotationLockController rotation, NetworkController network,
+ ZenModeController zen, TetheringController tethering,
+ CastController cast) {
+ mContext = context;
+ mStatusBar = statusBar;
+ mBluetooth = bluetooth;
+ mLocation = location;
+ mRotation = rotation;
+ mNetwork = network;
+ mZen = zen;
+ mTethering = tethering;
+ mCast = cast;
+
+ final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName());
+ ht.start();
+ mLooper = ht.getLooper();
+
+ mTiles.add(new WifiTile(this));
+ mTiles.add(new BluetoothTile(this));
+ mTiles.add(new ColorInversionTile(this));
+ mTiles.add(new CellularTile(this));
+ mTiles.add(new AirplaneModeTile(this));
+ mTiles.add(new ZenModeTile(this));
+ mTiles.add(new RingerModeTile(this));
+ mTiles.add(new RotationLockTile(this));
+ mTiles.add(new LocationTile(this));
+ mTiles.add(new CastTile(this));
+ mTiles.add(new HotspotTile(this));
+ mTiles.add(new BugreportTile(this));
+
+ mUserTracker = new CurrentUserTracker(mContext) {
+ @Override
+ public void onUserSwitched(int newUserId) {
+ for (QSTile<?> tile : mTiles) {
+ tile.userSwitch(newUserId);
+ }
+ }
+ };
+ mUserTracker.startTracking();
+ }
+
+ @Override
+ public List<QSTile<?>> getTiles() {
+ return mTiles;
+ }
+
+ @Override
+ public void startSettingsActivity(final Intent intent) {
+ mStatusBar.postStartSettingsActivity(intent);
+ }
+
+ @Override
+ public void warn(String message, Throwable t) {
+ // already logged
+ }
+
+ @Override
+ public void collapsePanels() {
+ mStatusBar.postAnimateCollapsePanels();
+ }
+
+ @Override
+ public Looper getLooper() {
+ return mLooper;
+ }
+
+ @Override
+ public Context getContext() {
+ return mContext;
+ }
+
+ @Override
+ public VectorDrawable getVectorDrawable(int resId) {
+ return (VectorDrawable) mContext.getDrawable(resId);
+ }
+
+ @Override
+ public BluetoothController getBluetoothController() {
+ return mBluetooth;
+ }
+
+ @Override
+ public LocationController getLocationController() {
+ return mLocation;
+ }
+
+ @Override
+ public RotationLockController getRotationLockController() {
+ return mRotation;
+ }
+
+ @Override
+ public NetworkController getNetworkController() {
+ return mNetwork;
+ }
+
+ @Override
+ public ZenModeController getZenModeController() {
+ return mZen;
+ }
+
+ @Override
+ public TetheringController getTetheringController() {
+ return mTethering;
+ }
+
+ @Override
+ public CastController getCastController() {
+ return mCast;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
deleted file mode 100644
index f3ebf1b..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ /dev/null
@@ -1,1127 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.animation.ValueAnimator;
-import android.app.ActivityManagerNative;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.PendingIntent;
-import android.app.admin.DevicePolicyManager;
-import android.bluetooth.BluetoothAdapter;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.UserInfo;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.hardware.display.DisplayManager;
-import android.media.MediaRouter;
-import android.net.wifi.WifiManager;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.AlarmClock;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.Profile;
-import android.provider.Settings;
-import android.security.KeyChain;
-import android.text.TextUtils.TruncateAt;
-import android.util.Log;
-import android.util.Pair;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-import android.view.WindowManager.LayoutParams;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.internal.app.MediaRouteDialogPresenter;
-import com.android.systemui.R;
-import com.android.systemui.settings.UserSwitcherHostView;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.ActivityState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.BluetoothState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.RSSIState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.State;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.UserState;
-import com.android.systemui.statusbar.phone.QuickSettingsModel.WifiState;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RotationLockController;
-
-import java.util.ArrayList;
-
-/**
- *
- */
-class QuickSettings {
- static final boolean DEBUG_GONE_TILES = false;
- private static final String TAG = "QuickSettings";
- public static final boolean SHOW_IME_TILE = false;
- public static final boolean SHOW_ACCESSIBILITY_TILES = true;
-
- public static final boolean LONG_PRESS_TOGGLES = true;
-
- private Context mContext;
- private PanelBar mBar;
- private QuickSettingsModel mModel;
- private ViewGroup mContainerView;
-
- private DevicePolicyManager mDevicePolicyManager;
- private PhoneStatusBar mStatusBarService;
- private BluetoothState mBluetoothState;
- private BluetoothAdapter mBluetoothAdapter;
- private WifiManager mWifiManager;
-
- private BluetoothController mBluetoothController;
- private RotationLockController mRotationLockController;
- private LocationController mLocationController;
-
- private AsyncTask<Void, Void, Pair<String, Drawable>> mUserInfoTask;
- private AsyncTask<Void, Void, Pair<Boolean, Boolean>> mQueryCertTask;
-
- boolean mTilesSetUp = false;
- boolean mUseDefaultAvatar = false;
-
- private Handler mHandler;
-
- // The set of QuickSettingsTiles that have dynamic spans (and need to be updated on
- // configuration change)
- private final ArrayList<QuickSettingsTileView> mDynamicSpannedTiles =
- new ArrayList<QuickSettingsTileView>();
-
- public QuickSettings(Context context, QuickSettingsContainerView container) {
- mDevicePolicyManager
- = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
- mContext = context;
- mContainerView = container;
- mModel = new QuickSettingsModel(context);
- mBluetoothState = new QuickSettingsModel.BluetoothState();
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-
- mHandler = new Handler();
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
- filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
- filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
- mContext.registerReceiver(mReceiver, filter);
-
- IntentFilter profileFilter = new IntentFilter();
- profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED);
- profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
- mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter,
- null, null);
- }
-
- void setBar(PanelBar bar) {
- mBar = bar;
- }
-
- public void setService(PhoneStatusBar phoneStatusBar) {
- mStatusBarService = phoneStatusBar;
- }
-
- public PhoneStatusBar getService() {
- return mStatusBarService;
- }
-
- public void setImeWindowStatus(boolean visible) {
- mModel.onImeWindowStatusChanged(visible);
- }
-
- void setup(NetworkController networkController, BluetoothController bluetoothController,
- BatteryController batteryController, LocationController locationController,
- RotationLockController rotationLockController) {
- mBluetoothController = bluetoothController;
- mRotationLockController = rotationLockController;
- mLocationController = locationController;
-
- setupQuickSettings();
- updateResources();
- applyLocationEnabledStatus();
-
- networkController.addNetworkSignalChangedCallback(mModel);
- bluetoothController.addStateChangedCallback(mModel);
- batteryController.addStateChangedCallback(mModel);
- locationController.addSettingsChangedCallback(mModel);
- if (rotationLockController != null) {
- rotationLockController.addRotationLockControllerCallback(mModel);
- }
- }
-
- private void queryForSslCaCerts() {
- mQueryCertTask = new AsyncTask<Void, Void, Pair<Boolean, Boolean>>() {
- @Override
- protected Pair<Boolean, Boolean> doInBackground(Void... params) {
- boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
- boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
-
- return Pair.create(hasCert, isManaged);
- }
- @Override
- protected void onPostExecute(Pair<Boolean, Boolean> result) {
- super.onPostExecute(result);
- boolean hasCert = result.first;
- boolean isManaged = result.second;
- mModel.setSslCaCertWarningTileInfo(hasCert, isManaged);
- }
- };
- mQueryCertTask.execute();
- }
-
- private void queryForUserInformation() {
- Context currentUserContext = null;
- UserInfo userInfo = null;
- try {
- userInfo = ActivityManagerNative.getDefault().getCurrentUser();
- currentUserContext = mContext.createPackageContextAsUser("android", 0,
- new UserHandle(userInfo.id));
- } catch (NameNotFoundException e) {
- Log.e(TAG, "Couldn't create user context", e);
- throw new RuntimeException(e);
- } catch (RemoteException e) {
- Log.e(TAG, "Couldn't get user info", e);
- }
- final int userId = userInfo.id;
- final String userName = userInfo.name;
-
- final Context context = currentUserContext;
- mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() {
- @Override
- protected Pair<String, Drawable> doInBackground(Void... params) {
- final UserManager um = UserManager.get(mContext);
-
- // Fall back to the UserManager nickname if we can't read the name from the local
- // profile below.
- String name = userName;
- Drawable avatar = null;
- Bitmap rawAvatar = um.getUserIcon(userId);
- if (rawAvatar != null) {
- avatar = new BitmapDrawable(mContext.getResources(), rawAvatar);
- } else {
- avatar = mContext.getResources().getDrawable(R.drawable.ic_qs_default_user);
- mUseDefaultAvatar = true;
- }
-
- // If it's a single-user device, get the profile name, since the nickname is not
- // usually valid
- if (um.getUsers().size() <= 1) {
- // Try and read the display name from the local profile
- final Cursor cursor = context.getContentResolver().query(
- Profile.CONTENT_URI, new String[] {Phone._ID, Phone.DISPLAY_NAME},
- null, null, null);
- if (cursor != null) {
- try {
- if (cursor.moveToFirst()) {
- name = cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME));
- }
- } finally {
- cursor.close();
- }
- }
- }
- return new Pair<String, Drawable>(name, avatar);
- }
-
- @Override
- protected void onPostExecute(Pair<String, Drawable> result) {
- super.onPostExecute(result);
- mModel.setUserTileInfo(result.first, result.second);
- mUserInfoTask = null;
- }
- };
- mUserInfoTask.execute();
- }
-
- private void setupQuickSettings() {
- // Setup the tiles that we are going to be showing (including the temporary ones)
- LayoutInflater inflater = LayoutInflater.from(mContext);
-
- addUserTiles(mContainerView, inflater);
- addSystemTiles(mContainerView, inflater);
- addTemporaryTiles(mContainerView, inflater);
- addAccessibilityTiles(mContainerView);
-
- queryForUserInformation();
- queryForSslCaCerts();
- mTilesSetUp = true;
- }
-
- public void startSettingsActivity(String action) {
- Intent intent = new Intent(action);
- startSettingsActivity(intent);
- }
-
- private void startSettingsActivity(Intent intent) {
- startSettingsActivity(intent, true);
- }
-
- private void collapsePanels() {
- getService().animateCollapsePanels();
- }
-
- private void startSettingsActivity(Intent intent, boolean onlyProvisioned) {
- if (onlyProvisioned && !getService().isDeviceProvisioned()) return;
- try {
- // Dismiss the lock screen when Settings starts.
- ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
- } catch (RemoteException e) {
- }
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
- collapsePanels();
- }
-
- private void addAccessibilityTiles(ViewGroup parent) {
- if (!DEBUG_GONE_TILES && !SHOW_ACCESSIBILITY_TILES) return;
-
- // Color inversion tile
- final SystemSettingTile inversionTile = new SystemSettingTile(mContext);
- inversionTile.setUri(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
- SystemSettingTile.TYPE_SECURE);
- inversionTile.setFragment("Settings$AccessibilityInversionSettingsActivity");
- mModel.addInversionTile(inversionTile, inversionTile.getRefreshCallback());
- parent.addView(inversionTile);
-
- // Contrast enhancement tile
- final SystemSettingTile contrastTile = new SystemSettingTile(mContext);
- contrastTile.setUri(Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED,
- SystemSettingTile.TYPE_SECURE);
- contrastTile.setFragment("Settings$AccessibilityContrastSettingsActivity");
- mModel.addContrastTile(contrastTile, contrastTile.getRefreshCallback());
- parent.addView(contrastTile);
-
- // Color space adjustment tile
- final SystemSettingTile colorSpaceTile = new SystemSettingTile(mContext);
- colorSpaceTile.setUri(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
- SystemSettingTile.TYPE_SECURE);
- colorSpaceTile.setFragment("Settings$AccessibilityDaltonizerSettingsActivity");
- mModel.addColorSpaceTile(colorSpaceTile, colorSpaceTile.getRefreshCallback());
- parent.addView(colorSpaceTile);
- }
-
- private void addUserTiles(final ViewGroup parent, final LayoutInflater inflater) {
- QuickSettingsTileView userTile = (QuickSettingsTileView)
- inflater.inflate(R.layout.quick_settings_tile, parent, false);
- userTile.setContent(R.layout.quick_settings_tile_user, inflater);
- userTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- final UserManager um = UserManager.get(mContext);
- if (um.isUserSwitcherEnabled()) {
- final ViewGroup switcherParent = getService().getQuickSettingsOverlayParent();
- final UserSwitcherHostView switcher = (UserSwitcherHostView) inflater.inflate(
- R.layout.user_switcher_host, switcherParent, false);
- switcher.setFinishRunnable(new Runnable() {
- @Override
- public void run() {
- switcherParent.removeView(switcher);
- }
- });
- switcher.refreshUsers();
- switcherParent.addView(switcher);
- } else {
- collapsePanels();
- Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
- mContext, v, ContactsContract.Profile.CONTENT_URI,
- ContactsContract.QuickContact.MODE_LARGE, null);
- mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
- }
- }
- });
- mModel.addUserTile(userTile, new QuickSettingsModel.RefreshCallback() {
- @Override
- public void refreshView(QuickSettingsTileView view, State state) {
- UserState us = (UserState) state;
- ImageView iv = (ImageView) view.findViewById(R.id.user_imageview);
- TextView tv = (TextView) view.findViewById(R.id.user_textview);
- tv.setText(state.label);
- iv.setImageDrawable(us.avatar);
- view.setContentDescription(mContext.getString(
- R.string.accessibility_quick_settings_user, state.label));
- }
- });
- parent.addView(userTile);
- mDynamicSpannedTiles.add(userTile);
-
- // Brightness
- final QuickSettingsBasicTile brightnessTile
- = new QuickSettingsBasicTile(mContext);
- brightnessTile.setImageResource(R.drawable.ic_qs_brightness_auto_off);
- brightnessTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- collapsePanels();
- showBrightnessDialog();
- }
- });
- mModel.addBrightnessTile(brightnessTile,
- new QuickSettingsModel.BasicRefreshCallback(brightnessTile));
- parent.addView(brightnessTile);
- mDynamicSpannedTiles.add(brightnessTile);
-
- // Settings tile
- final QuickSettingsBasicTile settingsTile = new QuickSettingsBasicTile(mContext);
- settingsTile.setImageResource(R.drawable.ic_qs_settings);
- settingsTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- startSettingsActivity(android.provider.Settings.ACTION_SETTINGS);
- }
- });
- mModel.addSettingsTile(settingsTile,
- new QuickSettingsModel.BasicRefreshCallback(settingsTile));
- parent.addView(settingsTile);
- mDynamicSpannedTiles.add(settingsTile);
- }
-
- private void addSystemTiles(ViewGroup parent, LayoutInflater inflater) {
- // Wi-fi
- final QuickSettingsTileView wifiTile = (QuickSettingsTileView)
- inflater.inflate(R.layout.quick_settings_tile, parent, false);
- wifiTile.setContent(R.layout.quick_settings_tile_wifi, inflater);
- wifiTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- startSettingsActivity(android.provider.Settings.ACTION_WIFI_SETTINGS);
- }
- });
- if (LONG_PRESS_TOGGLES) {
- wifiTile.setOnLongClickListener(new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- final boolean enable =
- (mWifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLED);
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... args) {
- // Disable tethering if enabling Wifi
- final int wifiApState = mWifiManager.getWifiApState();
- if (enable && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
- (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
- mWifiManager.setWifiApEnabled(null, false);
- }
-
- mWifiManager.setWifiEnabled(enable);
- return null;
- }
- }.execute();
- wifiTile.setPressed(false);
- return true;
- }} );
- }
- mModel.addWifiTile(wifiTile, new NetworkActivityCallback() {
- @Override
- public void refreshView(QuickSettingsTileView view, State state) {
- WifiState wifiState = (WifiState) state;
- ImageView iv = (ImageView) view.findViewById(R.id.image);
- iv.setImageResource(wifiState.iconId);
- setActivity(view, wifiState);
- TextView tv = (TextView) view.findViewById(R.id.text);
- tv.setText(wifiState.label);
- wifiTile.setContentDescription(mContext.getString(
- R.string.accessibility_quick_settings_wifi,
- wifiState.signalContentDescription,
- (wifiState.connected) ? wifiState.label : ""));
- }
- });
- parent.addView(wifiTile);
-
- if (mModel.deviceHasMobileData()) {
- // RSSI
- QuickSettingsTileView rssiTile = (QuickSettingsTileView)
- inflater.inflate(R.layout.quick_settings_tile, parent, false);
- rssiTile.setContent(R.layout.quick_settings_tile_rssi, inflater);
- rssiTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent();
- intent.setComponent(new ComponentName(
- "com.android.settings",
- "com.android.settings.Settings$DataUsageSummaryActivity"));
- startSettingsActivity(intent);
- }
- });
- mModel.addRSSITile(rssiTile, new NetworkActivityCallback() {
- @Override
- public void refreshView(QuickSettingsTileView view, State state) {
- RSSIState rssiState = (RSSIState) state;
- ImageView iv = (ImageView) view.findViewById(R.id.rssi_image);
- ImageView iov = (ImageView) view.findViewById(R.id.rssi_overlay_image);
- TextView tv = (TextView) view.findViewById(R.id.rssi_textview);
- // Force refresh
- iv.setImageDrawable(null);
- iv.setImageResource(rssiState.signalIconId);
-
- if (rssiState.dataTypeIconId > 0) {
- iov.setImageResource(rssiState.dataTypeIconId);
- } else {
- iov.setImageDrawable(null);
- }
- setActivity(view, rssiState);
-
- tv.setText(state.label);
- view.setContentDescription(mContext.getResources().getString(
- R.string.accessibility_quick_settings_mobile,
- rssiState.signalContentDescription, rssiState.dataContentDescription,
- state.label));
- }
- });
- parent.addView(rssiTile);
- }
-
- // Rotation Lock
- if (mRotationLockController != null) {
- final QuickSettingsBasicTile rotationLockTile
- = new QuickSettingsBasicTile(mContext);
- rotationLockTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- final boolean locked = mRotationLockController.isRotationLocked();
- mRotationLockController.setRotationLocked(!locked);
- }
- });
- mModel.addRotationLockTile(rotationLockTile, mRotationLockController,
- new QuickSettingsModel.RefreshCallback() {
- @Override
- public void refreshView(QuickSettingsTileView view, State state) {
- QuickSettingsModel.RotationLockState rotationLockState =
- (QuickSettingsModel.RotationLockState) state;
- view.setVisibility(rotationLockState.visible
- ? View.VISIBLE : View.GONE);
- if (state.iconId != 0) {
- // needed to flush any cached IDs
- rotationLockTile.setImageDrawable(null);
- rotationLockTile.setImageResource(state.iconId);
- }
- if (state.label != null) {
- rotationLockTile.setText(state.label);
- }
- }
- });
- parent.addView(rotationLockTile);
- }
-
- // Battery
- final QuickSettingsTileView batteryTile = (QuickSettingsTileView)
- inflater.inflate(R.layout.quick_settings_tile, parent, false);
- batteryTile.setContent(R.layout.quick_settings_tile_battery, inflater);
- batteryTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- startSettingsActivity(Intent.ACTION_POWER_USAGE_SUMMARY);
- }
- });
- mModel.addBatteryTile(batteryTile, new QuickSettingsModel.RefreshCallback() {
- @Override
- public void refreshView(QuickSettingsTileView unused, State state) {
- QuickSettingsModel.BatteryState batteryState =
- (QuickSettingsModel.BatteryState) state;
- String t;
- if (batteryState.batteryLevel == 100) {
- t = mContext.getString(R.string.quick_settings_battery_charged_label);
- } else {
- t = batteryState.pluggedIn
- ? mContext.getString(R.string.quick_settings_battery_charging_label,
- batteryState.batteryLevel)
- : mContext.getString(R.string.status_bar_settings_battery_meter_format,
- batteryState.batteryLevel);
- }
- ((TextView)batteryTile.findViewById(R.id.text)).setText(t);
- batteryTile.setContentDescription(
- mContext.getString(R.string.accessibility_quick_settings_battery, t));
- }
- });
- parent.addView(batteryTile);
-
- // Bluetooth
- if (mModel.deviceSupportsBluetooth()
- || DEBUG_GONE_TILES) {
- final QuickSettingsBasicTile bluetoothTile
- = new QuickSettingsBasicTile(mContext);
- bluetoothTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- startSettingsActivity(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS);
- }
- });
- if (LONG_PRESS_TOGGLES) {
- bluetoothTile.setOnLongClickListener(new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- if (mBluetoothAdapter.isEnabled()) {
- mBluetoothAdapter.disable();
- } else {
- mBluetoothAdapter.enable();
- }
- bluetoothTile.setPressed(false);
- return true;
- }});
- }
- mModel.addBluetoothTile(bluetoothTile, new QuickSettingsModel.RefreshCallback() {
- @Override
- public void refreshView(QuickSettingsTileView unused, State state) {
- BluetoothState bluetoothState = (BluetoothState) state;
- bluetoothTile.setImageResource(state.iconId);
-
- /*
- Resources r = mContext.getResources();
- //TODO: Show connected bluetooth device label
- Set<BluetoothDevice> btDevices =
- mBluetoothController.getBondedBluetoothDevices();
- if (btDevices.size() == 1) {
- // Show the name of the bluetooth device you are connected to
- label = btDevices.iterator().next().getName();
- } else if (btDevices.size() > 1) {
- // Show a generic label about the number of bluetooth devices
- label = r.getString(R.string.quick_settings_bluetooth_multiple_devices_label,
- btDevices.size());
- }
- */
- bluetoothTile.setContentDescription(mContext.getString(
- R.string.accessibility_quick_settings_bluetooth,
- bluetoothState.stateContentDescription));
- bluetoothTile.setText(state.label);
- }
- });
- parent.addView(bluetoothTile);
- }
-
- // Location
- final QuickSettingsBasicTile locationTile
- = new QuickSettingsBasicTile(mContext);
- locationTile.setImageResource(R.drawable.ic_qs_location_on);
- locationTile.setTextResource(R.string.quick_settings_location_label);
- locationTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- startSettingsActivity(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
- }
- });
- if (LONG_PRESS_TOGGLES) {
- locationTile.setOnLongClickListener(new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- boolean newLocationEnabledState = !mLocationController.isLocationEnabled();
- if (mLocationController.setLocationEnabled(newLocationEnabledState)
- && newLocationEnabledState) {
- // If we've successfully switched from location off to on, close the
- // notifications tray to show the network location provider consent dialog.
- Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- mContext.sendBroadcast(closeDialog);
- }
- return true; // Consume click
- }} );
- }
- mModel.addLocationTile(locationTile, new QuickSettingsModel.RefreshCallback() {
- @Override
- public void refreshView(QuickSettingsTileView unused, State state) {
- locationTile.setImageResource(state.iconId);
- String locationState = mContext.getString(
- (state.enabled) ? R.string.accessibility_desc_on
- : R.string.accessibility_desc_off);
- locationTile.setContentDescription(mContext.getString(
- R.string.accessibility_quick_settings_location,
- locationState));
- locationTile.setText(state.label);
- }
- });
- parent.addView(locationTile);
-
- // Airplane Mode
- final QuickSettingsBasicTile airplaneTile
- = new QuickSettingsBasicTile(mContext);
- mModel.addAirplaneModeTile(airplaneTile, new QuickSettingsModel.RefreshCallback() {
- @Override
- public void refreshView(QuickSettingsTileView unused, State state) {
- airplaneTile.setImageResource(state.iconId);
-
- String airplaneState = mContext.getString(
- (state.enabled) ? R.string.accessibility_desc_on
- : R.string.accessibility_desc_off);
- airplaneTile.setContentDescription(
- mContext.getString(R.string.accessibility_quick_settings_airplane,
- airplaneState));
- airplaneTile.setText(state.label);
- }
- });
- parent.addView(airplaneTile);
-
- // Zen Mode
- final QuickSettingsBasicTile zenModeTile = new QuickSettingsBasicTile(mContext);
- zenModeTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- showZenModeDialog();
- }
- });
- mModel.addZenModeTile(zenModeTile, new QuickSettingsModel.RefreshCallback() {
- @Override
- public void refreshView(QuickSettingsTileView unused, State state) {
- zenModeTile.setImageResource(state.iconId);
- // TODO cut new assets
- zenModeTile.getImageView().setAlpha(state.enabled ? 1 : .2f);
- zenModeTile.getImageView().setScaleX(1.5f);
- zenModeTile.getImageView().setScaleY(1.5f);
- // for landscape version
- zenModeTile.getTextView().setMaxLines(2);
- zenModeTile.getTextView().setEllipsize(TruncateAt.END);
- // TODO content description
- zenModeTile.setText(state.label);
- }
- });
- parent.addView(zenModeTile);
- }
-
- private void addTemporaryTiles(final ViewGroup parent, final LayoutInflater inflater) {
- // Alarm tile
- final QuickSettingsBasicTile alarmTile
- = new QuickSettingsBasicTile(mContext);
- alarmTile.setImageResource(R.drawable.ic_qs_alarm_on);
- alarmTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- startSettingsActivity(AlarmClock.ACTION_SHOW_ALARMS);
- }
- });
- mModel.addAlarmTile(alarmTile, new QuickSettingsModel.RefreshCallback() {
- @Override
- public void refreshView(QuickSettingsTileView unused, State alarmState) {
- alarmTile.setText(alarmState.label);
- alarmTile.setVisibility(alarmState.enabled ? View.VISIBLE : View.GONE);
- alarmTile.setContentDescription(mContext.getString(
- R.string.accessibility_quick_settings_alarm, alarmState.label));
- }
- });
- parent.addView(alarmTile);
-
- // Remote Display
- QuickSettingsBasicTile remoteDisplayTile
- = new QuickSettingsBasicTile(mContext);
- remoteDisplayTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- collapsePanels();
-
- final Dialog[] dialog = new Dialog[1];
- dialog[0] = MediaRouteDialogPresenter.createDialog(mContext,
- MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
- new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- dialog[0].dismiss();
- startSettingsActivity(
- android.provider.Settings.ACTION_WIFI_DISPLAY_SETTINGS);
- }
- });
- dialog[0].getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
- dialog[0].show();
- }
- });
- mModel.addRemoteDisplayTile(remoteDisplayTile,
- new QuickSettingsModel.BasicRefreshCallback(remoteDisplayTile)
- .setShowWhenEnabled(true));
- parent.addView(remoteDisplayTile);
-
- if (SHOW_IME_TILE || DEBUG_GONE_TILES) {
- // IME
- final QuickSettingsBasicTile imeTile
- = new QuickSettingsBasicTile(mContext);
- imeTile.setImageResource(R.drawable.ic_qs_ime);
- imeTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- try {
- collapsePanels();
- Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
- PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
- pendingIntent.send();
- } catch (Exception e) {}
- }
- });
- mModel.addImeTile(imeTile,
- new QuickSettingsModel.BasicRefreshCallback(imeTile)
- .setShowWhenEnabled(true));
- parent.addView(imeTile);
- }
-
- // Bug reports
- final QuickSettingsBasicTile bugreportTile
- = new QuickSettingsBasicTile(mContext);
- bugreportTile.setImageResource(com.android.internal.R.drawable.stat_sys_adb);
- bugreportTile.setTextResource(com.android.internal.R.string.bugreport_title);
- bugreportTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- collapsePanels();
- showBugreportDialog();
- }
- });
- mModel.addBugreportTile(bugreportTile, new QuickSettingsModel.RefreshCallback() {
- @Override
- public void refreshView(QuickSettingsTileView view, State state) {
- view.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
- }
- });
- parent.addView(bugreportTile);
- /*
- QuickSettingsTileView mediaTile = (QuickSettingsTileView)
- inflater.inflate(R.layout.quick_settings_tile, parent, false);
- mediaTile.setContent(R.layout.quick_settings_tile_media, inflater);
- parent.addView(mediaTile);
- QuickSettingsTileView imeTile = (QuickSettingsTileView)
- inflater.inflate(R.layout.quick_settings_tile, parent, false);
- imeTile.setContent(R.layout.quick_settings_tile_ime, inflater);
- imeTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- parent.removeViewAt(0);
- }
- });
- parent.addView(imeTile);
- */
-
- // SSL CA Cert Warning.
- final QuickSettingsBasicTile sslCaCertWarningTile =
- new QuickSettingsBasicTile(mContext, null, R.layout.quick_settings_tile_monitoring);
- sslCaCertWarningTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- collapsePanels();
- startSettingsActivity(Settings.ACTION_MONITORING_CERT_INFO);
- }
- });
-
- sslCaCertWarningTile.setImageResource(
- com.android.internal.R.drawable.indicator_input_error);
- sslCaCertWarningTile.setTextResource(R.string.ssl_ca_cert_warning);
-
- mModel.addSslCaCertWarningTile(sslCaCertWarningTile,
- new QuickSettingsModel.BasicRefreshCallback(sslCaCertWarningTile)
- .setShowWhenEnabled(true));
- parent.addView(sslCaCertWarningTile);
- }
-
- void updateResources() {
- Resources r = mContext.getResources();
-
- // Update the model
- mModel.updateResources();
-
- // Update the User, Time, and Settings tiles spans, and reset everything else
- int span = r.getInteger(R.integer.quick_settings_user_time_settings_tile_span);
- for (QuickSettingsTileView v : mDynamicSpannedTiles) {
- v.setColumnSpan(span);
- }
- ((QuickSettingsContainerView)mContainerView).updateResources();
- mContainerView.requestLayout();
- }
-
-
- private void showBrightnessDialog() {
- Intent intent = new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG);
- mContext.sendBroadcast(intent);
- }
-
- private void showBugreportDialog() {
- final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
- builder.setPositiveButton(com.android.internal.R.string.report, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- // Add a little delay before executing, to give the
- // dialog a chance to go away before it takes a
- // screenshot.
- mHandler.postDelayed(new Runnable() {
- @Override public void run() {
- try {
- ActivityManagerNative.getDefault()
- .requestBugReport();
- } catch (RemoteException e) {
- }
- }
- }, 500);
- }
- }
- });
- builder.setMessage(com.android.internal.R.string.bugreport_message);
- builder.setTitle(com.android.internal.R.string.bugreport_title);
- builder.setCancelable(true);
- final Dialog dialog = builder.create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
- try {
- WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
- } catch (RemoteException e) {
- }
- dialog.show();
- }
-
- private void showZenModeDialog() {
- final Dialog d = new Dialog(mContext);
- d.requestWindowFeature(Window.FEATURE_NO_TITLE);
- d.setCancelable(true);
- d.setCanceledOnTouchOutside(true);
- final ZenModeView v = new ZenModeView(mContext) {
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- WindowManager.LayoutParams lp = d.getWindow().getAttributes();
- lp.width = mContext.getResources()
- .getDimensionPixelSize(R.dimen.zen_mode_dialog_width);
- d.getWindow().setAttributes(lp);
- }
- };
- v.setAutoActivate(true);
- v.setAdapter(new ZenModeViewAdapter(mContext) {
- @Override
- public void configure() {
- if (mStatusBarService != null) {
- mStatusBarService.startSettingsActivity(Settings.ACTION_ZEN_MODE_SETTINGS);
- }
- d.dismiss();
- }
- @Override
- public void close() {
- d.dismiss();
- }
- });
- d.setContentView(v);
- d.create();
- d.getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
- WindowManager.LayoutParams lp = d.getWindow().getAttributes();
- lp.width = mContext.getResources().getDimensionPixelSize(R.dimen.zen_mode_dialog_width);
- d.getWindow().setAttributes(lp);
- d.show();
- }
-
- private void applyBluetoothStatus() {
- mModel.onBluetoothStateChange(mBluetoothState);
- }
-
- private void applyLocationEnabledStatus() {
- mModel.onLocationSettingsChanged(mLocationController.isLocationEnabled());
- }
-
- void reloadUserInfo() {
- if (mUserInfoTask != null) {
- mUserInfoTask.cancel(false);
- mUserInfoTask = null;
- }
- if (mTilesSetUp) {
- queryForUserInformation();
- queryForSslCaCerts();
- }
- }
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
- int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
- BluetoothAdapter.ERROR);
- mBluetoothState.enabled = (state == BluetoothAdapter.STATE_ON);
- applyBluetoothStatus();
- } else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
- int status = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
- BluetoothAdapter.STATE_DISCONNECTED);
- mBluetoothState.connected = (status == BluetoothAdapter.STATE_CONNECTED);
- applyBluetoothStatus();
- } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- reloadUserInfo();
- } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
- if (mUseDefaultAvatar) {
- queryForUserInformation();
- }
- } else if (KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
- queryForSslCaCerts();
- }
- }
- };
-
- private final BroadcastReceiver mProfileReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) ||
- Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
- try {
- final int currentUser = ActivityManagerNative.getDefault().getCurrentUser().id;
- final int changedUser =
- intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId());
- if (changedUser == currentUser) {
- reloadUserInfo();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Couldn't get current user id for profile change", e);
- }
- }
-
- }
- };
-
- private abstract static class NetworkActivityCallback
- implements QuickSettingsModel.RefreshCallback {
- private final long mDefaultDuration = new ValueAnimator().getDuration();
- private final long mShortDuration = mDefaultDuration / 3;
-
- public void setActivity(View view, ActivityState state) {
- setVisibility(view.findViewById(R.id.activity_in), state.activityIn);
- setVisibility(view.findViewById(R.id.activity_out), state.activityOut);
- }
-
- private void setVisibility(View view, boolean visible) {
- final float newAlpha = visible ? 1 : 0;
- if (view.getAlpha() != newAlpha) {
- view.animate()
- .setDuration(visible ? mShortDuration : mDefaultDuration)
- .alpha(newAlpha)
- .start();
- }
- }
- }
-
- /**
- * Quick Setting tile that represents a secure setting. This type of tile
- * can toggle a URI within Settings.Secure on click and launch a Settings
- * fragment on long-click.
- */
- public class SystemSettingTile extends QuickSettingsBasicTile {
- private static final int TYPE_GLOBAL = 0;
- private static final int TYPE_SECURE = 1;
- private static final int TYPE_SYSTEM = 2;
-
- private final QuickSettingsModel.BasicRefreshCallback mRefreshCallback;
-
- private String mFragment;
- private String mName;
- private int mType;
-
- public SystemSettingTile(Context context) {
- super(context);
-
- mRefreshCallback = new QuickSettingsModel.BasicRefreshCallback(this);
- mRefreshCallback.setShowWhenEnabled(true);
- }
-
- @Override
- public boolean performLongClick() {
- if (mFragment != null) {
- collapsePanels();
-
- final Intent intent = new Intent();
- intent.setComponent(new ComponentName(
- "com.android.settings", "com.android.settings." + mFragment));
- startSettingsActivity(intent);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean performClick() {
- if (mName != null) {
- collapsePanels();
-
- final ContentResolver cr = mContext.getContentResolver();
- switch (mType) {
- case TYPE_GLOBAL: {
- final boolean enable = Settings.Global.getInt(cr, mName, 0) == 0;
- Settings.Global.putInt(cr, mName, enable ? 1 : 0);
- } break;
- case TYPE_SECURE: {
- final boolean enable = Settings.Secure.getIntForUser(
- cr, mName, 0, UserHandle.USER_CURRENT) == 0;
- Settings.Secure.putIntForUser(
- cr, mName, enable ? 1 : 0, UserHandle.USER_CURRENT);
- } break;
- case TYPE_SYSTEM: {
- final boolean enable = Settings.System.getIntForUser(
- cr, mName, 0, UserHandle.USER_CURRENT) == 0;
- Settings.System.putIntForUser(
- cr, mName, enable ? 1 : 0, UserHandle.USER_CURRENT);
- } break;
- }
- return true;
- }
- return false;
- }
-
- /**
- * Specifies the fragment within the com.android.settings package to
- * launch when this tile is long-clicked.
- *
- * @param fragment a fragment name within the com.android.settings
- * package
- */
- public void setFragment(String fragment) {
- mFragment = fragment;
- setLongClickable(fragment != null);
- }
-
- /**
- * Specifies the setting name and type to toggle when this tile is
- * clicked.
- *
- * @param name a setting name
- * @param type the type of setting, one of:
- * <ul>
- * <li>{@link #TYPE_GLOBAL}
- * <li>{@link #TYPE_SECURE}
- * <li>{@link #TYPE_SYSTEM}
- * </ul>
- */
- public void setUri(String name, int type) {
- mName = name;
- mType = type;
- setClickable(mName != null);
- }
-
- /**
- * @return the refresh callback for this tile
- */
- public QuickSettingsModel.BasicRefreshCallback getRefreshCallback() {
- return mRefreshCallback;
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java
deleted file mode 100644
index 099780c..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsBasicTile.java
+++ /dev/null
@@ -1,85 +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.systemui.statusbar.phone;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-
-class QuickSettingsBasicTile extends QuickSettingsTileView {
- private final TextView mTextView;
- private final ImageView mImageView;
-
- public QuickSettingsBasicTile(Context context) {
- this(context, null);
- }
-
- public QuickSettingsBasicTile(Context context, AttributeSet attrs) {
- this(context, attrs, R.layout.quick_settings_tile_basic);
- }
-
- public QuickSettingsBasicTile(Context context, AttributeSet attrs, int layoutId) {
- super(context, attrs);
-
- setLayoutParams(new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.MATCH_PARENT,
- context.getResources().getDimensionPixelSize(R.dimen.quick_settings_cell_height)
- ));
- setBackgroundResource(R.drawable.qs_tile_background);
- addView(LayoutInflater.from(context).inflate(layoutId, null),
- new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.MATCH_PARENT,
- FrameLayout.LayoutParams.MATCH_PARENT));
- mTextView = (TextView) findViewById(R.id.text);
- mImageView = (ImageView) findViewById(R.id.image);
- }
-
- @Override
- void setContent(int layoutId, LayoutInflater inflater) {
- throw new RuntimeException("why?");
- }
-
- public ImageView getImageView() {
- return mImageView;
- }
-
- public TextView getTextView() {
- return mTextView;
- }
-
- public void setImageDrawable(Drawable drawable) {
- mImageView.setImageDrawable(drawable);
- }
-
- public void setImageResource(int resId) {
- mImageView.setImageResource(resId);
- }
-
- public void setText(CharSequence text) {
- mTextView.setText(text);
- }
-
- public void setTextResource(int resId) {
- mTextView.setText(resId);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java
deleted file mode 100644
index c44cb0c..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.animation.LayoutTransition;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import com.android.systemui.R;
-
-/**
- *
- */
-class QuickSettingsContainerView extends FrameLayout {
-
- private static boolean sShowScrim = true;
-
- private final Context mContext;
-
- // The number of columns in the QuickSettings grid
- private int mNumColumns;
-
- private boolean mKeyguardShowing;
- private int mMaxRows;
- private int mMaxRowsOnKeyguard;
-
- // The gap between tiles in the QuickSettings grid
- private float mCellGap;
-
- private ScrimView mScrim;
-
- public QuickSettingsContainerView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mContext = context;
- updateResources();
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- if (sShowScrim) {
- mScrim = new ScrimView(mContext);
- addView(mScrim);
- }
- // TODO: Setup the layout transitions
- LayoutTransition transitions = getLayoutTransition();
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (mScrim != null) {
- sShowScrim = false;
- removeView(mScrim);
- }
- return super.onTouchEvent(event);
- }
-
- void updateResources() {
- Resources r = getContext().getResources();
- mCellGap = r.getDimension(R.dimen.quick_settings_cell_gap);
- mNumColumns = r.getInteger(R.integer.quick_settings_num_columns);
- mMaxRows = r.getInteger(R.integer.quick_settings_max_rows);
- mMaxRowsOnKeyguard = r.getInteger(R.integer.quick_settings_max_rows_keyguard);
- requestLayout();
- }
-
- void setKeyguardShowing(boolean showing) {
- mKeyguardShowing = showing;
- requestLayout();
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // Calculate the cell width dynamically
- int width = MeasureSpec.getSize(widthMeasureSpec);
- int height = MeasureSpec.getSize(heightMeasureSpec);
- int availableWidth = (int) (width - getPaddingLeft() - getPaddingRight() -
- (mNumColumns - 1) * mCellGap);
- float cellWidth = (float) Math.ceil(((float) availableWidth) / mNumColumns);
-
- // Update each of the children's widths accordingly to the cell width
- final int N = getChildCount();
- int cellHeight = 0;
- int cursor = 0;
- int maxRows = mKeyguardShowing ? mMaxRowsOnKeyguard : mMaxRows;
-
- for (int i = 0; i < N; ++i) {
- if (getChildAt(i).equals(mScrim)) {
- continue;
- }
- // Update the child's width
- QuickSettingsTileView v = (QuickSettingsTileView) getChildAt(i);
- if (v.getVisibility() != View.GONE) {
- int row = (int) (cursor / mNumColumns);
- if (row >= maxRows) continue;
-
- ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
- int colSpan = v.getColumnSpan();
- lp.width = (int) ((colSpan * cellWidth) + (colSpan - 1) * mCellGap);
-
- // Measure the child
- int newWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
- int newHeightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
- v.measure(newWidthSpec, newHeightSpec);
-
- // Save the cell height
- if (cellHeight <= 0) {
- cellHeight = v.getMeasuredHeight();
- }
- cursor += colSpan;
- }
- }
-
- // Set the measured dimensions. We always fill the tray width, but wrap to the height of
- // all the tiles.
- int numRows = (int) Math.ceil((float) cursor / mNumColumns);
- int newHeight = (int) ((numRows * cellHeight) + ((numRows - 1) * mCellGap)) +
- getPaddingTop() + getPaddingBottom();
- setMeasuredDimension(width, newHeight);
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- if (mScrim != null) {
- mScrim.bringToFront();
- }
- final int N = getChildCount();
- final boolean isLayoutRtl = isLayoutRtl();
- final int width = getWidth();
-
- int x = getPaddingStart();
- int y = getPaddingTop();
- int cursor = 0;
- int maxRows = mKeyguardShowing ? mMaxRowsOnKeyguard : mMaxRows;
-
- for (int i = 0; i < N; ++i) {
- if (getChildAt(i).equals(mScrim)) {
- int w = right - left - getPaddingLeft() - getPaddingRight();
- int h = bottom - top - getPaddingTop() - getPaddingBottom();
- mScrim.measure(
- MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY));
- mScrim.layout(getPaddingLeft(), getPaddingTop(), right, bottom);
- continue;
- }
- QuickSettingsTileView child = (QuickSettingsTileView) getChildAt(i);
- ViewGroup.LayoutParams lp = child.getLayoutParams();
- if (child.getVisibility() != GONE) {
- final int col = cursor % mNumColumns;
- final int colSpan = child.getColumnSpan();
-
- final int childWidth = lp.width;
- final int childHeight = lp.height;
-
- int row = (int) (cursor / mNumColumns);
- if (row >= maxRows) continue;
-
- // Push the item to the next row if it can't fit on this one
- if ((col + colSpan) > mNumColumns) {
- x = getPaddingStart();
- y += childHeight + mCellGap;
- row++;
- }
-
- final int childLeft = (isLayoutRtl) ? width - x - childWidth : x;
- final int childRight = childLeft + childWidth;
-
- final int childTop = y;
- final int childBottom = childTop + childHeight;
-
- // Layout the container
- child.layout(childLeft, childTop, childRight, childBottom);
-
- // Offset the position by the cell gap or reset the position and cursor when we
- // reach the end of the row
- cursor += child.getColumnSpan();
- if (cursor < (((row + 1) * mNumColumns))) {
- x += childWidth + mCellGap;
- } else {
- x = getPaddingStart();
- y += childHeight + mCellGap;
- }
- }
- }
- }
-
- private static final class ScrimView extends View {
- private static final int SCRIM = 0x4f000000;
- private static final int COLOR = 0xaf4285f4;
-
- private final Paint mLinePaint;
- private final int mStrokeWidth;
- private final Rect mTmp = new Rect();
- private final Paint mTextPaint;
- private final int mTextSize;
-
- public ScrimView(Context context) {
- super(context);
- setFocusable(false);
- final Resources res = context.getResources();
- mStrokeWidth = res.getDimensionPixelSize(R.dimen.quick_settings_tmp_scrim_stroke_width);
- mTextSize = res.getDimensionPixelSize(R.dimen.quick_settings_tmp_scrim_text_size);
-
- mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mLinePaint.setColor(COLOR);
- mLinePaint.setStrokeWidth(mStrokeWidth);
- mLinePaint.setStrokeJoin(Paint.Join.ROUND);
- mLinePaint.setStrokeCap(Paint.Cap.ROUND);
- mLinePaint.setStyle(Paint.Style.STROKE);
-
- mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mTextPaint.setColor(COLOR);
- mTextPaint.setTextSize(mTextSize);
- mTextPaint.setTypeface(Typeface.create("sans-serif-condensed", Typeface.BOLD));
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- final int w = getMeasuredWidth();
- final int h = getMeasuredHeight();
- final int f = mStrokeWidth * 3 / 4;
-
- canvas.drawColor(SCRIM);
- canvas.drawPath(line(f, h / 2, w - f, h / 2), mLinePaint);
- canvas.drawPath(line(w / 2, f, w / 2, h - f), mLinePaint);
-
- final int s = mStrokeWidth;
- mTextPaint.setTextAlign(Paint.Align.RIGHT);
- canvas.drawText("FUTURE", w / 2 - s, h / 2 - s, mTextPaint);
- mTextPaint.setTextAlign(Paint.Align.LEFT);
- canvas.drawText("SITE OF", w / 2 + s, h / 2 - s , mTextPaint);
- mTextPaint.setTextAlign(Paint.Align.RIGHT);
- drawUnder(canvas, "QUANTUM", w / 2 - s, h / 2 + s);
- mTextPaint.setTextAlign(Paint.Align.LEFT);
- drawUnder(canvas, "SETTINGS", w / 2 + s, h / 2 + s);
- }
-
- private void drawUnder(Canvas c, String text, float x, float y) {
- if (mTmp.isEmpty()) {
- mTextPaint.getTextBounds(text, 0, text.length(), mTmp);
- }
- c.drawText(text, x, y + mTmp.height() * .85f, mTextPaint);
- }
-
- private Path line(float x1, float y1, float x2, float y2) {
- final int a = mStrokeWidth * 2;
- final Path p = new Path();
- p.moveTo(x1, y1);
- p.lineTo(x2, y2);
- if (y1 == y2) {
- p.moveTo(x1 + a, y1 + a);
- p.lineTo(x1, y1);
- p.lineTo(x1 + a, y1 - a);
-
- p.moveTo(x2 - a, y2 - a);
- p.lineTo(x2, y2);
- p.lineTo(x2 - a, y2 + a);
- }
- if (x1 == x2) {
- p.moveTo(x1 - a, y1 + a);
- p.lineTo(x1, y1);
- p.lineTo(x1 + a, y1 + a);
-
- p.moveTo(x2 - a, y2 - a);
- p.lineTo(x2, y2);
- p.lineTo(x2 + a, y2 - a);
- }
- return p;
- }
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
deleted file mode 100644
index e1ef83a..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ /dev/null
@@ -1,1126 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.graphics.drawable.Drawable;
-import android.media.MediaRouter;
-import android.media.MediaRouter.RouteInfo;
-import android.net.ConnectivityManager;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.InputMethodSubtype;
-
-import com.android.systemui.R;
-import com.android.systemui.settings.BrightnessController.BrightnessStateChangeCallback;
-import com.android.systemui.settings.CurrentUserTracker;
-import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
-import com.android.systemui.statusbar.policy.LocationController.LocationSettingsChangeCallback;
-import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
-import com.android.systemui.statusbar.policy.RotationLockController;
-import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
-
-import java.util.List;
-
-class QuickSettingsModel implements BluetoothStateChangeCallback,
- NetworkSignalChangedCallback,
- BatteryStateChangeCallback,
- BrightnessStateChangeCallback,
- RotationLockControllerCallback,
- LocationSettingsChangeCallback {
- // Sett InputMethoManagerService
- private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
-
- /** Represents the state of a given attribute. */
- static class State {
- int iconId;
- String label;
- boolean enabled = false;
- }
- static class BatteryState extends State {
- int batteryLevel;
- boolean pluggedIn;
- }
- static class ActivityState extends State {
- boolean activityIn;
- boolean activityOut;
- }
- static class RSSIState extends ActivityState {
- int signalIconId;
- String signalContentDescription;
- int dataTypeIconId;
- String dataContentDescription;
- }
- static class WifiState extends ActivityState {
- String signalContentDescription;
- boolean connected;
- }
- static class UserState extends State {
- Drawable avatar;
- }
- static class BrightnessState extends State {
- boolean autoBrightness;
- }
- static class InversionState extends State {
- boolean toggled;
- int type;
- }
- static class ContrastState extends State {
- boolean toggled;
- float contrast;
- float brightness;
- }
- static class ColorSpaceState extends State {
- boolean toggled;
- int type;
- }
- public static class BluetoothState extends State {
- boolean connected = false;
- String stateContentDescription;
- }
- public static class RotationLockState extends State {
- boolean visible = false;
- }
- public static class ZenModeState extends State {
- int zenMode = Settings.Global.ZEN_MODE_OFF;
- }
-
- /** The callback to update a given tile. */
- interface RefreshCallback {
- public void refreshView(QuickSettingsTileView view, State state);
- }
-
- public static class BasicRefreshCallback implements RefreshCallback {
- private final QuickSettingsBasicTile mView;
- private boolean mShowWhenEnabled;
-
- public BasicRefreshCallback(QuickSettingsBasicTile v) {
- mView = v;
- }
- public void refreshView(QuickSettingsTileView ignored, State state) {
- if (mShowWhenEnabled) {
- mView.setVisibility(state.enabled ? View.VISIBLE : View.GONE);
- }
- if (state.iconId != 0) {
- mView.setImageDrawable(null); // needed to flush any cached IDs
- mView.setImageResource(state.iconId);
- }
- if (state.label != null) {
- mView.setText(state.label);
- }
- }
- public BasicRefreshCallback setShowWhenEnabled(boolean swe) {
- mShowWhenEnabled = swe;
- return this;
- }
- }
-
- /** Broadcast receive to determine if there is an alarm set. */
- private BroadcastReceiver mAlarmIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
- onAlarmChanged(intent);
- onNextAlarmChanged();
- }
- }
- };
-
- /** ContentObserver to determine the next alarm */
- private class NextAlarmObserver extends ContentObserver {
- public NextAlarmObserver(Handler handler) {
- super(handler);
- }
-
- @Override public void onChange(boolean selfChange) {
- onNextAlarmChanged();
- }
-
- public void startObserving() {
- final ContentResolver cr = mContext.getContentResolver();
- cr.registerContentObserver(
- Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED), false, this,
- UserHandle.USER_ALL);
- }
- }
-
- /** ContentObserver to watch adb */
- private class BugreportObserver extends ContentObserver {
- public BugreportObserver(Handler handler) {
- super(handler);
- }
-
- @Override public void onChange(boolean selfChange) {
- onBugreportChanged();
- }
-
- public void startObserving() {
- final ContentResolver cr = mContext.getContentResolver();
- cr.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.BUGREPORT_IN_POWER_MENU), false, this);
- }
- }
-
- /** ContentObserver to watch brightness **/
- private class BrightnessObserver extends ContentObserver {
- public BrightnessObserver(Handler handler) {
- super(handler);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- onBrightnessLevelChanged();
- }
-
- public void startObserving() {
- final ContentResolver cr = mContext.getContentResolver();
- cr.unregisterContentObserver(this);
- cr.registerContentObserver(
- Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE),
- false, this, mUserTracker.getCurrentUserId());
- cr.registerContentObserver(
- Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS),
- false, this, mUserTracker.getCurrentUserId());
- }
- }
-
- /** ContentObserver to watch display inversion */
- private class DisplayInversionObserver extends ContentObserver {
- public DisplayInversionObserver(Handler handler) {
- super(handler);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- onInversionChanged();
- }
-
- public void startObserving() {
- final ContentResolver cr = mContext.getContentResolver();
- cr.unregisterContentObserver(this);
- cr.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
- false, this, mUserTracker.getCurrentUserId());
- cr.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_QUICK_SETTING_ENABLED),
- false, this, mUserTracker.getCurrentUserId());
- cr.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION),
- false, this, mUserTracker.getCurrentUserId());
- }
- }
-
- /** ContentObserver to watch display contrast */
- private class DisplayContrastObserver extends ContentObserver {
- public DisplayContrastObserver(Handler handler) {
- super(handler);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- onContrastChanged();
- }
-
- public void startObserving() {
- final ContentResolver cr = mContext.getContentResolver();
- cr.unregisterContentObserver(this);
- cr.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED),
- false, this, mUserTracker.getCurrentUserId());
- cr.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_QUICK_SETTING_ENABLED),
- false, this, mUserTracker.getCurrentUserId());
- cr.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST),
- false, this, mUserTracker.getCurrentUserId());
- cr.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_BRIGHTNESS),
- false, this, mUserTracker.getCurrentUserId());
- }
- }
-
- /** ContentObserver to watch display color space adjustment */
- private class DisplayColorSpaceObserver extends ContentObserver {
- public DisplayColorSpaceObserver(Handler handler) {
- super(handler);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- onColorSpaceChanged();
- }
-
- public void startObserving() {
- final ContentResolver cr = mContext.getContentResolver();
- cr.unregisterContentObserver(this);
- cr.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
- false, this, mUserTracker.getCurrentUserId());
- cr.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_QUICK_SETTING_ENABLED),
- false, this, mUserTracker.getCurrentUserId());
- cr.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
- false, this, mUserTracker.getCurrentUserId());
- }
- }
-
- /** ContentObserver to watch display color space adjustment */
- private class ZenModeObserver extends ContentObserver {
- public ZenModeObserver(Handler handler) {
- super(handler);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- onZenModeChanged();
- }
-
- public void startObserving() {
- final ContentResolver cr = mContext.getContentResolver();
- cr.unregisterContentObserver(this);
- cr.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false, this);
- }
- }
-
- /** Callback for changes to remote display routes. */
- private class RemoteDisplayRouteCallback extends MediaRouter.SimpleCallback {
- @Override
- public void onRouteAdded(MediaRouter router, RouteInfo route) {
- updateRemoteDisplays();
- }
- @Override
- public void onRouteChanged(MediaRouter router, RouteInfo route) {
- updateRemoteDisplays();
- }
- @Override
- public void onRouteRemoved(MediaRouter router, RouteInfo route) {
- updateRemoteDisplays();
- }
- @Override
- public void onRouteSelected(MediaRouter router, int type, RouteInfo route) {
- updateRemoteDisplays();
- }
- @Override
- public void onRouteUnselected(MediaRouter router, int type, RouteInfo route) {
- updateRemoteDisplays();
- }
- }
-
- private final Context mContext;
- private final Handler mHandler;
- private final CurrentUserTracker mUserTracker;
- private final NextAlarmObserver mNextAlarmObserver;
- private final BugreportObserver mBugreportObserver;
- private final BrightnessObserver mBrightnessObserver;
- private final DisplayInversionObserver mInversionObserver;
- private final DisplayContrastObserver mContrastObserver;
- private final DisplayColorSpaceObserver mColorSpaceObserver;
- private final ZenModeObserver mZenModeObserver;
-
- private final MediaRouter mMediaRouter;
- private final RemoteDisplayRouteCallback mRemoteDisplayRouteCallback;
-
- private final boolean mHasMobileData;
-
- private QuickSettingsTileView mUserTile;
- private RefreshCallback mUserCallback;
- private UserState mUserState = new UserState();
-
- private QuickSettingsTileView mTimeTile;
- private RefreshCallback mTimeCallback;
- private State mTimeState = new State();
-
- private QuickSettingsTileView mAlarmTile;
- private RefreshCallback mAlarmCallback;
- private State mAlarmState = new State();
-
- private QuickSettingsTileView mAirplaneModeTile;
- private RefreshCallback mAirplaneModeCallback;
- private State mAirplaneModeState = new State();
-
- private QuickSettingsTileView mZenModeTile;
- private RefreshCallback mZenModeCallback;
- private ZenModeState mZenModeState = new ZenModeState();
-
- private QuickSettingsTileView mWifiTile;
- private RefreshCallback mWifiCallback;
- private WifiState mWifiState = new WifiState();
-
- private QuickSettingsTileView mRemoteDisplayTile;
- private RefreshCallback mRemoteDisplayCallback;
- private State mRemoteDisplayState = new State();
-
- private QuickSettingsTileView mRSSITile;
- private RefreshCallback mRSSICallback;
- private RSSIState mRSSIState = new RSSIState();
-
- private QuickSettingsTileView mBluetoothTile;
- private RefreshCallback mBluetoothCallback;
- private BluetoothState mBluetoothState = new BluetoothState();
-
- private QuickSettingsTileView mBatteryTile;
- private RefreshCallback mBatteryCallback;
- private BatteryState mBatteryState = new BatteryState();
-
- private QuickSettingsTileView mLocationTile;
- private RefreshCallback mLocationCallback;
- private State mLocationState = new State();
-
- private QuickSettingsTileView mImeTile;
- private RefreshCallback mImeCallback = null;
- private State mImeState = new State();
-
- private QuickSettingsTileView mRotationLockTile;
- private RefreshCallback mRotationLockCallback;
- private RotationLockState mRotationLockState = new RotationLockState();
-
- private QuickSettingsTileView mBrightnessTile;
- private RefreshCallback mBrightnessCallback;
- private BrightnessState mBrightnessState = new BrightnessState();
-
- private QuickSettingsTileView mInversionTile;
- private RefreshCallback mInversionCallback;
- private InversionState mInversionState = new InversionState();
-
- private QuickSettingsTileView mContrastTile;
- private RefreshCallback mContrastCallback;
- private ContrastState mContrastState = new ContrastState();
-
- private QuickSettingsTileView mColorSpaceTile;
- private RefreshCallback mColorSpaceCallback;
- private ColorSpaceState mColorSpaceState = new ColorSpaceState();
-
- private QuickSettingsTileView mBugreportTile;
- private RefreshCallback mBugreportCallback;
- private State mBugreportState = new State();
-
- private QuickSettingsTileView mSettingsTile;
- private RefreshCallback mSettingsCallback;
- private State mSettingsState = new State();
-
- private QuickSettingsTileView mSslCaCertWarningTile;
- private RefreshCallback mSslCaCertWarningCallback;
- private State mSslCaCertWarningState = new State();
-
- private RotationLockController mRotationLockController;
- private int mRotationLockedLabel;
-
- public QuickSettingsModel(Context context) {
- mContext = context;
- mHandler = new Handler();
- mUserTracker = new CurrentUserTracker(mContext) {
- @Override
- public void onUserSwitched(int newUserId) {
- mBrightnessObserver.startObserving();
- mInversionObserver.startObserving();
- mContrastObserver.startObserving();
- mColorSpaceObserver.startObserving();
- refreshRotationLockTile();
- onBrightnessLevelChanged();
- onInversionChanged();
- onContrastChanged();
- onColorSpaceChanged();
- onNextAlarmChanged();
- onBugreportChanged();
- rebindMediaRouterAsCurrentUser();
- }
- };
-
- mNextAlarmObserver = new NextAlarmObserver(mHandler);
- mNextAlarmObserver.startObserving();
- mBugreportObserver = new BugreportObserver(mHandler);
- mBugreportObserver.startObserving();
- mBrightnessObserver = new BrightnessObserver(mHandler);
- mBrightnessObserver.startObserving();
- mInversionObserver = new DisplayInversionObserver(mHandler);
- mInversionObserver.startObserving();
- mContrastObserver = new DisplayContrastObserver(mHandler);
- mContrastObserver.startObserving();
- mColorSpaceObserver = new DisplayColorSpaceObserver(mHandler);
- mColorSpaceObserver.startObserving();
- mZenModeObserver = new ZenModeObserver(mHandler);
- mZenModeObserver.startObserving();
-
- mMediaRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
- rebindMediaRouterAsCurrentUser();
-
- mRemoteDisplayRouteCallback = new RemoteDisplayRouteCallback();
-
- ConnectivityManager cm = (ConnectivityManager)
- context.getSystemService(Context.CONNECTIVITY_SERVICE);
- mHasMobileData = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
-
- IntentFilter alarmIntentFilter = new IntentFilter();
- alarmIntentFilter.addAction(Intent.ACTION_ALARM_CHANGED);
- context.registerReceiver(mAlarmIntentReceiver, alarmIntentFilter);
- }
-
- void updateResources() {
- refreshSettingsTile();
- refreshBatteryTile();
- refreshBluetoothTile();
- refreshBrightnessTile();
- refreshRotationLockTile();
- refreshRssiTile();
- refreshLocationTile();
- }
-
- // Settings
- void addSettingsTile(QuickSettingsTileView view, RefreshCallback cb) {
- mSettingsTile = view;
- mSettingsCallback = cb;
- refreshSettingsTile();
- }
- void refreshSettingsTile() {
- Resources r = mContext.getResources();
- mSettingsState.label = r.getString(R.string.quick_settings_settings_label);
- mSettingsCallback.refreshView(mSettingsTile, mSettingsState);
- }
-
- // User
- void addUserTile(QuickSettingsTileView view, RefreshCallback cb) {
- mUserTile = view;
- mUserCallback = cb;
- mUserCallback.refreshView(mUserTile, mUserState);
- }
- void setUserTileInfo(String name, Drawable avatar) {
- mUserState.label = name;
- mUserState.avatar = avatar;
- mUserCallback.refreshView(mUserTile, mUserState);
- }
-
- // Time
- void addTimeTile(QuickSettingsTileView view, RefreshCallback cb) {
- mTimeTile = view;
- mTimeCallback = cb;
- mTimeCallback.refreshView(view, mTimeState);
- }
-
- // Alarm
- void addAlarmTile(QuickSettingsTileView view, RefreshCallback cb) {
- mAlarmTile = view;
- mAlarmCallback = cb;
- mAlarmCallback.refreshView(view, mAlarmState);
- }
- void onAlarmChanged(Intent intent) {
- mAlarmState.enabled = intent.getBooleanExtra("alarmSet", false);
- mAlarmCallback.refreshView(mAlarmTile, mAlarmState);
- }
- void onNextAlarmChanged() {
- final String alarmText = Settings.System.getStringForUser(mContext.getContentResolver(),
- Settings.System.NEXT_ALARM_FORMATTED,
- UserHandle.USER_CURRENT);
- mAlarmState.label = alarmText;
-
- // When switching users, this is the only clue we're going to get about whether the
- // alarm is actually set, since we won't get the ACTION_ALARM_CHANGED broadcast
- mAlarmState.enabled = ! TextUtils.isEmpty(alarmText);
-
- mAlarmCallback.refreshView(mAlarmTile, mAlarmState);
- }
-
- // Airplane Mode
- void addAirplaneModeTile(QuickSettingsTileView view, RefreshCallback cb) {
- mAirplaneModeTile = view;
- mAirplaneModeTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mAirplaneModeState.enabled) {
- setAirplaneModeState(false);
- } else {
- setAirplaneModeState(true);
- }
- }
- });
- mAirplaneModeCallback = cb;
- int airplaneMode = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON, 0);
- onAirplaneModeChanged(airplaneMode != 0);
- }
- private void setAirplaneModeState(boolean enabled) {
- // TODO: Sets the view to be "awaiting" if not already awaiting
-
- // Change the system setting
- Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
- enabled ? 1 : 0);
-
- // Post the intent
- Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- intent.putExtra("state", enabled);
- mContext.sendBroadcast(intent);
- }
- // NetworkSignalChanged callback
- @Override
- public void onAirplaneModeChanged(boolean enabled) {
- // TODO: If view is in awaiting state, disable
- Resources r = mContext.getResources();
- mAirplaneModeState.enabled = enabled;
- mAirplaneModeState.iconId = (enabled ?
- R.drawable.ic_qs_airplane_on :
- R.drawable.ic_qs_airplane_off);
- mAirplaneModeState.label = r.getString(R.string.quick_settings_airplane_mode_label);
- mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
- }
-
- // Zen Mode
- void addZenModeTile(QuickSettingsTileView view, RefreshCallback cb) {
- mZenModeTile = view;
- mZenModeCallback = cb;
- onZenModeChanged();
- }
- private void onZenModeChanged() {
- final int mode = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
- mZenModeState.enabled = mode != Settings.Global.ZEN_MODE_OFF;
- mZenModeState.zenMode = mode;
- mZenModeState.label = mContext.getString(R.string.zen_mode_title);
- mZenModeState.iconId = R.drawable.stat_sys_zen_limited;
- mZenModeCallback.refreshView(mZenModeTile, mZenModeState);
- }
-
- // Wifi
- void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) {
- mWifiTile = view;
- mWifiCallback = cb;
- mWifiCallback.refreshView(mWifiTile, mWifiState);
- }
- // Remove the double quotes that the SSID may contain
- public static String removeDoubleQuotes(String string) {
- if (string == null) return null;
- final int length = string.length();
- if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
- return string.substring(1, length - 1);
- }
- return string;
- }
- // Remove the period from the network name
- public static String removeTrailingPeriod(String string) {
- if (string == null) return null;
- final int length = string.length();
- if (string.endsWith(".")) {
- return string.substring(0, length - 1);
- }
- return string;
- }
- // NetworkSignalChanged callback
- @Override
- public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
- boolean activityIn, boolean activityOut,
- String wifiSignalContentDescription, String enabledDesc) {
- // TODO: If view is in awaiting state, disable
- Resources r = mContext.getResources();
-
- boolean wifiConnected = enabled && (wifiSignalIconId > 0) && (enabledDesc != null);
- boolean wifiNotConnected = (wifiSignalIconId > 0) && (enabledDesc == null);
- mWifiState.enabled = enabled;
- mWifiState.connected = wifiConnected;
- mWifiState.activityIn = enabled && activityIn;
- mWifiState.activityOut = enabled && activityOut;
- if (wifiConnected) {
- mWifiState.iconId = wifiSignalIconId;
- mWifiState.label = removeDoubleQuotes(enabledDesc);
- mWifiState.signalContentDescription = wifiSignalContentDescription;
- } else if (wifiNotConnected) {
- mWifiState.iconId = R.drawable.ic_qs_wifi_0;
- mWifiState.label = r.getString(R.string.quick_settings_wifi_label);
- mWifiState.signalContentDescription = r.getString(R.string.accessibility_no_wifi);
- } else {
- mWifiState.iconId = R.drawable.ic_qs_wifi_no_network;
- mWifiState.label = r.getString(R.string.quick_settings_wifi_off_label);
- mWifiState.signalContentDescription = r.getString(R.string.accessibility_wifi_off);
- }
- mWifiCallback.refreshView(mWifiTile, mWifiState);
- }
-
- boolean deviceHasMobileData() {
- return mHasMobileData;
- }
-
- // RSSI
- void addRSSITile(QuickSettingsTileView view, RefreshCallback cb) {
- mRSSITile = view;
- mRSSICallback = cb;
- mRSSICallback.refreshView(mRSSITile, mRSSIState);
- }
- // NetworkSignalChanged callback
- @Override
- public void onMobileDataSignalChanged(
- boolean enabled, int mobileSignalIconId, String signalContentDescription,
- int dataTypeIconId, boolean activityIn, boolean activityOut,
- String dataContentDescription,String enabledDesc) {
- if (deviceHasMobileData()) {
- // TODO: If view is in awaiting state, disable
- Resources r = mContext.getResources();
- mRSSIState.signalIconId = enabled && (mobileSignalIconId > 0)
- ? mobileSignalIconId
- : R.drawable.ic_qs_signal_no_signal;
- mRSSIState.signalContentDescription = enabled && (mobileSignalIconId > 0)
- ? signalContentDescription
- : r.getString(R.string.accessibility_no_signal);
- mRSSIState.dataTypeIconId = enabled && (dataTypeIconId > 0) && !mWifiState.enabled
- ? dataTypeIconId
- : 0;
- mRSSIState.activityIn = enabled && activityIn;
- mRSSIState.activityOut = enabled && activityOut;
- mRSSIState.dataContentDescription = enabled && (dataTypeIconId > 0) && !mWifiState.enabled
- ? dataContentDescription
- : r.getString(R.string.accessibility_no_data);
- mRSSIState.label = enabled
- ? removeTrailingPeriod(enabledDesc)
- : r.getString(R.string.quick_settings_rssi_emergency_only);
- mRSSICallback.refreshView(mRSSITile, mRSSIState);
- }
- }
-
- void refreshRssiTile() {
- if (mRSSITile != null) {
- // We reinflate the original view due to potential styling changes that may have
- // taken place due to a configuration change.
- mRSSITile.reinflateContent(LayoutInflater.from(mContext));
- }
- }
-
- // Bluetooth
- void addBluetoothTile(QuickSettingsTileView view, RefreshCallback cb) {
- mBluetoothTile = view;
- mBluetoothCallback = cb;
-
- final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- mBluetoothState.enabled = adapter.isEnabled();
- mBluetoothState.connected =
- (adapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED);
- onBluetoothStateChange(mBluetoothState);
- }
- boolean deviceSupportsBluetooth() {
- return (BluetoothAdapter.getDefaultAdapter() != null);
- }
- // BluetoothController callback
- @Override
- public void onBluetoothStateChange(boolean on) {
- mBluetoothState.enabled = on;
- onBluetoothStateChange(mBluetoothState);
- }
- public void onBluetoothStateChange(BluetoothState bluetoothStateIn) {
- // TODO: If view is in awaiting state, disable
- Resources r = mContext.getResources();
- mBluetoothState.enabled = bluetoothStateIn.enabled;
- mBluetoothState.connected = bluetoothStateIn.connected;
- if (mBluetoothState.enabled) {
- if (mBluetoothState.connected) {
- mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_on;
- mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_connected);
- } else {
- mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_not_connected;
- mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_on);
- }
- mBluetoothState.label = r.getString(R.string.quick_settings_bluetooth_label);
- } else {
- mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_off;
- mBluetoothState.label = r.getString(R.string.quick_settings_bluetooth_off_label);
- mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_off);
- }
- mBluetoothCallback.refreshView(mBluetoothTile, mBluetoothState);
- }
- void refreshBluetoothTile() {
- if (mBluetoothTile != null) {
- onBluetoothStateChange(mBluetoothState.enabled);
- }
- }
-
- // Battery
- void addBatteryTile(QuickSettingsTileView view, RefreshCallback cb) {
- mBatteryTile = view;
- mBatteryCallback = cb;
- mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
- }
- // BatteryController callback
- @Override
- public void onBatteryLevelChanged(int level, boolean pluggedIn) {
- mBatteryState.batteryLevel = level;
- mBatteryState.pluggedIn = pluggedIn;
- mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
- }
- void refreshBatteryTile() {
- mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
- }
-
- // Location
- void addLocationTile(QuickSettingsTileView view, RefreshCallback cb) {
- mLocationTile = view;
- mLocationCallback = cb;
- mLocationCallback.refreshView(mLocationTile, mLocationState);
- }
-
- void refreshLocationTile() {
- if (mLocationTile != null) {
- onLocationSettingsChanged(mLocationState.enabled);
- }
- }
-
- @Override
- public void onLocationSettingsChanged(boolean locationEnabled) {
- int textResId = locationEnabled ? R.string.quick_settings_location_label
- : R.string.quick_settings_location_off_label;
- String label = mContext.getText(textResId).toString();
- int locationIconId = locationEnabled
- ? R.drawable.ic_qs_location_on : R.drawable.ic_qs_location_off;
- mLocationState.enabled = locationEnabled;
- mLocationState.label = label;
- mLocationState.iconId = locationIconId;
- mLocationCallback.refreshView(mLocationTile, mLocationState);
- }
-
- // Bug report
- void addBugreportTile(QuickSettingsTileView view, RefreshCallback cb) {
- mBugreportTile = view;
- mBugreportCallback = cb;
- onBugreportChanged();
- }
- // SettingsObserver callback
- public void onBugreportChanged() {
- final ContentResolver cr = mContext.getContentResolver();
- boolean enabled = false;
- try {
- enabled = (Settings.Global.getInt(cr, Settings.Global.BUGREPORT_IN_POWER_MENU) != 0);
- } catch (SettingNotFoundException e) {
- }
-
- mBugreportState.enabled = enabled && mUserTracker.isCurrentUserOwner();
- mBugreportCallback.refreshView(mBugreportTile, mBugreportState);
- }
-
- // Remote Display
- void addRemoteDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
- mRemoteDisplayTile = view;
- mRemoteDisplayCallback = cb;
- mRemoteDisplayTile.setOnPrepareListener(new QuickSettingsTileView.OnPrepareListener() {
- @Override
- public void onPrepare() {
- mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
- mRemoteDisplayRouteCallback,
- MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
- updateRemoteDisplays();
- }
- @Override
- public void onUnprepare() {
- mMediaRouter.removeCallback(mRemoteDisplayRouteCallback);
- }
- });
-
- updateRemoteDisplays();
- }
-
- private void rebindMediaRouterAsCurrentUser() {
- mMediaRouter.rebindAsUser(mUserTracker.getCurrentUserId());
- }
-
- private void updateRemoteDisplays() {
- MediaRouter.RouteInfo connectedRoute = mMediaRouter.getSelectedRoute(
- MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
- boolean enabled = connectedRoute != null
- && connectedRoute.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
- boolean connecting;
- if (enabled) {
- connecting = connectedRoute.isConnecting();
- } else {
- connectedRoute = null;
- connecting = false;
- enabled = mMediaRouter.isRouteAvailable(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
- MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE);
- }
-
- mRemoteDisplayState.enabled = enabled;
- if (connectedRoute != null) {
- mRemoteDisplayState.label = connectedRoute.getName().toString();
- mRemoteDisplayState.iconId = connecting ?
- R.drawable.ic_qs_cast_connecting : R.drawable.ic_qs_cast_connected;
- } else {
- mRemoteDisplayState.label = mContext.getString(
- R.string.quick_settings_remote_display_no_connection_label);
- mRemoteDisplayState.iconId = R.drawable.ic_qs_cast_available;
- }
- mRemoteDisplayCallback.refreshView(mRemoteDisplayTile, mRemoteDisplayState);
- }
-
- // IME
- void addImeTile(QuickSettingsTileView view, RefreshCallback cb) {
- mImeTile = view;
- mImeCallback = cb;
- mImeCallback.refreshView(mImeTile, mImeState);
- }
- /* This implementation is taken from
- InputMethodManagerService.needsToShowImeSwitchOngoingNotification(). */
- private boolean needsToShowImeSwitchOngoingNotification(InputMethodManager imm) {
- List<InputMethodInfo> imis = imm.getEnabledInputMethodList();
- final int N = imis.size();
- if (N > 2) return true;
- if (N < 1) return false;
- int nonAuxCount = 0;
- int auxCount = 0;
- InputMethodSubtype nonAuxSubtype = null;
- InputMethodSubtype auxSubtype = null;
- for(int i = 0; i < N; ++i) {
- final InputMethodInfo imi = imis.get(i);
- final List<InputMethodSubtype> subtypes = imm.getEnabledInputMethodSubtypeList(imi,
- true);
- final int subtypeCount = subtypes.size();
- if (subtypeCount == 0) {
- ++nonAuxCount;
- } else {
- for (int j = 0; j < subtypeCount; ++j) {
- final InputMethodSubtype subtype = subtypes.get(j);
- if (!subtype.isAuxiliary()) {
- ++nonAuxCount;
- nonAuxSubtype = subtype;
- } else {
- ++auxCount;
- auxSubtype = subtype;
- }
- }
- }
- }
- if (nonAuxCount > 1 || auxCount > 1) {
- return true;
- } else if (nonAuxCount == 1 && auxCount == 1) {
- if (nonAuxSubtype != null && auxSubtype != null
- && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
- || auxSubtype.overridesImplicitlyEnabledSubtype()
- || nonAuxSubtype.overridesImplicitlyEnabledSubtype())
- && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
- return false;
- }
- return true;
- }
- return false;
- }
- void onImeWindowStatusChanged(boolean visible) {
- InputMethodManager imm =
- (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
- List<InputMethodInfo> imis = imm.getInputMethodList();
-
- mImeState.enabled = (visible && needsToShowImeSwitchOngoingNotification(imm));
- mImeState.label = getCurrentInputMethodName(mContext, mContext.getContentResolver(),
- imm, imis, mContext.getPackageManager());
- if (mImeCallback != null) {
- mImeCallback.refreshView(mImeTile, mImeState);
- }
- }
- private static String getCurrentInputMethodName(Context context, ContentResolver resolver,
- InputMethodManager imm, List<InputMethodInfo> imis, PackageManager pm) {
- if (resolver == null || imis == null) return null;
- final String currentInputMethodId = Settings.Secure.getString(resolver,
- Settings.Secure.DEFAULT_INPUT_METHOD);
- if (TextUtils.isEmpty(currentInputMethodId)) return null;
- for (InputMethodInfo imi : imis) {
- if (currentInputMethodId.equals(imi.getId())) {
- final InputMethodSubtype subtype = imm.getCurrentInputMethodSubtype();
- final CharSequence summary = subtype != null
- ? subtype.getDisplayName(context, imi.getPackageName(),
- imi.getServiceInfo().applicationInfo)
- : context.getString(R.string.quick_settings_ime_label);
- return summary.toString();
- }
- }
- return null;
- }
-
- // Rotation lock
- void addRotationLockTile(QuickSettingsTileView view,
- RotationLockController rotationLockController,
- RefreshCallback cb) {
- mRotationLockTile = view;
- mRotationLockCallback = cb;
- mRotationLockController = rotationLockController;
- final int lockOrientation = mRotationLockController.getRotationLockOrientation();
- mRotationLockedLabel = lockOrientation == Configuration.ORIENTATION_PORTRAIT
- ? R.string.quick_settings_rotation_locked_portrait_label
- : lockOrientation == Configuration.ORIENTATION_LANDSCAPE
- ? R.string.quick_settings_rotation_locked_landscape_label
- : R.string.quick_settings_rotation_locked_label;
- onRotationLockChanged();
- }
- void onRotationLockChanged() {
- onRotationLockStateChanged(mRotationLockController.isRotationLocked(),
- mRotationLockController.isRotationLockAffordanceVisible());
- }
- @Override
- public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
- mRotationLockState.visible = affordanceVisible;
- mRotationLockState.enabled = rotationLocked;
- mRotationLockState.iconId = rotationLocked
- ? R.drawable.ic_qs_rotation_locked
- : R.drawable.ic_qs_auto_rotate;
- mRotationLockState.label = rotationLocked
- ? mContext.getString(mRotationLockedLabel)
- : mContext.getString(R.string.quick_settings_rotation_unlocked_label);
- mRotationLockCallback.refreshView(mRotationLockTile, mRotationLockState);
- }
- void refreshRotationLockTile() {
- if (mRotationLockTile != null) {
- onRotationLockChanged();
- }
- }
-
- // Brightness
- void addBrightnessTile(QuickSettingsTileView view, RefreshCallback cb) {
- mBrightnessTile = view;
- mBrightnessCallback = cb;
- onBrightnessLevelChanged();
- }
- @Override
- public void onBrightnessLevelChanged() {
- Resources r = mContext.getResources();
- int mode = Settings.System.getIntForUser(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS_MODE,
- Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
- mUserTracker.getCurrentUserId());
- mBrightnessState.autoBrightness =
- (mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
- mBrightnessState.iconId = mBrightnessState.autoBrightness
- ? R.drawable.ic_qs_brightness_auto_on
- : R.drawable.ic_qs_brightness_auto_off;
- mBrightnessState.label = r.getString(R.string.quick_settings_brightness_label);
- mBrightnessCallback.refreshView(mBrightnessTile, mBrightnessState);
- }
- void refreshBrightnessTile() {
- onBrightnessLevelChanged();
- }
-
- // Color inversion
- void addInversionTile(QuickSettingsTileView view, RefreshCallback cb) {
- mInversionTile = view;
- mInversionCallback = cb;
- onInversionChanged();
- }
- public void onInversionChanged() {
- final Resources res = mContext.getResources();
- final ContentResolver cr = mContext.getContentResolver();
- final int currentUserId = mUserTracker.getCurrentUserId();
- final boolean quickSettingEnabled = Settings.Secure.getIntForUser(
- cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_QUICK_SETTING_ENABLED, 0,
- currentUserId) == 1;
- final boolean enabled = Settings.Secure.getIntForUser(
- cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, currentUserId) == 1;
- final int type = Settings.Secure.getIntForUser(
- cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION, 0, currentUserId);
- mInversionState.enabled = quickSettingEnabled;
- mInversionState.toggled = enabled;
- mInversionState.type = type;
- // TODO: Add real icon assets.
- mInversionState.iconId = enabled ? R.drawable.ic_qs_inversion_on
- : R.drawable.ic_qs_inversion_off;
- mInversionState.label = res.getString(R.string.quick_settings_inversion_label);
- mInversionCallback.refreshView(mInversionTile, mInversionState);
- }
-
- // Contrast enhancement
- void addContrastTile(QuickSettingsTileView view, RefreshCallback cb) {
- mContrastTile = view;
- mContrastCallback = cb;
- onContrastChanged();
- }
- public void onContrastChanged() {
- final Resources res = mContext.getResources();
- final ContentResolver cr = mContext.getContentResolver();
- final int currentUserId = mUserTracker.getCurrentUserId();
- final boolean quickSettingEnabled = Settings.Secure.getIntForUser(
- cr, Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_QUICK_SETTING_ENABLED, 0,
- currentUserId) == 1;
- final boolean enabled = Settings.Secure.getIntForUser(
- cr, Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED, 0, currentUserId) == 1;
- final float contrast = Settings.Secure.getFloatForUser(
- cr, Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST, 1, currentUserId);
- final float brightness = Settings.Secure.getFloatForUser(
- cr, Settings.Secure.ACCESSIBILITY_DISPLAY_BRIGHTNESS, 0, currentUserId);
- mContrastState.enabled = quickSettingEnabled;
- mContrastState.toggled = enabled;
- mContrastState.contrast = contrast;
- mContrastState.brightness = brightness;
- // TODO: Add real icon assets.
- mContrastState.iconId = enabled ? R.drawable.ic_qs_contrast_on
- : R.drawable.ic_qs_contrast_off;
- mContrastState.label = res.getString(R.string.quick_settings_contrast_label);
- mContrastCallback.refreshView(mContrastTile, mContrastState);
- }
-
- // Color space adjustment
- void addColorSpaceTile(QuickSettingsTileView view, RefreshCallback cb) {
- mColorSpaceTile = view;
- mColorSpaceCallback = cb;
- onColorSpaceChanged();
- }
- public void onColorSpaceChanged() {
- final Resources res = mContext.getResources();
- final ContentResolver cr = mContext.getContentResolver();
- final int currentUserId = mUserTracker.getCurrentUserId();
- final boolean quickSettingEnabled = Settings.Secure.getIntForUser(
- cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_QUICK_SETTING_ENABLED, 0,
- currentUserId) == 1;
- final boolean enabled = Settings.Secure.getIntForUser(cr,
- Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, currentUserId) == 1;
- final int type = Settings.Secure.getIntForUser(
- cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, 0, currentUserId);
- mColorSpaceState.enabled = quickSettingEnabled;
- mColorSpaceState.toggled = enabled;
- mColorSpaceState.type = type;
- // TODO: Add real icon assets.
- mColorSpaceState.iconId = enabled ? R.drawable.ic_qs_color_space_on
- : R.drawable.ic_qs_color_space_off;
- mColorSpaceState.label = res.getString(R.string.quick_settings_color_space_label);
- mColorSpaceCallback.refreshView(mColorSpaceTile, mColorSpaceState);
- }
-
- // SSL CA Cert warning.
- public void addSslCaCertWarningTile(QuickSettingsTileView view, RefreshCallback cb) {
- mSslCaCertWarningTile = view;
- mSslCaCertWarningCallback = cb;
- // Set a sane default while we wait for the AsyncTask to finish (no cert).
- setSslCaCertWarningTileInfo(false, true);
- }
- public void setSslCaCertWarningTileInfo(boolean hasCert, boolean isManaged) {
- Resources r = mContext.getResources();
- mSslCaCertWarningState.enabled = hasCert;
- if (isManaged) {
- mSslCaCertWarningState.iconId = R.drawable.ic_qs_certificate_info;
- } else {
- mSslCaCertWarningState.iconId = android.R.drawable.stat_notify_error;
- }
- mSslCaCertWarningState.label = r.getString(R.string.ssl_ca_cert_warning);
- mSslCaCertWarningCallback.refreshView(mSslCaCertWarningTile, mSslCaCertWarningState);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsScrollView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsScrollView.java
deleted file mode 100644
index 175805a..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsScrollView.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.ScrollView;
-
-public class QuickSettingsScrollView extends ScrollView {
-
- public QuickSettingsScrollView(Context context) {
- super(context);
- }
-
- public QuickSettingsScrollView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public QuickSettingsScrollView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- // Y U NO PROTECTED
- private int getScrollRange() {
- int scrollRange = 0;
- if (getChildCount() > 0) {
- View child = getChildAt(0);
- scrollRange = Math.max(0,
- child.getHeight() - (getHeight() - getPaddingBottom() - getPaddingTop()));
- }
- return scrollRange;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- final int range = getScrollRange();
- if (range == 0) {
- return false;
- }
-
- return super.onTouchEvent(ev);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
deleted file mode 100644
index ad18294..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewParent;
-import android.widget.FrameLayout;
-
-/**
- *
- */
-class QuickSettingsTileView extends FrameLayout {
- private static final String TAG = "QuickSettingsTileView";
-
- private int mContentLayoutId;
- private int mColSpan;
- private boolean mPrepared;
- private OnPrepareListener mOnPrepareListener;
-
- public QuickSettingsTileView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- mContentLayoutId = -1;
- mColSpan = 1;
- }
-
- void setColumnSpan(int span) {
- mColSpan = span;
- }
-
- int getColumnSpan() {
- return mColSpan;
- }
-
- void setContent(int layoutId, LayoutInflater inflater) {
- mContentLayoutId = layoutId;
- inflater.inflate(layoutId, this);
- }
-
- void reinflateContent(LayoutInflater inflater) {
- if (mContentLayoutId != -1) {
- removeAllViews();
- setContent(mContentLayoutId, inflater);
- } else {
- Log.e(TAG, "Not reinflating content: No layoutId set");
- }
- }
-
- @Override
- public void setVisibility(int vis) {
- if (QuickSettings.DEBUG_GONE_TILES) {
- if (vis == View.GONE) {
- vis = View.VISIBLE;
- setAlpha(0.25f);
- setEnabled(false);
- } else {
- setAlpha(1f);
- setEnabled(true);
- }
- }
- super.setVisibility(vis);
- }
-
- public void setOnPrepareListener(OnPrepareListener listener) {
- if (mOnPrepareListener != listener) {
- mOnPrepareListener = listener;
- mPrepared = false;
- post(new Runnable() {
- @Override
- public void run() {
- updatePreparedState();
- }
- });
- }
- }
-
- @Override
- protected void onVisibilityChanged(View changedView, int visibility) {
- super.onVisibilityChanged(changedView, visibility);
- updatePreparedState();
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- updatePreparedState();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- updatePreparedState();
- }
-
- private void updatePreparedState() {
- if (mOnPrepareListener != null) {
- if (isParentVisible()) {
- if (!mPrepared) {
- mPrepared = true;
- mOnPrepareListener.onPrepare();
- }
- } else if (mPrepared) {
- mPrepared = false;
- mOnPrepareListener.onUnprepare();
- }
- }
- }
-
- private boolean isParentVisible() {
- if (!isAttachedToWindow()) {
- return false;
- }
- for (ViewParent current = getParent(); current instanceof View;
- current = current.getParent()) {
- View view = (View)current;
- if (view.getVisibility() != VISIBLE) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Called when the view's parent becomes visible or invisible to provide
- * an opportunity for the client to provide new content.
- */
- public interface OnPrepareListener {
- void onPrepare();
- void onUnprepare();
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 9d33930..2305445 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -17,25 +17,54 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
+import android.content.Intent;
+import android.graphics.Outline;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.android.systemui.R;
+import com.android.systemui.qs.QSPanel;
+import com.android.systemui.settings.BrightnessController;
+import com.android.systemui.settings.ToggleSlider;
+import com.android.systemui.statusbar.policy.UserInfoController;
/**
* The view to manage the header area in the expanded status bar.
*/
-public class StatusBarHeaderView extends RelativeLayout {
+public class StatusBarHeaderView extends RelativeLayout implements View.OnClickListener {
private boolean mExpanded;
+ private boolean mKeyguardShowing;
+
private View mBackground;
- private View mFlipper;
+ private ViewGroup mSystemIconsContainer;
+ private View mDateTime;
+ private View mKeyguardCarrierText;
+ private MultiUserSwitch mMultiUserSwitch;
+ private View mDate;
+ private View mStatusIcons;
+ private View mSignalCluster;
+ private View mSettingsButton;
+ private View mBrightnessContainer;
private int mCollapsedHeight;
private int mExpandedHeight;
+ private int mKeyguardHeight;
+
+ private int mKeyguardWidth = ViewGroup.LayoutParams.MATCH_PARENT;
+ private int mNormalWidth;
+
+ private ActivityStarter mActivityStarter;
+ private BrightnessController mBrightnessController;
+ private QSPanel mQSPanel;
+
+ private final Rect mClipBounds = new Rect();
+ private final Outline mOutline = new Outline();
public StatusBarHeaderView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -45,19 +74,35 @@
protected void onFinishInflate() {
super.onFinishInflate();
mBackground = findViewById(R.id.background);
- mFlipper = findViewById(R.id.header_flipper);
+ mSystemIconsContainer = (ViewGroup) findViewById(R.id.system_icons_container);
+ mDateTime = findViewById(R.id.datetime);
+ mKeyguardCarrierText = findViewById(R.id.keyguard_carrier_text);
+ mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
+ mDate = findViewById(R.id.date);
+ mSettingsButton = findViewById(R.id.settings_button);
+ mSettingsButton.setOnClickListener(this);
+ mBrightnessContainer = findViewById(R.id.brightness_container);
+ mBrightnessController = new BrightnessController(getContext(),
+ (ImageView) findViewById(R.id.brightness_icon),
+ (ToggleSlider) findViewById(R.id.brightness_slider));
loadDimens();
}
private void loadDimens() {
- mCollapsedHeight = getResources().getDimensionPixelSize(
- R.dimen.status_bar_header_height);
+ mCollapsedHeight = getResources().getDimensionPixelSize(R.dimen.status_bar_header_height);
mExpandedHeight = getResources().getDimensionPixelSize(
R.dimen.status_bar_header_height_expanded);
+ mKeyguardHeight = getResources().getDimensionPixelSize(
+ R.dimen.status_bar_header_height_keyguard);
+ mNormalWidth = getLayoutParams().width;
+ }
+
+ public void setActivityStarter(ActivityStarter activityStarter) {
+ mActivityStarter = activityStarter;
}
public int getCollapsedHeight() {
- return mCollapsedHeight;
+ return mKeyguardShowing ? mKeyguardHeight : mCollapsedHeight;
}
public int getExpandedHeight() {
@@ -65,16 +110,85 @@
}
public void setExpanded(boolean expanded) {
- if (expanded != mExpanded) {
- ViewGroup.LayoutParams lp = getLayoutParams();
- lp.height = expanded ? mExpandedHeight : mCollapsedHeight;
- setLayoutParams(lp);
- mExpanded = expanded;
+ boolean changed = expanded != mExpanded;
+ mExpanded = expanded;
+ if (changed) {
+ updateHeights();
+ updateVisibilities();
+ updateSystemIconsLayoutParams();
+ updateBrightnessControllerState();
+ if (mQSPanel != null) {
+ mQSPanel.setExpanded(expanded);
+ }
}
}
- public void setExpansionEnabled(boolean enabled) {
- mFlipper.setVisibility(enabled ? View.VISIBLE : View.GONE);
+ private void updateHeights() {
+ boolean onKeyguardAndCollapsed = mKeyguardShowing && !mExpanded;
+ int height;
+ if (mExpanded) {
+ height = mExpandedHeight;
+ } else if (onKeyguardAndCollapsed) {
+ height = mKeyguardHeight;
+ } else {
+ height = mCollapsedHeight;
+ }
+ ViewGroup.LayoutParams lp = getLayoutParams();
+ if (lp.height != height) {
+ lp.height = height;
+ setLayoutParams(lp);
+ }
+ int systemIconsContainerHeight = onKeyguardAndCollapsed ? mKeyguardHeight : mCollapsedHeight;
+ lp = mSystemIconsContainer.getLayoutParams();
+ if (lp.height != systemIconsContainerHeight) {
+ lp.height = systemIconsContainerHeight;
+ mSystemIconsContainer.setLayoutParams(lp);
+ }
+ lp = mMultiUserSwitch.getLayoutParams();
+ if (lp.height != systemIconsContainerHeight) {
+ lp.height = systemIconsContainerHeight;
+ mMultiUserSwitch.setLayoutParams(lp);
+ }
+ }
+
+ private void updateWidth() {
+ int width = mKeyguardShowing ? mKeyguardWidth : mNormalWidth;
+ ViewGroup.LayoutParams lp = getLayoutParams();
+ if (width != lp.width) {
+ lp.width = width;
+ setLayoutParams(lp);
+ }
+ }
+
+ private void updateVisibilities() {
+ boolean onKeyguardAndCollapsed = mKeyguardShowing && !mExpanded;
+ mBackground.setVisibility(onKeyguardAndCollapsed ? View.INVISIBLE : View.VISIBLE);
+ mDateTime.setVisibility(onKeyguardAndCollapsed ? View.INVISIBLE : View.VISIBLE);
+ mKeyguardCarrierText.setVisibility(onKeyguardAndCollapsed ? View.VISIBLE : View.GONE);
+ mDate.setVisibility(mExpanded ? View.VISIBLE : View.GONE);
+ mSettingsButton.setVisibility(mExpanded ? View.VISIBLE : View.GONE);
+ mBrightnessContainer.setVisibility(mExpanded ? View.VISIBLE : View.GONE);
+ if (mStatusIcons != null) {
+ mStatusIcons.setVisibility(!mExpanded ? View.VISIBLE : View.GONE);
+ }
+ if (mSignalCluster != null) {
+ mSignalCluster.setVisibility(!mExpanded ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ private void updateSystemIconsLayoutParams() {
+ RelativeLayout.LayoutParams lp = (LayoutParams) mSystemIconsContainer.getLayoutParams();
+ lp.addRule(RelativeLayout.START_OF, mExpanded
+ ? mSettingsButton.getId()
+ : mMultiUserSwitch.getId());
+ }
+
+ private void updateBrightnessControllerState() {
+ if (mExpanded) {
+ mBrightnessController.registerCallbacks();
+ } else {
+ mBrightnessController.unregisterCallbacks();
+ }
}
public void setExpansion(float height) {
@@ -89,9 +203,69 @@
} else {
mBackground.setTranslationY(0);
}
+ setClipping(height);
+ }
+
+ private void setClipping(float height) {
+ mClipBounds.set(getPaddingLeft(), 0, getWidth() - getPaddingRight(), (int) height);
+ setClipBounds(mClipBounds);
+ mOutline.setRect(mClipBounds);
+ setOutline(mOutline);
}
public View getBackgroundView() {
return mBackground;
}
+
+ public void attachSystemIcons(LinearLayout systemIcons) {
+ mSystemIconsContainer.addView(systemIcons);
+ mStatusIcons = systemIcons.findViewById(R.id.statusIcons);
+ mSignalCluster = systemIcons.findViewById(R.id.signal_cluster);
+ }
+
+ public void onSystemIconsDetached() {
+ if (mStatusIcons != null) {
+ mStatusIcons.setVisibility(View.VISIBLE);
+ }
+ if (mSignalCluster != null) {
+ mSignalCluster.setVisibility(View.VISIBLE);
+ }
+ mStatusIcons = null;
+ mSignalCluster = null;
+ }
+
+ public void setKeyguardShowing(boolean keyguardShowing) {
+ mKeyguardShowing = keyguardShowing;
+ if (keyguardShowing) {
+ setZ(0);
+ } else {
+ setTranslationZ(0);
+ }
+ updateHeights();
+ updateWidth();
+ updateVisibilities();
+ }
+
+ public void setUserInfoController(UserInfoController userInfoController) {
+ mMultiUserSwitch.setUserInfoController(userInfoController);
+ }
+
+ public void setOverlayParent(ViewGroup parent) {
+ mMultiUserSwitch.setOverlayParent(parent);
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == mSettingsButton) {
+ startSettingsActivity();
+ }
+ }
+
+ private void startSettingsActivity() {
+ mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS));
+ }
+
+ public void setQSPanel(QSPanel qsp) {
+ mQSPanel = qsp;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 48c54fc..77b760e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -20,11 +20,13 @@
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Slog;
+import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import com.android.internal.policy.IKeyguardShowCallback;
import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
/**
@@ -50,6 +52,12 @@
private boolean mShowing;
private boolean mOccluded;
+ private boolean mFirstUpdate = true;
+ private boolean mLastShowing;
+ private boolean mLastOccluded;
+ private boolean mLastBouncerShowing;
+ private boolean mLastBouncerDismissible;
+
public StatusBarKeyguardViewManager(Context context, ViewMediatorCallback callback,
LockPatternUtils lockPatternUtils) {
mContext = context;
@@ -207,23 +215,55 @@
private void updateStates() {
int vis = mContainer.getSystemUiVisibility();
- boolean bouncerDismissable = mBouncer.isShowing() && !mBouncer.needsFullscreenBouncer();
- if (bouncerDismissable || !mShowing) {
- mContainer.setSystemUiVisibility(vis & ~View.STATUS_BAR_DISABLE_BACK);
- } else {
- mContainer.setSystemUiVisibility(vis | View.STATUS_BAR_DISABLE_BACK);
- }
- if (mPhoneStatusBar.getNavigationBarView() != null) {
- if (!(mShowing && !mOccluded) || mBouncer.isShowing()) {
- mPhoneStatusBar.getNavigationBarView().setVisibility(View.VISIBLE);
+ boolean showing = mShowing;
+ boolean occluded = mOccluded;
+ boolean bouncerShowing = mBouncer.isShowing();
+ boolean bouncerDismissible = bouncerShowing && !mBouncer.needsFullscreenBouncer();
+
+ if ((bouncerDismissible || !showing) != (mLastBouncerDismissible || !mLastShowing)
+ || mFirstUpdate) {
+ if (bouncerDismissible || !showing) {
+ mContainer.setSystemUiVisibility(vis & ~View.STATUS_BAR_DISABLE_BACK);
} else {
- mPhoneStatusBar.getNavigationBarView().setVisibility(View.GONE);
+ mContainer.setSystemUiVisibility(vis | View.STATUS_BAR_DISABLE_BACK);
}
}
- mPhoneStatusBar.setBouncerShowing(mBouncer.isShowing());
+ if ((!(showing && !occluded) || bouncerShowing)
+ != (!(mLastShowing && !mLastOccluded) || mLastBouncerShowing) || mFirstUpdate) {
+ if (mPhoneStatusBar.getNavigationBarView() != null) {
+ if (!(showing && !occluded) || bouncerShowing) {
+ mPhoneStatusBar.getNavigationBarView().setVisibility(View.VISIBLE);
+ } else {
+ mPhoneStatusBar.getNavigationBarView().setVisibility(View.GONE);
+ }
+ }
+ }
+
+ if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
+ mStatusBarWindowManager.setBouncerShowing(bouncerShowing);
+ mPhoneStatusBar.setBouncerShowing(bouncerShowing);
+ }
+
+ KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
+ if ((showing && !occluded) != (mLastShowing && !mLastOccluded) || mFirstUpdate) {
+ updateMonitor.sendKeyguardVisibilityChanged(showing && !occluded);
+ }
+ if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
+ updateMonitor.sendKeyguardBouncerChanged(bouncerShowing);
+ }
+
+ mFirstUpdate = false;
+ mLastShowing = showing;
+ mLastOccluded = occluded;
+ mLastBouncerShowing = bouncerShowing;
+ mLastBouncerDismissible = bouncerDismissible;
}
public boolean onMenuPressed() {
return mBouncer.onMenuPressed();
}
+
+ public boolean interceptMediaKey(KeyEvent event) {
+ return mBouncer.interceptMediaKey(event);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index a4c9df5..46a637b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -78,9 +78,8 @@
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
PixelFormat.TRANSLUCENT);
-
mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
- mLp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+ mLp.gravity = Gravity.TOP;
mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
mLp.setTitle("StatusBar");
mLp.packageName = mContext.getPackageName();
@@ -112,7 +111,8 @@
}
private void applyFocusableFlag(State state) {
- if (state.isKeyguardShowingAndNotOccluded() && state.keyguardNeedsInput) {
+ if (state.isKeyguardShowingAndNotOccluded() && state.keyguardNeedsInput
+ && state.bouncerShowing) {
mLp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mLp.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
} else if (state.isKeyguardShowingAndNotOccluded() || state.statusBarFocusable) {
@@ -197,6 +197,11 @@
apply(mCurrentState);
}
+ public void setBouncerShowing(boolean showing) {
+ mCurrentState.bouncerShowing = showing;
+ apply(mCurrentState);
+ }
+
/**
* @param state The {@link StatusBarState} of the status bar.
*/
@@ -212,6 +217,7 @@
boolean statusBarExpanded;
boolean statusBarFocusable;
long keyguardUserActivityTimeout;
+ boolean bouncerShowing;
/**
* The {@link BaseStatusBar} state from the status bar.
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 e802d185..b51626d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -103,6 +103,9 @@
return mService.onMenuPressed();
}
}
+ if (mService.interceptMediaKey(event)) {
+ return true;
+ }
return super.dispatchKeyEvent(event);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
deleted file mode 100644
index ff921cd..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.Typeface;
-import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.OvalShape;
-import android.text.Spannable;
-import android.text.SpannableStringBuilder;
-import android.text.TextPaint;
-import android.text.method.LinkMovementMethod;
-import android.text.style.URLSpan;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-import android.widget.Switch;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.ZenModeView.Adapter.ExitCondition;
-
-public class ZenModeView extends RelativeLayout {
- private static final String TAG = ZenModeView.class.getSimpleName();
- private static final boolean DEBUG = false;
-
- public static final int BACKGROUND = 0xff282828;
-
- private static final Typeface CONDENSED =
- Typeface.create("sans-serif-condensed", Typeface.NORMAL);
- private static final int GRAY = 0xff999999; //TextAppearance.StatusBar.Expanded.Network
- private static final int DARK_GRAY = 0xff333333;
-
- private static final long DURATION = new ValueAnimator().getDuration();
- private static final long PAGER_DURATION = DURATION / 2;
- private static final long CLOSE_DELAY = 600;
- private static final long AUTO_ACTIVATE_DELAY = 100;
-
- private final Context mContext;
- private final TextView mModeText;
- private final Switch mModeSwitch;
- private final View mDivider;
- private final UntilPager mUntilPager;
- private final ProgressDots mProgressDots;
- private final View mDivider2;
- private final TextView mSettingsButton;
-
- private Adapter mAdapter;
- private boolean mInit;
- private boolean mAutoActivate;
-
- public ZenModeView(Context context) {
- this(context, null);
- }
-
- public ZenModeView(Context context, AttributeSet attrs) {
- super(context, attrs);
- if (DEBUG) log("new %s()", getClass().getSimpleName());
- mContext = context;
-
- final int iconSize = mContext.getResources()
- .getDimensionPixelSize(com.android.internal.R.dimen.notification_large_icon_width);
- final int topRowSize = iconSize * 2 / 3;
- final int p = topRowSize / 3;
-
- LayoutParams lp = null;
-
- mModeText = new TextView(mContext);
- mModeText.setText(R.string.zen_mode_title);
- mModeText.setId(android.R.id.title);
- mModeText.setTextColor(GRAY);
- mModeText.setTypeface(CONDENSED);
- mModeText.setAllCaps(true);
- mModeText.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
- mModeText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mModeText.getTextSize() * 1.5f);
- lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
- lp.leftMargin = p;
- addView(mModeText, lp);
-
- mModeSwitch = new Switch(mContext);
- mModeSwitch.setSwitchPadding(0);
- mModeSwitch.setSwitchTypeface(CONDENSED);
- lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
- lp.topMargin = p;
- lp.rightMargin = p;
- lp.addRule(ALIGN_PARENT_RIGHT);
- lp.addRule(ALIGN_BASELINE, mModeText.getId());
- addView(mModeSwitch, lp);
- mModeSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- mAdapter.setMode(isChecked);
- if (!mInit) return;
- postDelayed(new Runnable(){
- @Override
- public void run() {
- mAdapter.close();
- }
- }, CLOSE_DELAY);
- }
- });
-
- mDivider = new View(mContext);
- mDivider.setId(android.R.id.empty);
- mDivider.setBackgroundColor(GRAY);
- lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2);
- lp.addRule(BELOW, mModeText.getId());
- lp.bottomMargin = p;
- addView(mDivider, lp);
-
- mUntilPager = new UntilPager(mContext, iconSize * 3 / 4);
- mUntilPager.setId(android.R.id.tabhost);
- lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
- lp.leftMargin = lp.rightMargin = iconSize / 2;
- lp.addRule(CENTER_HORIZONTAL);
- lp.addRule(BELOW, mDivider.getId());
- addView(mUntilPager, lp);
-
- mProgressDots = new ProgressDots(mContext, iconSize / 5);
- mProgressDots.setId(android.R.id.progress);
- lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
- lp.addRule(CENTER_HORIZONTAL);
- lp.addRule(BELOW, mUntilPager.getId());
- addView(mProgressDots, lp);
-
- mDivider2 = new View(mContext);
- mDivider2.setId(android.R.id.widget_frame);
- mDivider2.setBackgroundColor(GRAY);
- lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2);
- lp.addRule(BELOW, mProgressDots.getId());
- addView(mDivider2, lp);
-
- mSettingsButton = new TextView(mContext);
- mSettingsButton.setTypeface(CONDENSED);
- mSettingsButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, mSettingsButton.getTextSize() * 1.3f);
- mSettingsButton.setPadding(p, p, p, p);
- mSettingsButton.setText("More settings...");
- lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
- lp.addRule(BELOW, mDivider2.getId());
- addView(mSettingsButton, lp);
- mSettingsButton.setOnTouchListener(new OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- mSettingsButton.setBackgroundColor(DARK_GRAY);
- } else if (event.getAction() == MotionEvent.ACTION_UP) {
- mSettingsButton.setBackground(null);
- if (mAdapter != null) {
- mAdapter.configure();
- }
- }
- return true;
- }
- });
- }
-
- public void setAdapter(Adapter adapter) {
- mAdapter = adapter;
- mAdapter.setCallbacks(new Adapter.Callbacks() {
- @Override
- public void onChanged() {
- post(new Runnable() {
- @Override
- public void run() {
- updateState(true);
- }
- });
- }
- });
- updateState(false);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- if (mAutoActivate) {
- mAutoActivate = false;
- postDelayed(new Runnable() {
- @Override
- public void run() {
- if (!mModeSwitch.isChecked()) {
- mInit = false;
- mModeSwitch.setChecked(true);
- }
- }
- }, AUTO_ACTIVATE_DELAY);
- }
- }
-
- @Override
- protected void onDetachedFromWindow() {
- if (mAdapter != null) {
- mAdapter.dispose();
- }
- }
-
- public void setAutoActivate(boolean value) {
- mAutoActivate = value;
- }
-
- private void updateState(boolean animate) {
- mUntilPager.updateState();
- mModeSwitch.setChecked(mAdapter.getMode());
- mInit = true;
- }
-
- private static void log(String msg, Object... args) {
- Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args));
- }
-
- private final class UntilView extends FrameLayout {
- private static final boolean SUPPORT_LINKS = false;
-
- private final TextView mText;
- public UntilView(Context context) {
- super(context);
- mText = new TextView(mContext);
- mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mText.getTextSize() * 1.3f);
- mText.setTypeface(CONDENSED);
- mText.setTextColor(GRAY);
- mText.setGravity(Gravity.CENTER);
- addView(mText);
- }
-
- public void setExitCondition(final ExitCondition ec) {
- SpannableStringBuilder ss = new SpannableStringBuilder(ec.summary);
- if (SUPPORT_LINKS && ec.action != null) {
- ss.setSpan(new CustomLinkSpan() {
- @Override
- public void onClick() {
- // TODO wire up links
- Toast.makeText(mContext, ec.action, Toast.LENGTH_SHORT).show();
- }
- }, 0, ss.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
- mText.setMovementMethod(LinkMovementMethod.getInstance());
- } else {
- mText.setMovementMethod(null);
- }
- mText.setText(ss);
- }
- }
-
- private final class ProgressDots extends LinearLayout {
- private final int mDotSize;
- public ProgressDots(Context context, int dotSize) {
- super(context);
- setOrientation(HORIZONTAL);
- mDotSize = dotSize;
- }
-
- private void updateState(int current, int count) {
- while (getChildCount() < count) {
- View dot = new View(mContext);
- OvalShape s = new OvalShape();
- ShapeDrawable sd = new ShapeDrawable(s);
-
- dot.setBackground(sd);
- LayoutParams lp = new LayoutParams(mDotSize, mDotSize);
- lp.leftMargin = lp.rightMargin = mDotSize / 2;
- lp.topMargin = lp.bottomMargin = mDotSize * 2 / 3;
- addView(dot, lp);
- }
- while (getChildCount() > count) {
- removeViewAt(getChildCount() - 1);
- }
- final int N = getChildCount();
- for (int i = 0; i < N; i++) {
- final int color = current == i ? GRAY : DARK_GRAY;
- ((ShapeDrawable)getChildAt(i).getBackground()).setColorFilter(color, Mode.ADD);
- }
- }
- }
-
- private final class UntilPager extends RelativeLayout {
- private final UntilView[] mViews;
- private int mCurrent;
- private float mDownX;
-
- public UntilPager(Context context, int iconSize) {
- super(context);
- mViews = new UntilView[3];
- for (int i = 0; i < mViews.length; i++) {
- UntilView v = new UntilView(mContext);
- LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, iconSize);
- addView(v, lp);
- mViews[i] = v;
- }
- updateState();
- 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) {
- if (left != oldLeft || right != oldRight) {
- updateState();
- }
- }
- });
- setBackgroundColor(DARK_GRAY);
- }
-
- private void updateState() {
- if (mAdapter == null) {
- return;
- }
- UntilView current = mViews[mCurrent];
- current.setExitCondition(mAdapter.getExitCondition(0));
- UntilView next = mViews[mCurrent + 1 % 3];
- next.setExitCondition(mAdapter.getExitCondition(1));
- UntilView prev = mViews[mCurrent + 2 % 3];
- prev.setExitCondition(mAdapter.getExitCondition(-1));
- position(0, false);
- mProgressDots.updateState(mAdapter.getExitConditionIndex(),
- mAdapter.getExitConditionCount());
- }
-
- private void position(float dx, boolean animate) {
- int w = getWidth();
- UntilView current = mViews[mCurrent];
- UntilView next = mViews[mCurrent + 1 % 3];
- UntilView prev = mViews[mCurrent + 2 % 3];
- if (animate) {
- current.animate().setDuration(PAGER_DURATION).translationX(dx).start();
- next.animate().setDuration(PAGER_DURATION).translationX(w + dx).start();
- prev.animate().setDuration(PAGER_DURATION).translationX(-w + dx).start();
- } else {
- current.setTranslationX(dx);
- next.setTranslationX(w + dx);
- prev.setTranslationX(-w + dx);
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (DEBUG) log("onTouchEvent " + MotionEvent.actionToString(event.getAction()));
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- mDownX = event.getX();
- } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
- float dx = event.getX() - mDownX;
- position(dx, false);
- } else if (event.getAction() == MotionEvent.ACTION_UP
- || event.getAction() == MotionEvent.ACTION_CANCEL) {
- float dx = event.getX() - mDownX;
- int d = Math.abs(dx) < getWidth() / 3 ? 0 : Math.signum(dx) > 0 ? -1 : 1;
- if (d != 0 && mAdapter.getExitConditionCount() > 1) {
- mAdapter.select(mAdapter.getExitCondition(d));
- } else {
- position(0, true);
- }
- }
- return true;
- }
- }
-
- private abstract static class CustomLinkSpan extends URLSpan {
- abstract public void onClick();
-
- public CustomLinkSpan() {
- super("#");
- }
-
- @Override
- public void updateDrawState(TextPaint ds) {
- super.updateDrawState(ds);
- ds.setUnderlineText(false);
- ds.bgColor = BACKGROUND;
- }
-
- @Override
- public void onClick(View widget) {
- onClick();
- }
- }
-
- public interface Adapter {
- void configure();
- void close();
- boolean getMode();
- void setMode(boolean mode);
- void select(ExitCondition ec);
- void init();
- void dispose();
- void setCallbacks(Callbacks callbacks);
- ExitCondition getExitCondition(int d);
- int getExitConditionCount();
- int getExitConditionIndex();
-
- public static class ExitCondition {
- public String summary;
- public String line1;
- public String line2;
- public String action;
- public Object tag;
- }
-
- public interface Callbacks {
- void onChanged();
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
deleted file mode 100644
index 8748888..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.app.INotificationManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.provider.Settings;
-import android.service.notification.Condition;
-import android.service.notification.IConditionListener;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
- private static final String TAG = "ZenModeViewAdapter";
-
- private final Context mContext;
- private final ContentResolver mResolver;
- private final Handler mHandler = new Handler();
- private final SettingsObserver mObserver;
- private final List<ExitCondition> mExits = new ArrayList<ExitCondition>(Arrays.asList(
- newExit("Until you turn this off", "Until", "You turn this off", null)));
- private final INotificationManager mNoMan;
- private final ArrayMap<Uri, Condition> mConditions = new ArrayMap<Uri, Condition>();
-
- private Callbacks mCallbacks;
- private int mExitIndex;
- private boolean mMode;
-
- public ZenModeViewAdapter(Context context) {
- mContext = context;
- mResolver = mContext.getContentResolver();
- mObserver = new SettingsObserver(mHandler);
- mNoMan = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
- try {
- mNoMan.requestZenModeConditions(mListener, Condition.FLAG_RELEVANT_NOW);
- } catch (RemoteException e) {
- // noop
- }
- mObserver.init();
- init();
- }
-
- @Override
- public boolean getMode() {
- return mMode;
- }
-
- @Override
- public void setMode(boolean mode) {
- if (mode == mMode) return;
- mMode = mode;
- final int v = mMode ? Settings.Global.ZEN_MODE_ON : Settings.Global.ZEN_MODE_OFF;
- AsyncTask.execute(new Runnable() {
- @Override
- public void run() {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.ZEN_MODE, v);
- }
- });
- dispatchChanged();
- }
-
- @Override
- public void init() {
- if (mExitIndex != 0) {
- mExitIndex = 0;
- dispatchChanged();
- }
- setZenModeCondition();
- }
-
- @Override
- public void dispose() {
- try {
- mNoMan.requestZenModeConditions(mListener, 0 /*none*/);
- } catch (RemoteException e) {
- // noop
- }
- }
-
- private void dispatchChanged() {
- mHandler.removeCallbacks(mChanged);
- mHandler.post(mChanged);
- }
-
- @Override
- public void setCallbacks(final Callbacks callbacks) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mCallbacks = callbacks;
- }
- });
- }
-
- @Override
- public ExitCondition getExitCondition(int d) {
- final int n = mExits.size();
- final int i = (n + (mExitIndex + (int)Math.signum(d))) % n;
- return mExits.get(i);
- }
-
- @Override
- public int getExitConditionCount() {
- return mExits.size();
- }
-
- @Override
- public int getExitConditionIndex() {
- return mExitIndex;
- }
-
- @Override
- public void select(ExitCondition ec) {
- final int i = mExits.indexOf(ec);
- if (i == -1 || i == mExitIndex) {
- return;
- }
- mExitIndex = i;
- dispatchChanged();
- setZenModeCondition();
- }
-
- private void setZenModeCondition() {
- if (mExitIndex < 0 || mExitIndex >= mExits.size()) {
- Log.w(TAG, "setZenModeCondition to bad index " + mExitIndex + " of " + mExits.size());
- return;
- }
- final Uri conditionUri = (Uri) mExits.get(mExitIndex).tag;
- try {
- mNoMan.setZenModeCondition(conditionUri);
- } catch (RemoteException e) {
- // noop
- }
- }
-
- private static ExitCondition newExit(String summary, String line1, String line2, Object tag) {
- final ExitCondition rt = new ExitCondition();
- rt.summary = summary;
- rt.line1 = line1;
- rt.line2 = line2;
- rt.tag = tag;
- return rt;
- }
-
- private final Runnable mChanged = new Runnable() {
- public void run() {
- if (mCallbacks == null) {
- return;
- }
- try {
- mCallbacks.onChanged();
- } catch (Throwable t) {
- Log.w(TAG, "Error dispatching onChanged to " + mCallbacks, t);
- }
- }
- };
-
- private final class SettingsObserver extends ContentObserver {
- public SettingsObserver(Handler handler) {
- super(handler);
- }
-
- public void init() {
- loadSettings();
- mResolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
- false, this);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- loadSettings();
- mChanged.run(); // already on handler
- }
-
- private void loadSettings() {
- mMode = getModeFromSetting();
- }
-
- private boolean getModeFromSetting() {
- final int v = Settings.Global.getInt(mResolver,
- Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
- return v != Settings.Global.ZEN_MODE_OFF;
- }
- }
-
- private final IConditionListener mListener = new IConditionListener.Stub() {
- @Override
- public void onConditionsReceived(Condition[] conditions) {
- if (conditions == null || conditions.length == 0) return;
- for (Condition c : conditions) {
- mConditions.put(c.id, c);
- }
- for (int i = mExits.size() - 1; i > 0; i--) {
- mExits.remove(i);
- }
- for (Condition c : mConditions.values()) {
- mExits.add(newExit(c.summary, c.line1, c.line2, c.id));
- }
- dispatchChanged();
- }
- };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index 0e53f0d..f4145cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,87 +16,14 @@
package com.android.systemui.statusbar.policy;
-import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
-import android.bluetooth.BluetoothDevice;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
+public interface BluetoothController {
+ void addStateChangedCallback(BluetoothStateChangeCallback callback);
+ void removeStateChangedCallback(BluetoothStateChangeCallback callback);
-public class BluetoothController extends BroadcastReceiver {
- private static final String TAG = "StatusBar.BluetoothController";
-
- private boolean mEnabled = false;
-
- private Set<BluetoothDevice> mBondedDevices = new HashSet<BluetoothDevice>();
-
- private ArrayList<BluetoothStateChangeCallback> mChangeCallbacks =
- new ArrayList<BluetoothStateChangeCallback>();
-
- public BluetoothController(Context context) {
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
- filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
- filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
- context.registerReceiver(this, filter);
-
- final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- if (adapter != null) {
- handleAdapterStateChange(adapter.getState());
- }
- fireCallbacks();
- updateBondedBluetoothDevices();
- }
-
- public void addStateChangedCallback(BluetoothStateChangeCallback cb) {
- mChangeCallbacks.add(cb);
- }
-
- public Set<BluetoothDevice> getBondedBluetoothDevices() {
- return mBondedDevices;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
-
- if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
- handleAdapterStateChange(
- intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR));
- }
- fireCallbacks();
- updateBondedBluetoothDevices();
- }
-
- private void updateBondedBluetoothDevices() {
- mBondedDevices.clear();
-
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- if (adapter != null) {
- Set<BluetoothDevice> devices = adapter.getBondedDevices();
- if (devices != null) {
- for (BluetoothDevice device : devices) {
- if (device.getBondState() != BluetoothDevice.BOND_NONE) {
- mBondedDevices.add(device);
- }
- }
- }
- }
- }
-
- private void handleAdapterStateChange(int adapterState) {
- mEnabled = (adapterState == BluetoothAdapter.STATE_ON);
- }
-
- private void fireCallbacks() {
- for (BluetoothStateChangeCallback cb : mChangeCallbacks) {
- cb.onBluetoothStateChange(mEnabled);
- }
- }
+ boolean isBluetoothSupported();
+ boolean isBluetoothEnabled();
+ boolean isBluetoothConnected();
+ void setBluetoothEnabled(boolean enabled);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
new file mode 100644
index 0000000..1c7119f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -0,0 +1,137 @@
+/*
+ * 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.systemui.statusbar.policy;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+public class BluetoothControllerImpl extends BroadcastReceiver implements BluetoothController {
+ private static final String TAG = "StatusBar.BluetoothController";
+
+ private final BluetoothAdapter mAdapter;
+
+ private boolean mEnabled = false;
+
+ private Set<BluetoothDevice> mBondedDevices = new HashSet<BluetoothDevice>();
+
+ private ArrayList<BluetoothStateChangeCallback> mChangeCallbacks =
+ new ArrayList<BluetoothStateChangeCallback>();
+
+ public BluetoothControllerImpl(Context context) {
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+ filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
+ filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+ context.registerReceiver(this, filter);
+
+ final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null) {
+ handleAdapterStateChange(adapter.getState());
+ }
+ fireCallbacks();
+ updateBondedBluetoothDevices();
+ }
+
+ public void addStateChangedCallback(BluetoothStateChangeCallback cb) {
+ mChangeCallbacks.add(cb);
+ }
+
+ @Override
+ public void removeStateChangedCallback(BluetoothStateChangeCallback cb) {
+ mChangeCallbacks.remove(cb);
+ }
+
+ @Override
+ public boolean isBluetoothEnabled() {
+ return mAdapter != null && mAdapter.isEnabled();
+ }
+
+ @Override
+ public boolean isBluetoothConnected() {
+ return mAdapter != null
+ && mAdapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED;
+ }
+
+ @Override
+ public void setBluetoothEnabled(boolean enabled) {
+ if (mAdapter != null) {
+ if (enabled) {
+ mAdapter.enable();
+ } else {
+ mAdapter.disable();
+ }
+ }
+ }
+
+ @Override
+ public boolean isBluetoothSupported() {
+ return mAdapter != null;
+ }
+
+ public Set<BluetoothDevice> getBondedBluetoothDevices() {
+ return mBondedDevices;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+
+ if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+ handleAdapterStateChange(
+ intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR));
+ }
+ fireCallbacks();
+ updateBondedBluetoothDevices();
+ }
+
+ private void updateBondedBluetoothDevices() {
+ mBondedDevices.clear();
+
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null) {
+ Set<BluetoothDevice> devices = adapter.getBondedDevices();
+ if (devices != null) {
+ for (BluetoothDevice device : devices) {
+ if (device.getBondState() != BluetoothDevice.BOND_NONE) {
+ mBondedDevices.add(device);
+ }
+ }
+ }
+ }
+ }
+
+ private void handleAdapterStateChange(int adapterState) {
+ mEnabled = (adapterState == BluetoothAdapter.STATE_ON);
+ }
+
+ private void fireCallbacks() {
+ for (BluetoothStateChangeCallback cb : mChangeCallbacks) {
+ cb.onBluetoothStateChange(mEnabled);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
new file mode 100644
index 0000000..54041e1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+public interface CastController {
+ void addCallback(Callback callback);
+ void removeCallback(Callback callback);
+ void setDiscovering(boolean request);
+ void setCurrentUserId(int currentUserId);
+
+ public interface Callback {
+ void onStateChanged(boolean enabled, boolean connecting, String connectedRouteName);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
new file mode 100644
index 0000000..33a85b1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.media.MediaRouter;
+import android.media.MediaRouter.RouteInfo;
+
+import java.util.ArrayList;
+
+/** Platform implementation of the cast controller. **/
+public class CastControllerImpl implements CastController {
+
+ private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+ private final MediaRouter mMediaRouter;
+
+ public CastControllerImpl(Context context) {
+ mMediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+ }
+
+ @Override
+ public void addCallback(Callback callback) {
+ mCallbacks.add(callback);
+ }
+
+ @Override
+ public void removeCallback(Callback callback) {
+ mCallbacks.remove(callback);
+ }
+
+ @Override
+ public void setDiscovering(boolean request) {
+ if (request) {
+ mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+ mMediaCallback,
+ MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
+ } else {
+ mMediaRouter.removeCallback(mMediaCallback);
+ }
+ }
+
+ @Override
+ public void setCurrentUserId(int currentUserId) {
+ mMediaRouter.rebindAsUser(currentUserId);
+ }
+
+ private void updateRemoteDisplays() {
+ final MediaRouter.RouteInfo connectedRoute = mMediaRouter.getSelectedRoute(
+ MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+ boolean enabled = connectedRoute != null
+ && connectedRoute.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+ boolean connecting;
+ if (enabled) {
+ connecting = connectedRoute.isConnecting();
+ } else {
+ connecting = false;
+ enabled = mMediaRouter.isRouteAvailable(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+ MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE);
+ }
+
+ String connectedRouteName = null;
+ if (connectedRoute != null) {
+ connectedRouteName = connectedRoute.getName().toString();
+ }
+ fireStateChanged(enabled, connecting, connectedRouteName);
+ }
+
+ private void fireStateChanged(boolean enabled, boolean connecting, String connectedRouteName) {
+ for (Callback callback : mCallbacks) {
+ callback.onStateChanged(enabled, connecting, connectedRouteName);
+ }
+ }
+
+ private final MediaRouter.SimpleCallback mMediaCallback = new MediaRouter.SimpleCallback() {
+ @Override
+ public void onRouteAdded(MediaRouter router, RouteInfo route) {
+ updateRemoteDisplays();
+ }
+ @Override
+ public void onRouteChanged(MediaRouter router, RouteInfo route) {
+ updateRemoteDisplays();
+ }
+ @Override
+ public void onRouteRemoved(MediaRouter router, RouteInfo route) {
+ updateRemoteDisplays();
+ }
+ @Override
+ public void onRouteSelected(MediaRouter router, int type, RouteInfo route) {
+ updateRemoteDisplays();
+ }
+ @Override
+ public void onRouteUnselected(MediaRouter router, int type, RouteInfo route) {
+ updateRemoteDisplays();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 8ced1c9..55a0bba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.TypedArray;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
@@ -30,6 +31,7 @@
import android.widget.TextView;
import com.android.systemui.DemoMode;
+import com.android.systemui.R;
import java.text.SimpleDateFormat;
import java.util.Calendar;
@@ -52,7 +54,7 @@
private static final int AM_PM_STYLE_SMALL = 1;
private static final int AM_PM_STYLE_GONE = 2;
- private static final int AM_PM_STYLE = AM_PM_STYLE_GONE;
+ private final int mAmPmStyle;
public Clock(Context context) {
this(context, null);
@@ -64,6 +66,15 @@
public Clock(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+ TypedArray a = context.getTheme().obtainStyledAttributes(
+ attrs,
+ R.styleable.Clock,
+ 0, 0);
+ try {
+ mAmPmStyle = a.getInt(R.styleable.Clock_amPmStyle, AM_PM_STYLE_GONE);
+ } finally {
+ a.recycle();
+ }
}
@Override
@@ -145,7 +156,7 @@
* add dummy characters around it to let us find it again after
* formatting and change its size.
*/
- if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) {
+ if (mAmPmStyle != AM_PM_STYLE_NORMAL) {
int a = -1;
boolean quoted = false;
for (int i = 0; i < format.length(); i++) {
@@ -177,15 +188,15 @@
}
String result = sdf.format(mCalendar.getTime());
- if (AM_PM_STYLE != AM_PM_STYLE_NORMAL) {
+ if (mAmPmStyle != AM_PM_STYLE_NORMAL) {
int magic1 = result.indexOf(MAGIC1);
int magic2 = result.indexOf(MAGIC2);
if (magic1 >= 0 && magic2 > magic1) {
SpannableStringBuilder formatted = new SpannableStringBuilder(result);
- if (AM_PM_STYLE == AM_PM_STYLE_GONE) {
+ if (mAmPmStyle == AM_PM_STYLE_GONE) {
formatted.delete(magic1, magic2+1);
} else {
- if (AM_PM_STYLE == AM_PM_STYLE_SMALL) {
+ if (mAmPmStyle == AM_PM_STYLE_SMALL) {
CharacterStyle style = new RelativeSizeSpan(0.7f);
formatted.setSpan(style, magic1, magic2,
Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java
new file mode 100644
index 0000000..158e9c1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+/** Common interface for items requiring manual cleanup. **/
+public interface Disposable {
+ void dispose();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index f5ee95b..29a8981 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,47 +16,11 @@
package com.android.systemui.statusbar.policy;
-import android.app.ActivityManager;
-import android.app.AppOpsManager;
-import android.app.StatusBarManager;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.location.LocationManager;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-
-import com.android.systemui.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A controller to manage changes of location related states and update the views accordingly.
- */
-public class LocationController extends BroadcastReceiver {
- // The name of the placeholder corresponding to the location request status icon.
- // This string corresponds to config_statusBarIcons in core/res/res/values/config.xml.
- public static final String LOCATION_STATUS_ICON_PLACEHOLDER = "location";
- public static final int LOCATION_STATUS_ICON_ID
- = R.drawable.stat_sys_device_access_location_found;
-
- private static final int[] mHighPowerRequestAppOpArray
- = new int[] {AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION};
-
- private Context mContext;
-
- private AppOpsManager mAppOpsManager;
- private StatusBarManager mStatusBarManager;
-
- private boolean mAreActiveLocationRequests;
-
- private ArrayList<LocationSettingsChangeCallback> mSettingsChangeCallbacks =
- new ArrayList<LocationSettingsChangeCallback>();
+public interface LocationController {
+ boolean isLocationEnabled();
+ boolean setLocationEnabled(boolean enabled);
+ void addSettingsChangedCallback(LocationSettingsChangeCallback cb);
+ void removeSettingsChangedCallback(LocationSettingsChangeCallback cb);
/**
* A callback for change in location settings (the user has enabled/disabled location).
@@ -68,156 +32,6 @@
* @param locationEnabled A value of true indicates that at least one type of location
* is enabled in settings.
*/
- public void onLocationSettingsChanged(boolean locationEnabled);
- }
-
- public LocationController(Context context) {
- mContext = context;
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
- context.registerReceiver(this, filter);
-
- mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
- mStatusBarManager
- = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
-
- // Register to listen for changes in location settings.
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION);
- context.registerReceiverAsUser(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
- locationSettingsChanged();
- }
- }
- }, UserHandle.ALL, intentFilter, null, new Handler());
-
- // Examine the current location state and initialize the status view.
- updateActiveLocationRequests();
- refreshViews();
- }
-
- /**
- * Add a callback to listen for changes in location settings.
- */
- public void addSettingsChangedCallback(LocationSettingsChangeCallback cb) {
- mSettingsChangeCallbacks.add(cb);
- }
-
- /**
- * Enable or disable location in settings.
- *
- * <p>This will attempt to enable/disable every type of location setting
- * (e.g. high and balanced power).
- *
- * <p>If enabling, a user consent dialog will pop up prompting the user to accept.
- * If the user doesn't accept, network location won't be enabled.
- *
- * @return true if attempt to change setting was successful.
- */
- public boolean setLocationEnabled(boolean enabled) {
- int currentUserId = ActivityManager.getCurrentUser();
- if (isUserLocationRestricted(currentUserId)) {
- return false;
- }
- final ContentResolver cr = mContext.getContentResolver();
- // When enabling location, a user consent dialog will pop up, and the
- // setting won't be fully enabled until the user accepts the agreement.
- int mode = enabled
- ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY : Settings.Secure.LOCATION_MODE_OFF;
- // QuickSettings always runs as the owner, so specifically set the settings
- // for the current foreground user.
- return Settings.Secure
- .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
- }
-
- /**
- * Returns true if location isn't disabled in settings.
- */
- public boolean isLocationEnabled() {
- ContentResolver resolver = mContext.getContentResolver();
- // QuickSettings always runs as the owner, so specifically retrieve the settings
- // for the current foreground user.
- int mode = Settings.Secure.getIntForUser(resolver, Settings.Secure.LOCATION_MODE,
- Settings.Secure.LOCATION_MODE_OFF, ActivityManager.getCurrentUser());
- return mode != Settings.Secure.LOCATION_MODE_OFF;
- }
-
- /**
- * Returns true if the current user is restricted from using location.
- */
- private boolean isUserLocationRestricted(int userId) {
- final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- return um.hasUserRestriction(
- UserManager.DISALLOW_SHARE_LOCATION,
- new UserHandle(userId));
- }
-
- /**
- * Returns true if there currently exist active high power location requests.
- */
- private boolean areActiveHighPowerLocationRequests() {
- List<AppOpsManager.PackageOps> packages
- = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray);
- // AppOpsManager can return null when there is no requested data.
- if (packages != null) {
- final int numPackages = packages.size();
- for (int packageInd = 0; packageInd < numPackages; packageInd++) {
- AppOpsManager.PackageOps packageOp = packages.get(packageInd);
- List<AppOpsManager.OpEntry> opEntries = packageOp.getOps();
- if (opEntries != null) {
- final int numOps = opEntries.size();
- for (int opInd = 0; opInd < numOps; opInd++) {
- AppOpsManager.OpEntry opEntry = opEntries.get(opInd);
- // AppOpsManager should only return OP_MONITOR_HIGH_POWER_LOCATION because
- // of the mHighPowerRequestAppOpArray filter, but checking defensively.
- if (opEntry.getOp() == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) {
- if (opEntry.isRunning()) {
- return true;
- }
- }
- }
- }
- }
- }
-
- return false;
- }
-
- // Updates the status view based on the current state of location requests.
- private void refreshViews() {
- if (mAreActiveLocationRequests) {
- mStatusBarManager.setIcon(LOCATION_STATUS_ICON_PLACEHOLDER, LOCATION_STATUS_ICON_ID, 0,
- mContext.getString(R.string.accessibility_location_active));
- } else {
- mStatusBarManager.removeIcon(LOCATION_STATUS_ICON_PLACEHOLDER);
- }
- }
-
- // Reads the active location requests and updates the status view if necessary.
- private void updateActiveLocationRequests() {
- boolean hadActiveLocationRequests = mAreActiveLocationRequests;
- mAreActiveLocationRequests = areActiveHighPowerLocationRequests();
- if (mAreActiveLocationRequests != hadActiveLocationRequests) {
- refreshViews();
- }
- }
-
- private void locationSettingsChanged() {
- boolean isEnabled = isLocationEnabled();
- for (LocationSettingsChangeCallback cb : mSettingsChangeCallbacks) {
- cb.onLocationSettingsChanged(isEnabled);
- }
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
- updateActiveLocationRequests();
- }
+ void onLocationSettingsChanged(boolean locationEnabled);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
new file mode 100644
index 0000000..9e5ad18
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -0,0 +1,214 @@
+/*
+ * 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.systemui.statusbar.policy;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.location.LocationManager;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A controller to manage changes of location related states and update the views accordingly.
+ */
+public class LocationControllerImpl extends BroadcastReceiver implements LocationController {
+ // The name of the placeholder corresponding to the location request status icon.
+ // This string corresponds to config_statusBarIcons in core/res/res/values/config.xml.
+ public static final String LOCATION_STATUS_ICON_PLACEHOLDER = "location";
+ public static final int LOCATION_STATUS_ICON_ID
+ = R.drawable.stat_sys_device_access_location_found;
+
+ private static final int[] mHighPowerRequestAppOpArray
+ = new int[] {AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION};
+
+ private Context mContext;
+
+ private AppOpsManager mAppOpsManager;
+ private StatusBarManager mStatusBarManager;
+
+ private boolean mAreActiveLocationRequests;
+
+ private ArrayList<LocationSettingsChangeCallback> mSettingsChangeCallbacks =
+ new ArrayList<LocationSettingsChangeCallback>();
+
+ public LocationControllerImpl(Context context) {
+ mContext = context;
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
+ context.registerReceiver(this, filter);
+
+ mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ mStatusBarManager
+ = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
+
+ // Register to listen for changes in location settings.
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION);
+ context.registerReceiverAsUser(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
+ locationSettingsChanged();
+ }
+ }
+ }, UserHandle.ALL, intentFilter, null, new Handler());
+
+ // Examine the current location state and initialize the status view.
+ updateActiveLocationRequests();
+ refreshViews();
+ }
+
+ /**
+ * Add a callback to listen for changes in location settings.
+ */
+ public void addSettingsChangedCallback(LocationSettingsChangeCallback cb) {
+ mSettingsChangeCallbacks.add(cb);
+ }
+
+ public void removeSettingsChangedCallback(LocationSettingsChangeCallback cb) {
+ mSettingsChangeCallbacks.remove(cb);
+ }
+
+ /**
+ * Enable or disable location in settings.
+ *
+ * <p>This will attempt to enable/disable every type of location setting
+ * (e.g. high and balanced power).
+ *
+ * <p>If enabling, a user consent dialog will pop up prompting the user to accept.
+ * If the user doesn't accept, network location won't be enabled.
+ *
+ * @return true if attempt to change setting was successful.
+ */
+ public boolean setLocationEnabled(boolean enabled) {
+ int currentUserId = ActivityManager.getCurrentUser();
+ if (isUserLocationRestricted(currentUserId)) {
+ return false;
+ }
+ final ContentResolver cr = mContext.getContentResolver();
+ // When enabling location, a user consent dialog will pop up, and the
+ // setting won't be fully enabled until the user accepts the agreement.
+ int mode = enabled
+ ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY : Settings.Secure.LOCATION_MODE_OFF;
+ // QuickSettings always runs as the owner, so specifically set the settings
+ // for the current foreground user.
+ return Settings.Secure
+ .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
+ }
+
+ /**
+ * Returns true if location isn't disabled in settings.
+ */
+ public boolean isLocationEnabled() {
+ ContentResolver resolver = mContext.getContentResolver();
+ // QuickSettings always runs as the owner, so specifically retrieve the settings
+ // for the current foreground user.
+ int mode = Settings.Secure.getIntForUser(resolver, Settings.Secure.LOCATION_MODE,
+ Settings.Secure.LOCATION_MODE_OFF, ActivityManager.getCurrentUser());
+ return mode != Settings.Secure.LOCATION_MODE_OFF;
+ }
+
+ /**
+ * Returns true if the current user is restricted from using location.
+ */
+ private boolean isUserLocationRestricted(int userId) {
+ final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ return um.hasUserRestriction(
+ UserManager.DISALLOW_SHARE_LOCATION,
+ new UserHandle(userId));
+ }
+
+ /**
+ * Returns true if there currently exist active high power location requests.
+ */
+ private boolean areActiveHighPowerLocationRequests() {
+ List<AppOpsManager.PackageOps> packages
+ = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray);
+ // AppOpsManager can return null when there is no requested data.
+ if (packages != null) {
+ final int numPackages = packages.size();
+ for (int packageInd = 0; packageInd < numPackages; packageInd++) {
+ AppOpsManager.PackageOps packageOp = packages.get(packageInd);
+ List<AppOpsManager.OpEntry> opEntries = packageOp.getOps();
+ if (opEntries != null) {
+ final int numOps = opEntries.size();
+ for (int opInd = 0; opInd < numOps; opInd++) {
+ AppOpsManager.OpEntry opEntry = opEntries.get(opInd);
+ // AppOpsManager should only return OP_MONITOR_HIGH_POWER_LOCATION because
+ // of the mHighPowerRequestAppOpArray filter, but checking defensively.
+ if (opEntry.getOp() == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) {
+ if (opEntry.isRunning()) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ // Updates the status view based on the current state of location requests.
+ private void refreshViews() {
+ if (mAreActiveLocationRequests) {
+ mStatusBarManager.setIcon(LOCATION_STATUS_ICON_PLACEHOLDER, LOCATION_STATUS_ICON_ID, 0,
+ mContext.getString(R.string.accessibility_location_active));
+ } else {
+ mStatusBarManager.removeIcon(LOCATION_STATUS_ICON_PLACEHOLDER);
+ }
+ }
+
+ // Reads the active location requests and updates the status view if necessary.
+ private void updateActiveLocationRequests() {
+ boolean hadActiveLocationRequests = mAreActiveLocationRequests;
+ mAreActiveLocationRequests = areActiveHighPowerLocationRequests();
+ if (mAreActiveLocationRequests != hadActiveLocationRequests) {
+ refreshViews();
+ }
+ }
+
+ private void locationSettingsChanged() {
+ boolean isEnabled = isLocationEnabled();
+ for (LocationSettingsChangeCallback cb : mSettingsChangeCallbacks) {
+ cb.onLocationSettingsChanged(isEnabled);
+ }
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
+ updateActiveLocationRequests();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 92c008e..dc8f315 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,153 +16,12 @@
package com.android.systemui.statusbar.policy;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.net.wimax.WimaxManagerConstants;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
-import android.provider.Settings;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.view.View;
-import android.widget.TextView;
+public interface NetworkController {
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.cdma.EriInfo;
-import com.android.internal.util.AsyncChannel;
-import com.android.systemui.DemoMode;
-import com.android.systemui.R;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-public class NetworkController extends BroadcastReceiver implements DemoMode {
- // debug
- static final String TAG = "StatusBar.NetworkController";
- static final boolean DEBUG = false;
- static final boolean CHATTY = false; // additional diagnostics, but not logspew
-
- private static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_signal_flightmode;
-
- // telephony
- boolean mHspaDataDistinguishable;
- final TelephonyManager mPhone;
- boolean mDataConnected;
- IccCardConstants.State mSimState = IccCardConstants.State.READY;
- int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
- int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
- int mDataState = TelephonyManager.DATA_DISCONNECTED;
- int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
- ServiceState mServiceState;
- SignalStrength mSignalStrength;
- int[] mDataIconList = TelephonyIcons.DATA_G[0];
- String mNetworkName;
- String mNetworkNameDefault;
- String mNetworkNameSeparator;
- int mPhoneSignalIconId;
- int mQSPhoneSignalIconId;
- int mDataDirectionIconId; // data + data direction on phones
- int mDataSignalIconId;
- int mDataTypeIconId;
- int mQSDataTypeIconId;
- int mAirplaneIconId;
- boolean mDataActive;
- int mLastSignalLevel;
- boolean mShowPhoneRSSIForData = false;
- boolean mShowAtLeastThreeGees = false;
- boolean mAlwaysShowCdmaRssi = false;
-
- String mContentDescriptionPhoneSignal;
- String mContentDescriptionWifi;
- String mContentDescriptionWimax;
- String mContentDescriptionCombinedSignal;
- String mContentDescriptionDataType;
-
- // wifi
- final WifiManager mWifiManager;
- AsyncChannel mWifiChannel;
- boolean mWifiEnabled, mWifiConnected;
- int mWifiRssi, mWifiLevel;
- String mWifiSsid;
- int mWifiIconId = 0;
- int mQSWifiIconId = 0;
- int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE;
-
- // bluetooth
- private boolean mBluetoothTethered = false;
- private int mBluetoothTetherIconId =
- com.android.internal.R.drawable.stat_sys_tether_bluetooth;
-
- //wimax
- private boolean mWimaxSupported = false;
- private boolean mIsWimaxEnabled = false;
- private boolean mWimaxConnected = false;
- private boolean mWimaxIdle = false;
- private int mWimaxIconId = 0;
- private int mWimaxSignal = 0;
- private int mWimaxState = 0;
- private int mWimaxExtraState = 0;
-
- // data connectivity (regardless of state, can we access the internet?)
- // state of inet connection - 0 not connected, 100 connected
- private boolean mConnected = false;
- private int mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
- private String mConnectedNetworkTypeName;
- private int mInetCondition = 0;
- private int mLastInetCondition = 0;
- private static final int INET_CONDITION_THRESHOLD = 50;
-
- private boolean mAirplaneMode = false;
- private boolean mLastAirplaneMode = true;
-
- private Locale mLocale = null;
- private Locale mLastLocale = null;
-
- // our ui
- Context mContext;
- ArrayList<TextView> mCombinedLabelViews = new ArrayList<TextView>();
- ArrayList<TextView> mMobileLabelViews = new ArrayList<TextView>();
- ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>();
- ArrayList<TextView> mEmergencyLabelViews = new ArrayList<TextView>();
- ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
- ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
- new ArrayList<NetworkSignalChangedCallback>();
- int mLastPhoneSignalIconId = -1;
- int mLastDataDirectionIconId = -1;
- int mLastWifiIconId = -1;
- int mLastWimaxIconId = -1;
- int mLastCombinedSignalIconId = -1;
- int mLastDataTypeIconId = -1;
- String mLastCombinedLabel = "";
-
- private boolean mHasMobileDataFeature;
-
- boolean mDataAndWifiStacked = false;
-
- public interface SignalCluster {
- void setWifiIndicators(boolean visible, int strengthIcon, boolean problem,
- String contentDescription);
- void setMobileDataIndicators(boolean visible, int strengthIcon, boolean problem,
- int typeIcon, String contentDescription, String typeContentDescription);
- void setIsAirplaneMode(boolean is, int airplaneIcon);
- }
+ boolean hasMobileDataFeature();
+ void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb);
+ void removeNetworkSignalChangedCallback(NetworkSignalChangedCallback cb);
+ void setWifiEnabled(boolean enabled);
public interface NetworkSignalChangedCallback {
void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
@@ -174,1304 +33,4 @@
String dataTypeContentDescriptionId, String description);
void onAirplaneModeChanged(boolean enabled);
}
-
- /**
- * Construct this controller object and register for updates.
- */
- public NetworkController(Context context) {
- mContext = context;
- final Resources res = context.getResources();
-
- ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- mHasMobileDataFeature = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
-
- mShowPhoneRSSIForData = res.getBoolean(R.bool.config_showPhoneRSSIForData);
- mShowAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G);
- mAlwaysShowCdmaRssi = res.getBoolean(
- com.android.internal.R.bool.config_alwaysUseCdmaRssi);
-
- // set up the default wifi icon, used when no radios have ever appeared
- updateWifiIcons();
- updateWimaxIcons();
-
- // telephony
- mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
- mPhone.listen(mPhoneStateListener,
- PhoneStateListener.LISTEN_SERVICE_STATE
- | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
- | PhoneStateListener.LISTEN_CALL_STATE
- | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
- | PhoneStateListener.LISTEN_DATA_ACTIVITY);
- mHspaDataDistinguishable = mContext.getResources().getBoolean(
- R.bool.config_hspa_data_distinguishable);
- mNetworkNameSeparator = mContext.getString(R.string.status_bar_network_name_separator);
- mNetworkNameDefault = mContext.getString(
- com.android.internal.R.string.lockscreen_carrier_default);
- mNetworkName = mNetworkNameDefault;
-
- // wifi
- mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- Handler handler = new WifiHandler();
- mWifiChannel = new AsyncChannel();
- Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
- if (wifiMessenger != null) {
- mWifiChannel.connect(mContext, handler, wifiMessenger);
- }
-
- // broadcasts
- IntentFilter filter = new IntentFilter();
- filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
- filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
- filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
- filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
- filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
- filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
- filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- mWimaxSupported = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_wimaxEnabled);
- if(mWimaxSupported) {
- filter.addAction(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION);
- filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION);
- filter.addAction(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION);
- }
- context.registerReceiver(this, filter);
-
- // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
- updateAirplaneMode();
-
- mLastLocale = mContext.getResources().getConfiguration().locale;
- }
-
- public boolean hasMobileDataFeature() {
- return mHasMobileDataFeature;
- }
-
- public boolean hasVoiceCallingFeature() {
- return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
- }
-
- public boolean isEmergencyOnly() {
- return (mServiceState != null && mServiceState.isEmergencyOnly());
- }
-
- public void addCombinedLabelView(TextView v) {
- mCombinedLabelViews.add(v);
- }
-
- public void addMobileLabelView(TextView v) {
- mMobileLabelViews.add(v);
- }
-
- public void addWifiLabelView(TextView v) {
- mWifiLabelViews.add(v);
- }
-
- public void addEmergencyLabelView(TextView v) {
- mEmergencyLabelViews.add(v);
- }
-
- public void addSignalCluster(SignalCluster cluster) {
- mSignalClusters.add(cluster);
- refreshSignalCluster(cluster);
- }
-
- public void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
- mSignalsChangedCallbacks.add(cb);
- notifySignalsChangedCallbacks(cb);
- }
-
- public void refreshSignalCluster(SignalCluster cluster) {
- if (mDemoMode) return;
- cluster.setWifiIndicators(
- // only show wifi in the cluster if connected or if wifi-only
- mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature),
- mWifiIconId,
- mInetCondition == 0,
- mContentDescriptionWifi);
-
- if (mIsWimaxEnabled && mWimaxConnected) {
- // wimax is special
- cluster.setMobileDataIndicators(
- true,
- mAlwaysShowCdmaRssi ? mPhoneSignalIconId : mWimaxIconId,
- mInetCondition == 0,
- mDataTypeIconId,
- mContentDescriptionWimax,
- mContentDescriptionDataType);
- } else {
- // normal mobile data
- cluster.setMobileDataIndicators(
- mHasMobileDataFeature,
- mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
- mInetCondition == 0,
- mDataTypeIconId,
- mContentDescriptionPhoneSignal,
- mContentDescriptionDataType);
- }
- cluster.setIsAirplaneMode(mAirplaneMode, mAirplaneIconId);
- }
-
- void notifySignalsChangedCallbacks(NetworkSignalChangedCallback cb) {
- // only show wifi in the cluster if connected or if wifi-only
- boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature);
- String wifiDesc = wifiEnabled ?
- mWifiSsid : null;
- boolean wifiIn = wifiEnabled && mWifiSsid != null
- && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
- || mWifiActivity == WifiManager.DATA_ACTIVITY_IN);
- boolean wifiOut = wifiEnabled && mWifiSsid != null
- && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
- || mWifiActivity == WifiManager.DATA_ACTIVITY_OUT);
- cb.onWifiSignalChanged(wifiEnabled, mQSWifiIconId, wifiIn, wifiOut,
- mContentDescriptionWifi, wifiDesc);
-
- boolean mobileIn = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
- || mDataActivity == TelephonyManager.DATA_ACTIVITY_IN);
- boolean mobileOut = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
- || mDataActivity == TelephonyManager.DATA_ACTIVITY_OUT);
- if (isEmergencyOnly()) {
- cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId,
- mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
- mContentDescriptionDataType, null);
- } else {
- if (mIsWimaxEnabled && mWimaxConnected) {
- // Wimax is special
- cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId,
- mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
- mContentDescriptionDataType, mNetworkName);
- } else {
- // Normal mobile data
- cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId,
- mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
- mContentDescriptionDataType, mNetworkName);
- }
- }
- cb.onAirplaneModeChanged(mAirplaneMode);
- }
-
- public void setStackedMode(boolean stacked) {
- mDataAndWifiStacked = true;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (action.equals(WifiManager.RSSI_CHANGED_ACTION)
- || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)
- || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
- updateWifiState(intent);
- refreshViews();
- } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
- updateSimState(intent);
- updateDataIcon();
- refreshViews();
- } else if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
- updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
- intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
- intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
- intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
- refreshViews();
- } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
- action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
- updateConnectivity(intent);
- refreshViews();
- } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
- refreshLocale();
- refreshViews();
- } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
- refreshLocale();
- updateAirplaneMode();
- refreshViews();
- } else if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION) ||
- action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) ||
- action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
- updateWimaxState(intent);
- refreshViews();
- }
- }
-
-
- // ===== Telephony ==============================================================
-
- PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
- @Override
- public void onSignalStrengthsChanged(SignalStrength signalStrength) {
- if (DEBUG) {
- Log.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
- ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
- }
- mSignalStrength = signalStrength;
- updateTelephonySignalStrength();
- refreshViews();
- }
-
- @Override
- public void onServiceStateChanged(ServiceState state) {
- if (DEBUG) {
- Log.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
- + " dataState=" + state.getDataRegState());
- }
- mServiceState = state;
- updateTelephonySignalStrength();
- updateDataNetType();
- updateDataIcon();
- refreshViews();
- }
-
- @Override
- public void onCallStateChanged(int state, String incomingNumber) {
- if (DEBUG) {
- Log.d(TAG, "onCallStateChanged state=" + state);
- }
- // In cdma, if a voice call is made, RSSI should switch to 1x.
- if (isCdma()) {
- updateTelephonySignalStrength();
- refreshViews();
- }
- }
-
- @Override
- public void onDataConnectionStateChanged(int state, int networkType) {
- if (DEBUG) {
- Log.d(TAG, "onDataConnectionStateChanged: state=" + state
- + " type=" + networkType);
- }
- mDataState = state;
- mDataNetType = networkType;
- updateDataNetType();
- updateDataIcon();
- refreshViews();
- }
-
- @Override
- public void onDataActivity(int direction) {
- if (DEBUG) {
- Log.d(TAG, "onDataActivity: direction=" + direction);
- }
- mDataActivity = direction;
- updateDataIcon();
- refreshViews();
- }
- };
-
- private final void updateSimState(Intent intent) {
- String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
- if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
- mSimState = IccCardConstants.State.ABSENT;
- }
- else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
- mSimState = IccCardConstants.State.READY;
- }
- else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
- final String lockedReason =
- intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
- if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
- mSimState = IccCardConstants.State.PIN_REQUIRED;
- }
- else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
- mSimState = IccCardConstants.State.PUK_REQUIRED;
- }
- else {
- mSimState = IccCardConstants.State.NETWORK_LOCKED;
- }
- } else {
- mSimState = IccCardConstants.State.UNKNOWN;
- }
- }
-
- private boolean isCdma() {
- return (mSignalStrength != null) && !mSignalStrength.isGsm();
- }
-
- private boolean hasService() {
- if (mServiceState != null) {
- // Consider the device to be in service if either voice or data service is available.
- // Some SIM cards are marketed as data-only and do not support voice service, and on
- // these SIM cards, we want to show signal bars for data service as well as the "no
- // service" or "emergency calls only" text that indicates that voice is not available.
- switch(mServiceState.getVoiceRegState()) {
- case ServiceState.STATE_POWER_OFF:
- return false;
- case ServiceState.STATE_OUT_OF_SERVICE:
- case ServiceState.STATE_EMERGENCY_ONLY:
- return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE;
- default:
- return true;
- }
- } else {
- return false;
- }
- }
-
- private void updateAirplaneMode() {
- mAirplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
- }
-
- private void refreshLocale() {
- mLocale = mContext.getResources().getConfiguration().locale;
- }
-
- private final void updateTelephonySignalStrength() {
- if (!hasService()) {
- if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: !hasService()");
- mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
- mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
- mDataSignalIconId = R.drawable.stat_sys_signal_null;
- } else {
- if (mSignalStrength == null) {
- if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
- mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
- mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
- mDataSignalIconId = R.drawable.stat_sys_signal_null;
- mContentDescriptionPhoneSignal = mContext.getString(
- AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]);
- } else {
- int iconLevel;
- int[] iconList;
- if (isCdma() && mAlwaysShowCdmaRssi) {
- mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel();
- if(DEBUG) Log.d(TAG, "mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi
- + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel()
- + " instead of level=" + mSignalStrength.getLevel());
- } else {
- mLastSignalLevel = iconLevel = mSignalStrength.getLevel();
- }
-
- if (isCdma()) {
- if (isCdmaEri()) {
- iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
- } else {
- iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
- }
- } else {
- // Though mPhone is a Manager, this call is not an IPC
- if (mPhone.isNetworkRoaming()) {
- iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
- } else {
- iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
- }
- }
- mPhoneSignalIconId = iconList[iconLevel];
- mQSPhoneSignalIconId =
- TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mInetCondition][iconLevel];
- mContentDescriptionPhoneSignal = mContext.getString(
- AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]);
- mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel];
- }
- }
- }
-
- private final void updateDataNetType() {
- if (mIsWimaxEnabled && mWimaxConnected) {
- // wimax is a special 4g network not handled by telephony
- mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
- mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_4g);
- } else {
- switch (mDataNetType) {
- case TelephonyManager.NETWORK_TYPE_UNKNOWN:
- if (!mShowAtLeastThreeGees) {
- mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
- mDataTypeIconId = 0;
- mQSDataTypeIconId = 0;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_gprs);
- break;
- } else {
- // fall through
- }
- case TelephonyManager.NETWORK_TYPE_EDGE:
- if (!mShowAtLeastThreeGees) {
- mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_e;
- mQSDataTypeIconId = TelephonyIcons.QS_DATA_E[mInetCondition];
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_edge);
- break;
- } else {
- // fall through
- }
- case TelephonyManager.NETWORK_TYPE_UMTS:
- mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
- mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_3g);
- break;
- case TelephonyManager.NETWORK_TYPE_HSDPA:
- case TelephonyManager.NETWORK_TYPE_HSUPA:
- case TelephonyManager.NETWORK_TYPE_HSPA:
- case TelephonyManager.NETWORK_TYPE_HSPAP:
- if (mHspaDataDistinguishable) {
- mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_h;
- mQSDataTypeIconId = TelephonyIcons.QS_DATA_H[mInetCondition];
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_3_5g);
- } else {
- mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
- mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_3g);
- }
- break;
- case TelephonyManager.NETWORK_TYPE_CDMA:
- if (!mShowAtLeastThreeGees) {
- // display 1xRTT for IS95A/B
- mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
- mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_cdma);
- break;
- } else {
- // fall through
- }
- case TelephonyManager.NETWORK_TYPE_1xRTT:
- if (!mShowAtLeastThreeGees) {
- mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
- mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_cdma);
- break;
- } else {
- // fall through
- }
- case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
- case TelephonyManager.NETWORK_TYPE_EVDO_A:
- case TelephonyManager.NETWORK_TYPE_EVDO_B:
- case TelephonyManager.NETWORK_TYPE_EHRPD:
- mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
- mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_3g);
- break;
- case TelephonyManager.NETWORK_TYPE_LTE:
- boolean show4GforLTE = mContext.getResources().getBoolean(R.bool.config_show4GForLTE);
- if (show4GforLTE) {
- mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
- mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_4g);
- } else {
- mDataIconList = TelephonyIcons.DATA_LTE[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_lte;
- mQSDataTypeIconId = TelephonyIcons.QS_DATA_LTE[mInetCondition];
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_lte);
- }
- break;
- default:
- if (!mShowAtLeastThreeGees) {
- mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_g;
- mQSDataTypeIconId = TelephonyIcons.QS_DATA_G[mInetCondition];
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_gprs);
- } else {
- mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
- mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_3g);
- }
- break;
- }
- }
-
- if (isCdma()) {
- if (isCdmaEri()) {
- mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
- mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
- }
- } else if (mPhone.isNetworkRoaming()) {
- mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
- mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
- }
- }
-
- boolean isCdmaEri() {
- if (mServiceState != null) {
- final int iconIndex = mServiceState.getCdmaEriIconIndex();
- if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
- final int iconMode = mServiceState.getCdmaEriIconMode();
- if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
- || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
- return true;
- }
- }
- }
- return false;
- }
-
- private final void updateDataIcon() {
- int iconId;
- boolean visible = true;
-
- if (!isCdma()) {
- // GSM case, we have to check also the sim state
- if (mSimState == IccCardConstants.State.READY ||
- mSimState == IccCardConstants.State.UNKNOWN) {
- if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
- switch (mDataActivity) {
- case TelephonyManager.DATA_ACTIVITY_IN:
- iconId = mDataIconList[1];
- break;
- case TelephonyManager.DATA_ACTIVITY_OUT:
- iconId = mDataIconList[2];
- break;
- case TelephonyManager.DATA_ACTIVITY_INOUT:
- iconId = mDataIconList[3];
- break;
- default:
- iconId = mDataIconList[0];
- break;
- }
- mDataDirectionIconId = iconId;
- } else {
- iconId = 0;
- visible = false;
- }
- } else {
- iconId = R.drawable.stat_sys_no_sim;
- visible = false; // no SIM? no data
- }
- } else {
- // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
- if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
- switch (mDataActivity) {
- case TelephonyManager.DATA_ACTIVITY_IN:
- iconId = mDataIconList[1];
- break;
- case TelephonyManager.DATA_ACTIVITY_OUT:
- iconId = mDataIconList[2];
- break;
- case TelephonyManager.DATA_ACTIVITY_INOUT:
- iconId = mDataIconList[3];
- break;
- case TelephonyManager.DATA_ACTIVITY_DORMANT:
- default:
- iconId = mDataIconList[0];
- break;
- }
- } else {
- iconId = 0;
- visible = false;
- }
- }
-
- mDataDirectionIconId = iconId;
- mDataConnected = visible;
- }
-
- void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
- if (false) {
- Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
- + " showPlmn=" + showPlmn + " plmn=" + plmn);
- }
- StringBuilder str = new StringBuilder();
- boolean something = false;
- if (showPlmn && plmn != null) {
- str.append(plmn);
- something = true;
- }
- if (showSpn && spn != null) {
- if (something) {
- str.append(mNetworkNameSeparator);
- }
- str.append(spn);
- something = true;
- }
- if (something) {
- mNetworkName = str.toString();
- } else {
- mNetworkName = mNetworkNameDefault;
- }
- }
-
- // ===== Wifi ===================================================================
-
- class WifiHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
- if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- mWifiChannel.sendMessage(Message.obtain(this,
- AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
- } else {
- Log.e(TAG, "Failed to connect to wifi");
- }
- break;
- case WifiManager.DATA_ACTIVITY_NOTIFICATION:
- if (msg.arg1 != mWifiActivity) {
- mWifiActivity = msg.arg1;
- refreshViews();
- }
- break;
- default:
- //Ignore
- break;
- }
- }
- }
-
- private void updateWifiState(Intent intent) {
- final String action = intent.getAction();
- if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
- mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
- WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
-
- } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
- final NetworkInfo networkInfo = (NetworkInfo)
- intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
- boolean wasConnected = mWifiConnected;
- mWifiConnected = networkInfo != null && networkInfo.isConnected();
- // If we just connected, grab the inintial signal strength and ssid
- if (mWifiConnected && !wasConnected) {
- // try getting it out of the intent first
- WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
- if (info == null) {
- info = mWifiManager.getConnectionInfo();
- }
- if (info != null) {
- mWifiSsid = huntForSsid(info);
- } else {
- mWifiSsid = null;
- }
- } else if (!mWifiConnected) {
- mWifiSsid = null;
- }
- } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
- mWifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
- mWifiLevel = WifiManager.calculateSignalLevel(
- mWifiRssi, WifiIcons.WIFI_LEVEL_COUNT);
- }
-
- updateWifiIcons();
- }
-
- private void updateWifiIcons() {
- if (mWifiConnected) {
- mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
- mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
- mContentDescriptionWifi = mContext.getString(
- AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]);
- } else {
- if (mDataAndWifiStacked) {
- mWifiIconId = 0;
- mQSWifiIconId = 0;
- } else {
- mWifiIconId = mWifiEnabled ? R.drawable.stat_sys_wifi_signal_null : 0;
- mQSWifiIconId = mWifiEnabled ? R.drawable.ic_qs_wifi_no_network : 0;
- }
- mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi);
- }
- }
-
- private String huntForSsid(WifiInfo info) {
- String ssid = info.getSSID();
- if (ssid != null) {
- return ssid;
- }
- // OK, it's not in the connectionInfo; we have to go hunting for it
- List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
- for (WifiConfiguration net : networks) {
- if (net.networkId == info.getNetworkId()) {
- return net.SSID;
- }
- }
- return null;
- }
-
-
- // ===== Wimax ===================================================================
- private final void updateWimaxState(Intent intent) {
- final String action = intent.getAction();
- boolean wasConnected = mWimaxConnected;
- if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION)) {
- int wimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_4G_STATE,
- WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
- mIsWimaxEnabled = (wimaxStatus ==
- WimaxManagerConstants.NET_4G_STATE_ENABLED);
- } else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) {
- mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0);
- } else if (action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
- mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
- WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
- mWimaxExtraState = intent.getIntExtra(
- WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL,
- WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
- mWimaxConnected = (mWimaxState ==
- WimaxManagerConstants.WIMAX_STATE_CONNECTED);
- mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE);
- }
- updateDataNetType();
- updateWimaxIcons();
- }
-
- private void updateWimaxIcons() {
- if (mIsWimaxEnabled) {
- if (mWimaxConnected) {
- if (mWimaxIdle)
- mWimaxIconId = WimaxIcons.WIMAX_IDLE;
- else
- mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal];
- mContentDescriptionWimax = mContext.getString(
- AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]);
- } else {
- mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED;
- mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax);
- }
- } else {
- mWimaxIconId = 0;
- }
- }
-
- // ===== Full or limited Internet connectivity ==================================
-
- private void updateConnectivity(Intent intent) {
- if (CHATTY) {
- Log.d(TAG, "updateConnectivity: intent=" + intent);
- }
-
- final ConnectivityManager connManager = (ConnectivityManager) mContext
- .getSystemService(Context.CONNECTIVITY_SERVICE);
- final NetworkInfo info = connManager.getActiveNetworkInfo();
-
- // Are we connected at all, by any interface?
- mConnected = info != null && info.isConnected();
- if (mConnected) {
- mConnectedNetworkType = info.getType();
- mConnectedNetworkTypeName = info.getTypeName();
- } else {
- mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
- mConnectedNetworkTypeName = null;
- }
-
- int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
-
- if (CHATTY) {
- Log.d(TAG, "updateConnectivity: networkInfo=" + info);
- Log.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus);
- }
-
- mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
-
- if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) {
- mBluetoothTethered = info.isConnected();
- } else {
- mBluetoothTethered = false;
- }
-
- // We want to update all the icons, all at once, for any condition change
- updateDataNetType();
- updateWimaxIcons();
- updateDataIcon();
- updateTelephonySignalStrength();
- updateWifiIcons();
- }
-
-
- // ===== Update the views =======================================================
-
- void refreshViews() {
- Context context = mContext;
-
- int combinedSignalIconId = 0;
- String combinedLabel = "";
- String wifiLabel = "";
- String mobileLabel = "";
- int N;
- final boolean emergencyOnly = isEmergencyOnly();
-
- if (!mHasMobileDataFeature) {
- mDataSignalIconId = mPhoneSignalIconId = 0;
- mQSPhoneSignalIconId = 0;
- mobileLabel = "";
- } else {
- // We want to show the carrier name if in service and either:
- // - We are connected to mobile data, or
- // - We are not connected to mobile data, as long as the *reason* packets are not
- // being routed over that link is that we have better connectivity via wifi.
- // If data is disconnected for some other reason but wifi (or ethernet/bluetooth)
- // is connected, we show nothing.
- // Otherwise (nothing connected) we show "No internet connection".
-
- if (mDataConnected) {
- mobileLabel = mNetworkName;
- } else if (mConnected || emergencyOnly) {
- if (hasService() || emergencyOnly) {
- // The isEmergencyOnly test covers the case of a phone with no SIM
- mobileLabel = mNetworkName;
- } else {
- // Tablets, basically
- mobileLabel = "";
- }
- } else {
- mobileLabel
- = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
- }
-
- // Now for things that should only be shown when actually using mobile data.
- if (mDataConnected) {
- combinedSignalIconId = mDataSignalIconId;
-
- combinedLabel = mobileLabel;
- combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
- mContentDescriptionCombinedSignal = mContentDescriptionDataType;
- }
- }
-
- if (mWifiConnected) {
- if (mWifiSsid == null) {
- wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
- } else {
- wifiLabel = mWifiSsid;
- if (DEBUG) {
- wifiLabel += "xxxxXXXXxxxxXXXX";
- }
- }
-
- combinedLabel = wifiLabel;
- combinedSignalIconId = mWifiIconId; // set by updateWifiIcons()
- mContentDescriptionCombinedSignal = mContentDescriptionWifi;
- } else {
- if (mHasMobileDataFeature) {
- wifiLabel = "";
- } else {
- wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
- }
- }
-
- if (mBluetoothTethered) {
- combinedLabel = mContext.getString(R.string.bluetooth_tethered);
- combinedSignalIconId = mBluetoothTetherIconId;
- mContentDescriptionCombinedSignal = mContext.getString(
- R.string.accessibility_bluetooth_tether);
- }
-
- final boolean ethernetConnected = (mConnectedNetworkType == ConnectivityManager.TYPE_ETHERNET);
- if (ethernetConnected) {
- combinedLabel = context.getString(R.string.ethernet_label);
- }
-
- if (mAirplaneMode &&
- (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) {
- // Only display the flight-mode icon if not in "emergency calls only" mode.
-
- // look again; your radios are now airplanes
- mContentDescriptionPhoneSignal = mContext.getString(
- R.string.accessibility_airplane_mode);
- mAirplaneIconId = FLIGHT_MODE_ICON;
- mPhoneSignalIconId = mDataSignalIconId = mDataTypeIconId = mQSDataTypeIconId = 0;
- mQSPhoneSignalIconId = 0;
-
- // combined values from connected wifi take precedence over airplane mode
- if (mWifiConnected) {
- // Suppress "No internet connection." from mobile if wifi connected.
- mobileLabel = "";
- } else {
- if (mHasMobileDataFeature) {
- // let the mobile icon show "No internet connection."
- wifiLabel = "";
- } else {
- wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
- combinedLabel = wifiLabel;
- }
- mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal;
- combinedSignalIconId = mDataSignalIconId;
- }
- }
- else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected && !ethernetConnected) {
- // pretty much totally disconnected
-
- combinedLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
- // On devices without mobile radios, we want to show the wifi icon
- combinedSignalIconId =
- mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId;
- mContentDescriptionCombinedSignal = mHasMobileDataFeature
- ? mContentDescriptionDataType : mContentDescriptionWifi;
-
- mDataTypeIconId = 0;
- mQSDataTypeIconId = 0;
- if (isCdma()) {
- if (isCdmaEri()) {
- mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
- mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
- }
- } else if (mPhone.isNetworkRoaming()) {
- mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
- mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
- }
- }
-
- if (DEBUG) {
- Log.d(TAG, "refreshViews connected={"
- + (mWifiConnected?" wifi":"")
- + (mDataConnected?" data":"")
- + " } level="
- + ((mSignalStrength == null)?"??":Integer.toString(mSignalStrength.getLevel()))
- + " combinedSignalIconId=0x"
- + Integer.toHexString(combinedSignalIconId)
- + "/" + getResourceName(combinedSignalIconId)
- + " mobileLabel=" + mobileLabel
- + " wifiLabel=" + wifiLabel
- + " emergencyOnly=" + emergencyOnly
- + " combinedLabel=" + combinedLabel
- + " mAirplaneMode=" + mAirplaneMode
- + " mDataActivity=" + mDataActivity
- + " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId)
- + " mQSPhoneSignalIconId=0x" + Integer.toHexString(mQSPhoneSignalIconId)
- + " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId)
- + " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId)
- + " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId)
- + " mQSDataTypeIconId=0x" + Integer.toHexString(mQSDataTypeIconId)
- + " mWifiIconId=0x" + Integer.toHexString(mWifiIconId)
- + " mQSWifiIconId=0x" + Integer.toHexString(mQSWifiIconId)
- + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId));
- }
-
- // update QS
- for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
- notifySignalsChangedCallbacks(cb);
- }
-
- if (mLastPhoneSignalIconId != mPhoneSignalIconId
- || mLastWifiIconId != mWifiIconId
- || mLastInetCondition != mInetCondition
- || mLastWimaxIconId != mWimaxIconId
- || mLastDataTypeIconId != mDataTypeIconId
- || mLastAirplaneMode != mAirplaneMode
- || mLastLocale != mLocale)
- {
- // NB: the mLast*s will be updated later
- for (SignalCluster cluster : mSignalClusters) {
- refreshSignalCluster(cluster);
- }
- }
-
- if (mLastAirplaneMode != mAirplaneMode) {
- mLastAirplaneMode = mAirplaneMode;
- }
-
- if (mLastLocale != mLocale) {
- mLastLocale = mLocale;
- }
-
- // the phone icon on phones
- if (mLastPhoneSignalIconId != mPhoneSignalIconId) {
- mLastPhoneSignalIconId = mPhoneSignalIconId;
- }
-
- // the data icon on phones
- if (mLastDataDirectionIconId != mDataDirectionIconId) {
- mLastDataDirectionIconId = mDataDirectionIconId;
- }
-
- // the wifi icon on phones
- if (mLastWifiIconId != mWifiIconId) {
- mLastWifiIconId = mWifiIconId;
- }
-
- if (mLastInetCondition != mInetCondition) {
- mLastInetCondition = mInetCondition;
- }
-
- // the wimax icon on phones
- if (mLastWimaxIconId != mWimaxIconId) {
- mLastWimaxIconId = mWimaxIconId;
- }
- // the combined data signal icon
- if (mLastCombinedSignalIconId != combinedSignalIconId) {
- mLastCombinedSignalIconId = combinedSignalIconId;
- }
-
- // the data network type overlay
- if (mLastDataTypeIconId != mDataTypeIconId) {
- mLastDataTypeIconId = mDataTypeIconId;
- }
-
- // the combinedLabel in the notification panel
- if (!mLastCombinedLabel.equals(combinedLabel)) {
- mLastCombinedLabel = combinedLabel;
- N = mCombinedLabelViews.size();
- for (int i=0; i<N; i++) {
- TextView v = mCombinedLabelViews.get(i);
- v.setText(combinedLabel);
- }
- }
-
- // wifi label
- N = mWifiLabelViews.size();
- for (int i=0; i<N; i++) {
- TextView v = mWifiLabelViews.get(i);
- v.setText(wifiLabel);
- if ("".equals(wifiLabel)) {
- v.setVisibility(View.GONE);
- } else {
- v.setVisibility(View.VISIBLE);
- }
- }
-
- // mobile label
- N = mMobileLabelViews.size();
- for (int i=0; i<N; i++) {
- TextView v = mMobileLabelViews.get(i);
- v.setText(mobileLabel);
- if ("".equals(mobileLabel)) {
- v.setVisibility(View.GONE);
- } else {
- v.setVisibility(View.VISIBLE);
- }
- }
-
- // e-call label
- N = mEmergencyLabelViews.size();
- for (int i=0; i<N; i++) {
- TextView v = mEmergencyLabelViews.get(i);
- if (!emergencyOnly) {
- v.setVisibility(View.GONE);
- } else {
- v.setText(mobileLabel); // comes from the telephony stack
- v.setVisibility(View.VISIBLE);
- }
- }
- }
-
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("NetworkController state:");
- pw.println(String.format(" %s network type %d (%s)",
- mConnected?"CONNECTED":"DISCONNECTED",
- mConnectedNetworkType, mConnectedNetworkTypeName));
- pw.println(" - telephony ------");
- pw.print(" hasVoiceCallingFeature()=");
- pw.println(hasVoiceCallingFeature());
- pw.print(" hasService()=");
- pw.println(hasService());
- pw.print(" mHspaDataDistinguishable=");
- pw.println(mHspaDataDistinguishable);
- pw.print(" mDataConnected=");
- pw.println(mDataConnected);
- pw.print(" mSimState=");
- pw.println(mSimState);
- pw.print(" mPhoneState=");
- pw.println(mPhoneState);
- pw.print(" mDataState=");
- pw.println(mDataState);
- pw.print(" mDataActivity=");
- pw.println(mDataActivity);
- pw.print(" mDataNetType=");
- pw.print(mDataNetType);
- pw.print("/");
- pw.println(TelephonyManager.getNetworkTypeName(mDataNetType));
- pw.print(" mServiceState=");
- pw.println(mServiceState);
- pw.print(" mSignalStrength=");
- pw.println(mSignalStrength);
- pw.print(" mLastSignalLevel=");
- pw.println(mLastSignalLevel);
- pw.print(" mNetworkName=");
- pw.println(mNetworkName);
- pw.print(" mNetworkNameDefault=");
- pw.println(mNetworkNameDefault);
- pw.print(" mNetworkNameSeparator=");
- pw.println(mNetworkNameSeparator.replace("\n","\\n"));
- pw.print(" mPhoneSignalIconId=0x");
- pw.print(Integer.toHexString(mPhoneSignalIconId));
- pw.print("/");
- pw.print(" mQSPhoneSignalIconId=0x");
- pw.print(Integer.toHexString(mQSPhoneSignalIconId));
- pw.print("/");
- pw.println(getResourceName(mPhoneSignalIconId));
- pw.print(" mDataDirectionIconId=");
- pw.print(Integer.toHexString(mDataDirectionIconId));
- pw.print("/");
- pw.println(getResourceName(mDataDirectionIconId));
- pw.print(" mDataSignalIconId=");
- pw.print(Integer.toHexString(mDataSignalIconId));
- pw.print("/");
- pw.println(getResourceName(mDataSignalIconId));
- pw.print(" mDataTypeIconId=");
- pw.print(Integer.toHexString(mDataTypeIconId));
- pw.print("/");
- pw.println(getResourceName(mDataTypeIconId));
- pw.print(" mQSDataTypeIconId=");
- pw.print(Integer.toHexString(mQSDataTypeIconId));
- pw.print("/");
- pw.println(getResourceName(mQSDataTypeIconId));
-
- pw.println(" - wifi ------");
- pw.print(" mWifiEnabled=");
- pw.println(mWifiEnabled);
- pw.print(" mWifiConnected=");
- pw.println(mWifiConnected);
- pw.print(" mWifiRssi=");
- pw.println(mWifiRssi);
- pw.print(" mWifiLevel=");
- pw.println(mWifiLevel);
- pw.print(" mWifiSsid=");
- pw.println(mWifiSsid);
- pw.println(String.format(" mWifiIconId=0x%08x/%s",
- mWifiIconId, getResourceName(mWifiIconId)));
- pw.println(String.format(" mQSWifiIconId=0x%08x/%s",
- mQSWifiIconId, getResourceName(mQSWifiIconId)));
- pw.print(" mWifiActivity=");
- pw.println(mWifiActivity);
-
- if (mWimaxSupported) {
- pw.println(" - wimax ------");
- pw.print(" mIsWimaxEnabled="); pw.println(mIsWimaxEnabled);
- pw.print(" mWimaxConnected="); pw.println(mWimaxConnected);
- pw.print(" mWimaxIdle="); pw.println(mWimaxIdle);
- pw.println(String.format(" mWimaxIconId=0x%08x/%s",
- mWimaxIconId, getResourceName(mWimaxIconId)));
- pw.println(String.format(" mWimaxSignal=%d", mWimaxSignal));
- pw.println(String.format(" mWimaxState=%d", mWimaxState));
- pw.println(String.format(" mWimaxExtraState=%d", mWimaxExtraState));
- }
-
- pw.println(" - Bluetooth ----");
- pw.print(" mBtReverseTethered=");
- pw.println(mBluetoothTethered);
-
- pw.println(" - connectivity ------");
- pw.print(" mInetCondition=");
- pw.println(mInetCondition);
-
- pw.println(" - icons ------");
- pw.print(" mLastPhoneSignalIconId=0x");
- pw.print(Integer.toHexString(mLastPhoneSignalIconId));
- pw.print("/");
- pw.println(getResourceName(mLastPhoneSignalIconId));
- pw.print(" mLastDataDirectionIconId=0x");
- pw.print(Integer.toHexString(mLastDataDirectionIconId));
- pw.print("/");
- pw.println(getResourceName(mLastDataDirectionIconId));
- pw.print(" mLastWifiIconId=0x");
- pw.print(Integer.toHexString(mLastWifiIconId));
- pw.print("/");
- pw.println(getResourceName(mLastWifiIconId));
- pw.print(" mLastCombinedSignalIconId=0x");
- pw.print(Integer.toHexString(mLastCombinedSignalIconId));
- pw.print("/");
- pw.println(getResourceName(mLastCombinedSignalIconId));
- pw.print(" mLastDataTypeIconId=0x");
- pw.print(Integer.toHexString(mLastDataTypeIconId));
- pw.print("/");
- pw.println(getResourceName(mLastDataTypeIconId));
- pw.print(" mLastCombinedLabel=");
- pw.print(mLastCombinedLabel);
- pw.println("");
- }
-
- private String getResourceName(int resId) {
- if (resId != 0) {
- final Resources res = mContext.getResources();
- try {
- return res.getResourceName(resId);
- } catch (android.content.res.Resources.NotFoundException ex) {
- return "(unknown)";
- }
- } else {
- return "(null)";
- }
- }
-
- private boolean mDemoMode;
- private int mDemoInetCondition;
- private int mDemoWifiLevel;
- private int mDemoDataTypeIconId;
- private int mDemoMobileLevel;
-
- @Override
- public void dispatchDemoCommand(String command, Bundle args) {
- if (!mDemoMode && command.equals(COMMAND_ENTER)) {
- mDemoMode = true;
- mDemoWifiLevel = mWifiLevel;
- mDemoInetCondition = mInetCondition;
- mDemoDataTypeIconId = mDataTypeIconId;
- mDemoMobileLevel = mLastSignalLevel;
- } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
- mDemoMode = false;
- for (SignalCluster cluster : mSignalClusters) {
- refreshSignalCluster(cluster);
- }
- } else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
- String airplane = args.getString("airplane");
- if (airplane != null) {
- boolean show = airplane.equals("show");
- for (SignalCluster cluster : mSignalClusters) {
- cluster.setIsAirplaneMode(show, FLIGHT_MODE_ICON);
- }
- }
- String fully = args.getString("fully");
- if (fully != null) {
- mDemoInetCondition = Boolean.parseBoolean(fully) ? 1 : 0;
- }
- String wifi = args.getString("wifi");
- if (wifi != null) {
- boolean show = wifi.equals("show");
- String level = args.getString("level");
- if (level != null) {
- mDemoWifiLevel = level.equals("null") ? -1
- : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
- }
- int iconId = mDemoWifiLevel < 0 ? R.drawable.stat_sys_wifi_signal_null
- : WifiIcons.WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel];
- for (SignalCluster cluster : mSignalClusters) {
- cluster.setWifiIndicators(
- show,
- iconId,
- mDemoInetCondition == 0,
- "Demo");
- }
- }
- String mobile = args.getString("mobile");
- if (mobile != null) {
- boolean show = mobile.equals("show");
- String datatype = args.getString("datatype");
- if (datatype != null) {
- mDemoDataTypeIconId =
- datatype.equals("1x") ? R.drawable.stat_sys_data_fully_connected_1x :
- datatype.equals("3g") ? R.drawable.stat_sys_data_fully_connected_3g :
- datatype.equals("4g") ? R.drawable.stat_sys_data_fully_connected_4g :
- datatype.equals("e") ? R.drawable.stat_sys_data_fully_connected_e :
- datatype.equals("g") ? R.drawable.stat_sys_data_fully_connected_g :
- datatype.equals("h") ? R.drawable.stat_sys_data_fully_connected_h :
- datatype.equals("lte") ? R.drawable.stat_sys_data_fully_connected_lte :
- datatype.equals("roam")
- ? R.drawable.stat_sys_data_fully_connected_roam :
- 0;
- }
- int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
- String level = args.getString("level");
- if (level != null) {
- mDemoMobileLevel = level.equals("null") ? -1
- : Math.min(Integer.parseInt(level), icons[0].length - 1);
- }
- int iconId = mDemoMobileLevel < 0 ? R.drawable.stat_sys_signal_null :
- icons[mDemoInetCondition][mDemoMobileLevel];
- for (SignalCluster cluster : mSignalClusters) {
- cluster.setMobileDataIndicators(
- show,
- iconId,
- mDemoInetCondition == 0,
- mDemoDataTypeIconId,
- "Demo",
- "Demo");
- }
- }
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
new file mode 100644
index 0000000..966c0b0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -0,0 +1,1491 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.net.wimax.WimaxManagerConstants;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.provider.Settings;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.cdma.EriInfo;
+import com.android.internal.util.AsyncChannel;
+import com.android.systemui.DemoMode;
+import com.android.systemui.R;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/** Platform implementation of the network controller. **/
+public class NetworkControllerImpl extends BroadcastReceiver
+ implements NetworkController, DemoMode {
+ // debug
+ static final String TAG = "StatusBar.NetworkController";
+ static final boolean DEBUG = false;
+ static final boolean CHATTY = false; // additional diagnostics, but not logspew
+
+ private static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_signal_flightmode;
+
+ // telephony
+ boolean mHspaDataDistinguishable;
+ final TelephonyManager mPhone;
+ boolean mDataConnected;
+ IccCardConstants.State mSimState = IccCardConstants.State.READY;
+ int mPhoneState = TelephonyManager.CALL_STATE_IDLE;
+ int mDataNetType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ int mDataState = TelephonyManager.DATA_DISCONNECTED;
+ int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
+ ServiceState mServiceState;
+ SignalStrength mSignalStrength;
+ int[] mDataIconList = TelephonyIcons.DATA_G[0];
+ String mNetworkName;
+ String mNetworkNameDefault;
+ String mNetworkNameSeparator;
+ int mPhoneSignalIconId;
+ int mQSPhoneSignalIconId;
+ int mDataDirectionIconId; // data + data direction on phones
+ int mDataSignalIconId;
+ int mDataTypeIconId;
+ int mQSDataTypeIconId;
+ int mAirplaneIconId;
+ boolean mDataActive;
+ int mLastSignalLevel;
+ boolean mShowPhoneRSSIForData = false;
+ boolean mShowAtLeastThreeGees = false;
+ boolean mAlwaysShowCdmaRssi = false;
+
+ String mContentDescriptionPhoneSignal;
+ String mContentDescriptionWifi;
+ String mContentDescriptionWimax;
+ String mContentDescriptionCombinedSignal;
+ String mContentDescriptionDataType;
+
+ // wifi
+ final WifiManager mWifiManager;
+ AsyncChannel mWifiChannel;
+ boolean mWifiEnabled, mWifiConnected;
+ int mWifiRssi, mWifiLevel;
+ String mWifiSsid;
+ int mWifiIconId = 0;
+ int mQSWifiIconId = 0;
+ int mWifiActivity = WifiManager.DATA_ACTIVITY_NONE;
+
+ // bluetooth
+ private boolean mBluetoothTethered = false;
+ private int mBluetoothTetherIconId =
+ com.android.internal.R.drawable.stat_sys_tether_bluetooth;
+
+ //wimax
+ private boolean mWimaxSupported = false;
+ private boolean mIsWimaxEnabled = false;
+ private boolean mWimaxConnected = false;
+ private boolean mWimaxIdle = false;
+ private int mWimaxIconId = 0;
+ private int mWimaxSignal = 0;
+ private int mWimaxState = 0;
+ private int mWimaxExtraState = 0;
+
+ // data connectivity (regardless of state, can we access the internet?)
+ // state of inet connection - 0 not connected, 100 connected
+ private boolean mConnected = false;
+ private int mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
+ private String mConnectedNetworkTypeName;
+ private int mInetCondition = 0;
+ private int mLastInetCondition = 0;
+ private static final int INET_CONDITION_THRESHOLD = 50;
+
+ private boolean mAirplaneMode = false;
+ private boolean mLastAirplaneMode = true;
+
+ private Locale mLocale = null;
+ private Locale mLastLocale = null;
+
+ // our ui
+ Context mContext;
+ ArrayList<TextView> mCombinedLabelViews = new ArrayList<TextView>();
+ ArrayList<TextView> mMobileLabelViews = new ArrayList<TextView>();
+ ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>();
+ ArrayList<TextView> mEmergencyLabelViews = new ArrayList<TextView>();
+ ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
+ ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
+ new ArrayList<NetworkSignalChangedCallback>();
+ int mLastPhoneSignalIconId = -1;
+ int mLastDataDirectionIconId = -1;
+ int mLastWifiIconId = -1;
+ int mLastWimaxIconId = -1;
+ int mLastCombinedSignalIconId = -1;
+ int mLastDataTypeIconId = -1;
+ String mLastCombinedLabel = "";
+
+ private boolean mHasMobileDataFeature;
+
+ boolean mDataAndWifiStacked = false;
+
+ public interface SignalCluster {
+ void setWifiIndicators(boolean visible, int strengthIcon, boolean problem,
+ String contentDescription);
+ void setMobileDataIndicators(boolean visible, int strengthIcon, boolean problem,
+ int typeIcon, String contentDescription, String typeContentDescription);
+ void setIsAirplaneMode(boolean is, int airplaneIcon);
+ }
+
+ /**
+ * Construct this controller object and register for updates.
+ */
+ public NetworkControllerImpl(Context context) {
+ mContext = context;
+ final Resources res = context.getResources();
+
+ ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ mHasMobileDataFeature = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+
+ mShowPhoneRSSIForData = res.getBoolean(R.bool.config_showPhoneRSSIForData);
+ mShowAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G);
+ mAlwaysShowCdmaRssi = res.getBoolean(
+ com.android.internal.R.bool.config_alwaysUseCdmaRssi);
+
+ // set up the default wifi icon, used when no radios have ever appeared
+ updateWifiIcons();
+ updateWimaxIcons();
+
+ // telephony
+ mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
+ mPhone.listen(mPhoneStateListener,
+ PhoneStateListener.LISTEN_SERVICE_STATE
+ | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
+ | PhoneStateListener.LISTEN_CALL_STATE
+ | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
+ | PhoneStateListener.LISTEN_DATA_ACTIVITY);
+ mHspaDataDistinguishable = mContext.getResources().getBoolean(
+ R.bool.config_hspa_data_distinguishable);
+ mNetworkNameSeparator = mContext.getString(R.string.status_bar_network_name_separator);
+ mNetworkNameDefault = mContext.getString(
+ com.android.internal.R.string.lockscreen_carrier_default);
+ mNetworkName = mNetworkNameDefault;
+
+ // wifi
+ mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ Handler handler = new WifiHandler();
+ mWifiChannel = new AsyncChannel();
+ Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
+ if (wifiMessenger != null) {
+ mWifiChannel.connect(mContext, handler, wifiMessenger);
+ }
+
+ // broadcasts
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
+ filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
+ filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
+ filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+ filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ mWimaxSupported = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_wimaxEnabled);
+ if(mWimaxSupported) {
+ filter.addAction(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION);
+ filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION);
+ filter.addAction(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION);
+ }
+ context.registerReceiver(this, filter);
+
+ // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
+ updateAirplaneMode();
+
+ mLastLocale = mContext.getResources().getConfiguration().locale;
+ }
+
+ public boolean hasMobileDataFeature() {
+ return mHasMobileDataFeature;
+ }
+
+ public boolean hasVoiceCallingFeature() {
+ return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
+ }
+
+ public boolean isEmergencyOnly() {
+ return (mServiceState != null && mServiceState.isEmergencyOnly());
+ }
+
+ public void addCombinedLabelView(TextView v) {
+ mCombinedLabelViews.add(v);
+ }
+
+ public void addMobileLabelView(TextView v) {
+ mMobileLabelViews.add(v);
+ }
+
+ public void addWifiLabelView(TextView v) {
+ mWifiLabelViews.add(v);
+ }
+
+ public void addEmergencyLabelView(TextView v) {
+ mEmergencyLabelViews.add(v);
+ }
+
+ public void addSignalCluster(SignalCluster cluster) {
+ mSignalClusters.add(cluster);
+ refreshSignalCluster(cluster);
+ }
+
+ public void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
+ mSignalsChangedCallbacks.add(cb);
+ notifySignalsChangedCallbacks(cb);
+ }
+
+ public void removeNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
+ mSignalsChangedCallbacks.remove(cb);
+ }
+
+ @Override
+ public void setWifiEnabled(final boolean enabled) {
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... args) {
+ // Disable tethering if enabling Wifi
+ final int wifiApState = mWifiManager.getWifiApState();
+ if (enabled && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
+ (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
+ mWifiManager.setWifiApEnabled(null, false);
+ }
+
+ mWifiManager.setWifiEnabled(enabled);
+ return null;
+ }
+ }.execute();
+ }
+
+ public void refreshSignalCluster(SignalCluster cluster) {
+ if (mDemoMode) return;
+ cluster.setWifiIndicators(
+ // only show wifi in the cluster if connected or if wifi-only
+ mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature),
+ mWifiIconId,
+ mInetCondition == 0,
+ mContentDescriptionWifi);
+
+ if (mIsWimaxEnabled && mWimaxConnected) {
+ // wimax is special
+ cluster.setMobileDataIndicators(
+ true,
+ mAlwaysShowCdmaRssi ? mPhoneSignalIconId : mWimaxIconId,
+ mInetCondition == 0,
+ mDataTypeIconId,
+ mContentDescriptionWimax,
+ mContentDescriptionDataType);
+ } else {
+ // normal mobile data
+ cluster.setMobileDataIndicators(
+ mHasMobileDataFeature,
+ mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
+ mInetCondition == 0,
+ mDataTypeIconId,
+ mContentDescriptionPhoneSignal,
+ mContentDescriptionDataType);
+ }
+ cluster.setIsAirplaneMode(mAirplaneMode, mAirplaneIconId);
+ }
+
+ void notifySignalsChangedCallbacks(NetworkSignalChangedCallback cb) {
+ // only show wifi in the cluster if connected or if wifi-only
+ boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature);
+ String wifiDesc = wifiEnabled ?
+ mWifiSsid : null;
+ boolean wifiIn = wifiEnabled && mWifiSsid != null
+ && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
+ || mWifiActivity == WifiManager.DATA_ACTIVITY_IN);
+ boolean wifiOut = wifiEnabled && mWifiSsid != null
+ && (mWifiActivity == WifiManager.DATA_ACTIVITY_INOUT
+ || mWifiActivity == WifiManager.DATA_ACTIVITY_OUT);
+ cb.onWifiSignalChanged(wifiEnabled, mQSWifiIconId, wifiIn, wifiOut,
+ mContentDescriptionWifi, wifiDesc);
+
+ boolean mobileIn = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
+ || mDataActivity == TelephonyManager.DATA_ACTIVITY_IN);
+ boolean mobileOut = mDataConnected && (mDataActivity == TelephonyManager.DATA_ACTIVITY_INOUT
+ || mDataActivity == TelephonyManager.DATA_ACTIVITY_OUT);
+ if (isEmergencyOnly()) {
+ cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId,
+ mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
+ mContentDescriptionDataType, null);
+ } else {
+ if (mIsWimaxEnabled && mWimaxConnected) {
+ // Wimax is special
+ cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId,
+ mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
+ mContentDescriptionDataType, mNetworkName);
+ } else {
+ // Normal mobile data
+ cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId,
+ mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
+ mContentDescriptionDataType, mNetworkName);
+ }
+ }
+ cb.onAirplaneModeChanged(mAirplaneMode);
+ }
+
+ public void setStackedMode(boolean stacked) {
+ mDataAndWifiStacked = true;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (action.equals(WifiManager.RSSI_CHANGED_ACTION)
+ || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)
+ || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+ updateWifiState(intent);
+ refreshViews();
+ } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
+ updateSimState(intent);
+ updateDataIcon();
+ refreshViews();
+ } else if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
+ updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
+ intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
+ intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
+ intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
+ refreshViews();
+ } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
+ action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
+ updateConnectivity(intent);
+ refreshViews();
+ } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
+ refreshLocale();
+ refreshViews();
+ } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
+ refreshLocale();
+ updateAirplaneMode();
+ refreshViews();
+ } else if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION) ||
+ action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) ||
+ action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
+ updateWimaxState(intent);
+ refreshViews();
+ }
+ }
+
+
+ // ===== Telephony ==============================================================
+
+ PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+ @Override
+ public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+ if (DEBUG) {
+ Log.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
+ ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
+ }
+ mSignalStrength = signalStrength;
+ updateTelephonySignalStrength();
+ refreshViews();
+ }
+
+ @Override
+ public void onServiceStateChanged(ServiceState state) {
+ if (DEBUG) {
+ Log.d(TAG, "onServiceStateChanged voiceState=" + state.getVoiceRegState()
+ + " dataState=" + state.getDataRegState());
+ }
+ mServiceState = state;
+ updateTelephonySignalStrength();
+ updateDataNetType();
+ updateDataIcon();
+ refreshViews();
+ }
+
+ @Override
+ public void onCallStateChanged(int state, String incomingNumber) {
+ if (DEBUG) {
+ Log.d(TAG, "onCallStateChanged state=" + state);
+ }
+ // In cdma, if a voice call is made, RSSI should switch to 1x.
+ if (isCdma()) {
+ updateTelephonySignalStrength();
+ refreshViews();
+ }
+ }
+
+ @Override
+ public void onDataConnectionStateChanged(int state, int networkType) {
+ if (DEBUG) {
+ Log.d(TAG, "onDataConnectionStateChanged: state=" + state
+ + " type=" + networkType);
+ }
+ mDataState = state;
+ mDataNetType = networkType;
+ updateDataNetType();
+ updateDataIcon();
+ refreshViews();
+ }
+
+ @Override
+ public void onDataActivity(int direction) {
+ if (DEBUG) {
+ Log.d(TAG, "onDataActivity: direction=" + direction);
+ }
+ mDataActivity = direction;
+ updateDataIcon();
+ refreshViews();
+ }
+ };
+
+ private final void updateSimState(Intent intent) {
+ String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
+ if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
+ mSimState = IccCardConstants.State.ABSENT;
+ }
+ else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
+ mSimState = IccCardConstants.State.READY;
+ }
+ else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
+ final String lockedReason =
+ intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
+ if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
+ mSimState = IccCardConstants.State.PIN_REQUIRED;
+ }
+ else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
+ mSimState = IccCardConstants.State.PUK_REQUIRED;
+ }
+ else {
+ mSimState = IccCardConstants.State.NETWORK_LOCKED;
+ }
+ } else {
+ mSimState = IccCardConstants.State.UNKNOWN;
+ }
+ }
+
+ private boolean isCdma() {
+ return (mSignalStrength != null) && !mSignalStrength.isGsm();
+ }
+
+ private boolean hasService() {
+ if (mServiceState != null) {
+ // Consider the device to be in service if either voice or data service is available.
+ // Some SIM cards are marketed as data-only and do not support voice service, and on
+ // these SIM cards, we want to show signal bars for data service as well as the "no
+ // service" or "emergency calls only" text that indicates that voice is not available.
+ switch(mServiceState.getVoiceRegState()) {
+ case ServiceState.STATE_POWER_OFF:
+ return false;
+ case ServiceState.STATE_OUT_OF_SERVICE:
+ case ServiceState.STATE_EMERGENCY_ONLY:
+ return mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE;
+ default:
+ return true;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ private void updateAirplaneMode() {
+ mAirplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
+ }
+
+ private void refreshLocale() {
+ mLocale = mContext.getResources().getConfiguration().locale;
+ }
+
+ private final void updateTelephonySignalStrength() {
+ if (!hasService()) {
+ if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: !hasService()");
+ mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
+ mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
+ mDataSignalIconId = R.drawable.stat_sys_signal_null;
+ } else {
+ if (mSignalStrength == null) {
+ if (CHATTY) Log.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
+ mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
+ mQSPhoneSignalIconId = R.drawable.ic_qs_signal_no_signal;
+ mDataSignalIconId = R.drawable.stat_sys_signal_null;
+ mContentDescriptionPhoneSignal = mContext.getString(
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]);
+ } else {
+ int iconLevel;
+ int[] iconList;
+ if (isCdma() && mAlwaysShowCdmaRssi) {
+ mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel();
+ if(DEBUG) Log.d(TAG, "mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi
+ + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel()
+ + " instead of level=" + mSignalStrength.getLevel());
+ } else {
+ mLastSignalLevel = iconLevel = mSignalStrength.getLevel();
+ }
+
+ if (isCdma()) {
+ if (isCdmaEri()) {
+ iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
+ } else {
+ iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
+ }
+ } else {
+ // Though mPhone is a Manager, this call is not an IPC
+ if (mPhone.isNetworkRoaming()) {
+ iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
+ } else {
+ iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[mInetCondition];
+ }
+ }
+ mPhoneSignalIconId = iconList[iconLevel];
+ mQSPhoneSignalIconId =
+ TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[mInetCondition][iconLevel];
+ mContentDescriptionPhoneSignal = mContext.getString(
+ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]);
+ mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel];
+ }
+ }
+ }
+
+ private final void updateDataNetType() {
+ if (mIsWimaxEnabled && mWimaxConnected) {
+ // wimax is a special 4g network not handled by telephony
+ mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_4g);
+ } else {
+ switch (mDataNetType) {
+ case TelephonyManager.NETWORK_TYPE_UNKNOWN:
+ if (!mShowAtLeastThreeGees) {
+ mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
+ mDataTypeIconId = 0;
+ mQSDataTypeIconId = 0;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_gprs);
+ break;
+ } else {
+ // fall through
+ }
+ case TelephonyManager.NETWORK_TYPE_EDGE:
+ if (!mShowAtLeastThreeGees) {
+ mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_e;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_E[mInetCondition];
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_edge);
+ break;
+ } else {
+ // fall through
+ }
+ case TelephonyManager.NETWORK_TYPE_UMTS:
+ mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_3g);
+ break;
+ case TelephonyManager.NETWORK_TYPE_HSDPA:
+ case TelephonyManager.NETWORK_TYPE_HSUPA:
+ case TelephonyManager.NETWORK_TYPE_HSPA:
+ case TelephonyManager.NETWORK_TYPE_HSPAP:
+ if (mHspaDataDistinguishable) {
+ mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_h;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_H[mInetCondition];
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_3_5g);
+ } else {
+ mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_3g);
+ }
+ break;
+ case TelephonyManager.NETWORK_TYPE_CDMA:
+ if (!mShowAtLeastThreeGees) {
+ // display 1xRTT for IS95A/B
+ mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_cdma);
+ break;
+ } else {
+ // fall through
+ }
+ case TelephonyManager.NETWORK_TYPE_1xRTT:
+ if (!mShowAtLeastThreeGees) {
+ mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_1x;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_1X[mInetCondition];
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_cdma);
+ break;
+ } else {
+ // fall through
+ }
+ case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
+ case TelephonyManager.NETWORK_TYPE_EVDO_A:
+ case TelephonyManager.NETWORK_TYPE_EVDO_B:
+ case TelephonyManager.NETWORK_TYPE_EHRPD:
+ mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_3g);
+ break;
+ case TelephonyManager.NETWORK_TYPE_LTE:
+ boolean show4GforLTE = mContext.getResources().getBoolean(R.bool.config_show4GForLTE);
+ if (show4GforLTE) {
+ mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_4g;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_4G[mInetCondition];
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_4g);
+ } else {
+ mDataIconList = TelephonyIcons.DATA_LTE[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_lte;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_LTE[mInetCondition];
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_lte);
+ }
+ break;
+ default:
+ if (!mShowAtLeastThreeGees) {
+ mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_g;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_G[mInetCondition];
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_gprs);
+ } else {
+ mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_3g;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_3G[mInetCondition];
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_3g);
+ }
+ break;
+ }
+ }
+
+ if (isCdma()) {
+ if (isCdmaEri()) {
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
+ }
+ } else if (mPhone.isNetworkRoaming()) {
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
+ }
+ }
+
+ boolean isCdmaEri() {
+ if (mServiceState != null) {
+ final int iconIndex = mServiceState.getCdmaEriIconIndex();
+ if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) {
+ final int iconMode = mServiceState.getCdmaEriIconMode();
+ if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL
+ || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private final void updateDataIcon() {
+ int iconId;
+ boolean visible = true;
+
+ if (!isCdma()) {
+ // GSM case, we have to check also the sim state
+ if (mSimState == IccCardConstants.State.READY ||
+ mSimState == IccCardConstants.State.UNKNOWN) {
+ if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
+ switch (mDataActivity) {
+ case TelephonyManager.DATA_ACTIVITY_IN:
+ iconId = mDataIconList[1];
+ break;
+ case TelephonyManager.DATA_ACTIVITY_OUT:
+ iconId = mDataIconList[2];
+ break;
+ case TelephonyManager.DATA_ACTIVITY_INOUT:
+ iconId = mDataIconList[3];
+ break;
+ default:
+ iconId = mDataIconList[0];
+ break;
+ }
+ mDataDirectionIconId = iconId;
+ } else {
+ iconId = 0;
+ visible = false;
+ }
+ } else {
+ iconId = R.drawable.stat_sys_no_sim;
+ visible = false; // no SIM? no data
+ }
+ } else {
+ // CDMA case, mDataActivity can be also DATA_ACTIVITY_DORMANT
+ if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
+ switch (mDataActivity) {
+ case TelephonyManager.DATA_ACTIVITY_IN:
+ iconId = mDataIconList[1];
+ break;
+ case TelephonyManager.DATA_ACTIVITY_OUT:
+ iconId = mDataIconList[2];
+ break;
+ case TelephonyManager.DATA_ACTIVITY_INOUT:
+ iconId = mDataIconList[3];
+ break;
+ case TelephonyManager.DATA_ACTIVITY_DORMANT:
+ default:
+ iconId = mDataIconList[0];
+ break;
+ }
+ } else {
+ iconId = 0;
+ visible = false;
+ }
+ }
+
+ mDataDirectionIconId = iconId;
+ mDataConnected = visible;
+ }
+
+ void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) {
+ if (false) {
+ Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn
+ + " showPlmn=" + showPlmn + " plmn=" + plmn);
+ }
+ StringBuilder str = new StringBuilder();
+ boolean something = false;
+ if (showPlmn && plmn != null) {
+ str.append(plmn);
+ something = true;
+ }
+ if (showSpn && spn != null) {
+ if (something) {
+ str.append(mNetworkNameSeparator);
+ }
+ str.append(spn);
+ something = true;
+ }
+ if (something) {
+ mNetworkName = str.toString();
+ } else {
+ mNetworkName = mNetworkNameDefault;
+ }
+ }
+
+ // ===== Wifi ===================================================================
+
+ class WifiHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+ if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+ mWifiChannel.sendMessage(Message.obtain(this,
+ AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
+ } else {
+ Log.e(TAG, "Failed to connect to wifi");
+ }
+ break;
+ case WifiManager.DATA_ACTIVITY_NOTIFICATION:
+ if (msg.arg1 != mWifiActivity) {
+ mWifiActivity = msg.arg1;
+ refreshViews();
+ }
+ break;
+ default:
+ //Ignore
+ break;
+ }
+ }
+ }
+
+ private void updateWifiState(Intent intent) {
+ final String action = intent.getAction();
+ if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+ mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+ WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
+
+ } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+ final NetworkInfo networkInfo = (NetworkInfo)
+ intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
+ boolean wasConnected = mWifiConnected;
+ mWifiConnected = networkInfo != null && networkInfo.isConnected();
+ // If we just connected, grab the inintial signal strength and ssid
+ if (mWifiConnected && !wasConnected) {
+ // try getting it out of the intent first
+ WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
+ if (info == null) {
+ info = mWifiManager.getConnectionInfo();
+ }
+ if (info != null) {
+ mWifiSsid = huntForSsid(info);
+ } else {
+ mWifiSsid = null;
+ }
+ } else if (!mWifiConnected) {
+ mWifiSsid = null;
+ }
+ } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
+ mWifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
+ mWifiLevel = WifiManager.calculateSignalLevel(
+ mWifiRssi, WifiIcons.WIFI_LEVEL_COUNT);
+ }
+
+ updateWifiIcons();
+ }
+
+ private void updateWifiIcons() {
+ if (mWifiConnected) {
+ mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
+ mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
+ mContentDescriptionWifi = mContext.getString(
+ AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]);
+ } else {
+ if (mDataAndWifiStacked) {
+ mWifiIconId = 0;
+ mQSWifiIconId = 0;
+ } else {
+ mWifiIconId = mWifiEnabled ? R.drawable.stat_sys_wifi_signal_null : 0;
+ mQSWifiIconId = mWifiEnabled ? R.drawable.ic_qs_wifi_no_network : 0;
+ }
+ mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi);
+ }
+ }
+
+ private String huntForSsid(WifiInfo info) {
+ String ssid = info.getSSID();
+ if (ssid != null) {
+ return ssid;
+ }
+ // OK, it's not in the connectionInfo; we have to go hunting for it
+ List<WifiConfiguration> networks = mWifiManager.getConfiguredNetworks();
+ for (WifiConfiguration net : networks) {
+ if (net.networkId == info.getNetworkId()) {
+ return net.SSID;
+ }
+ }
+ return null;
+ }
+
+
+ // ===== Wimax ===================================================================
+ private final void updateWimaxState(Intent intent) {
+ final String action = intent.getAction();
+ boolean wasConnected = mWimaxConnected;
+ if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION)) {
+ int wimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_4G_STATE,
+ WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
+ mIsWimaxEnabled = (wimaxStatus ==
+ WimaxManagerConstants.NET_4G_STATE_ENABLED);
+ } else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) {
+ mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0);
+ } else if (action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
+ mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
+ WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
+ mWimaxExtraState = intent.getIntExtra(
+ WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL,
+ WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
+ mWimaxConnected = (mWimaxState ==
+ WimaxManagerConstants.WIMAX_STATE_CONNECTED);
+ mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE);
+ }
+ updateDataNetType();
+ updateWimaxIcons();
+ }
+
+ private void updateWimaxIcons() {
+ if (mIsWimaxEnabled) {
+ if (mWimaxConnected) {
+ if (mWimaxIdle)
+ mWimaxIconId = WimaxIcons.WIMAX_IDLE;
+ else
+ mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal];
+ mContentDescriptionWimax = mContext.getString(
+ AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]);
+ } else {
+ mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED;
+ mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax);
+ }
+ } else {
+ mWimaxIconId = 0;
+ }
+ }
+
+ // ===== Full or limited Internet connectivity ==================================
+
+ private void updateConnectivity(Intent intent) {
+ if (CHATTY) {
+ Log.d(TAG, "updateConnectivity: intent=" + intent);
+ }
+
+ final ConnectivityManager connManager = (ConnectivityManager) mContext
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ final NetworkInfo info = connManager.getActiveNetworkInfo();
+
+ // Are we connected at all, by any interface?
+ mConnected = info != null && info.isConnected();
+ if (mConnected) {
+ mConnectedNetworkType = info.getType();
+ mConnectedNetworkTypeName = info.getTypeName();
+ } else {
+ mConnectedNetworkType = ConnectivityManager.TYPE_NONE;
+ mConnectedNetworkTypeName = null;
+ }
+
+ int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
+
+ if (CHATTY) {
+ Log.d(TAG, "updateConnectivity: networkInfo=" + info);
+ Log.d(TAG, "updateConnectivity: connectionStatus=" + connectionStatus);
+ }
+
+ mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
+
+ if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) {
+ mBluetoothTethered = info.isConnected();
+ } else {
+ mBluetoothTethered = false;
+ }
+
+ // We want to update all the icons, all at once, for any condition change
+ updateDataNetType();
+ updateWimaxIcons();
+ updateDataIcon();
+ updateTelephonySignalStrength();
+ updateWifiIcons();
+ }
+
+
+ // ===== Update the views =======================================================
+
+ void refreshViews() {
+ Context context = mContext;
+
+ int combinedSignalIconId = 0;
+ String combinedLabel = "";
+ String wifiLabel = "";
+ String mobileLabel = "";
+ int N;
+ final boolean emergencyOnly = isEmergencyOnly();
+
+ if (!mHasMobileDataFeature) {
+ mDataSignalIconId = mPhoneSignalIconId = 0;
+ mQSPhoneSignalIconId = 0;
+ mobileLabel = "";
+ } else {
+ // We want to show the carrier name if in service and either:
+ // - We are connected to mobile data, or
+ // - We are not connected to mobile data, as long as the *reason* packets are not
+ // being routed over that link is that we have better connectivity via wifi.
+ // If data is disconnected for some other reason but wifi (or ethernet/bluetooth)
+ // is connected, we show nothing.
+ // Otherwise (nothing connected) we show "No internet connection".
+
+ if (mDataConnected) {
+ mobileLabel = mNetworkName;
+ } else if (mConnected || emergencyOnly) {
+ if (hasService() || emergencyOnly) {
+ // The isEmergencyOnly test covers the case of a phone with no SIM
+ mobileLabel = mNetworkName;
+ } else {
+ // Tablets, basically
+ mobileLabel = "";
+ }
+ } else {
+ mobileLabel
+ = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+ }
+
+ // Now for things that should only be shown when actually using mobile data.
+ if (mDataConnected) {
+ combinedSignalIconId = mDataSignalIconId;
+
+ combinedLabel = mobileLabel;
+ combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
+ mContentDescriptionCombinedSignal = mContentDescriptionDataType;
+ }
+ }
+
+ if (mWifiConnected) {
+ if (mWifiSsid == null) {
+ wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_wifi_nossid);
+ } else {
+ wifiLabel = mWifiSsid;
+ if (DEBUG) {
+ wifiLabel += "xxxxXXXXxxxxXXXX";
+ }
+ }
+
+ combinedLabel = wifiLabel;
+ combinedSignalIconId = mWifiIconId; // set by updateWifiIcons()
+ mContentDescriptionCombinedSignal = mContentDescriptionWifi;
+ } else {
+ if (mHasMobileDataFeature) {
+ wifiLabel = "";
+ } else {
+ wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+ }
+ }
+
+ if (mBluetoothTethered) {
+ combinedLabel = mContext.getString(R.string.bluetooth_tethered);
+ combinedSignalIconId = mBluetoothTetherIconId;
+ mContentDescriptionCombinedSignal = mContext.getString(
+ R.string.accessibility_bluetooth_tether);
+ }
+
+ final boolean ethernetConnected = (mConnectedNetworkType == ConnectivityManager.TYPE_ETHERNET);
+ if (ethernetConnected) {
+ combinedLabel = context.getString(R.string.ethernet_label);
+ }
+
+ if (mAirplaneMode &&
+ (mServiceState == null || (!hasService() && !mServiceState.isEmergencyOnly()))) {
+ // Only display the flight-mode icon if not in "emergency calls only" mode.
+
+ // look again; your radios are now airplanes
+ mContentDescriptionPhoneSignal = mContext.getString(
+ R.string.accessibility_airplane_mode);
+ mAirplaneIconId = FLIGHT_MODE_ICON;
+ mPhoneSignalIconId = mDataSignalIconId = mDataTypeIconId = mQSDataTypeIconId = 0;
+ mQSPhoneSignalIconId = 0;
+
+ // combined values from connected wifi take precedence over airplane mode
+ if (mWifiConnected) {
+ // Suppress "No internet connection." from mobile if wifi connected.
+ mobileLabel = "";
+ } else {
+ if (mHasMobileDataFeature) {
+ // let the mobile icon show "No internet connection."
+ wifiLabel = "";
+ } else {
+ wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+ combinedLabel = wifiLabel;
+ }
+ mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal;
+ combinedSignalIconId = mDataSignalIconId;
+ }
+ }
+ else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected && !ethernetConnected) {
+ // pretty much totally disconnected
+
+ combinedLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+ // On devices without mobile radios, we want to show the wifi icon
+ combinedSignalIconId =
+ mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId;
+ mContentDescriptionCombinedSignal = mHasMobileDataFeature
+ ? mContentDescriptionDataType : mContentDescriptionWifi;
+
+ mDataTypeIconId = 0;
+ mQSDataTypeIconId = 0;
+ if (isCdma()) {
+ if (isCdmaEri()) {
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
+ }
+ } else if (mPhone.isNetworkRoaming()) {
+ mDataTypeIconId = R.drawable.stat_sys_data_fully_connected_roam;
+ mQSDataTypeIconId = TelephonyIcons.QS_DATA_R[mInetCondition];
+ }
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "refreshViews connected={"
+ + (mWifiConnected?" wifi":"")
+ + (mDataConnected?" data":"")
+ + " } level="
+ + ((mSignalStrength == null)?"??":Integer.toString(mSignalStrength.getLevel()))
+ + " combinedSignalIconId=0x"
+ + Integer.toHexString(combinedSignalIconId)
+ + "/" + getResourceName(combinedSignalIconId)
+ + " mobileLabel=" + mobileLabel
+ + " wifiLabel=" + wifiLabel
+ + " emergencyOnly=" + emergencyOnly
+ + " combinedLabel=" + combinedLabel
+ + " mAirplaneMode=" + mAirplaneMode
+ + " mDataActivity=" + mDataActivity
+ + " mPhoneSignalIconId=0x" + Integer.toHexString(mPhoneSignalIconId)
+ + " mQSPhoneSignalIconId=0x" + Integer.toHexString(mQSPhoneSignalIconId)
+ + " mDataDirectionIconId=0x" + Integer.toHexString(mDataDirectionIconId)
+ + " mDataSignalIconId=0x" + Integer.toHexString(mDataSignalIconId)
+ + " mDataTypeIconId=0x" + Integer.toHexString(mDataTypeIconId)
+ + " mQSDataTypeIconId=0x" + Integer.toHexString(mQSDataTypeIconId)
+ + " mWifiIconId=0x" + Integer.toHexString(mWifiIconId)
+ + " mQSWifiIconId=0x" + Integer.toHexString(mQSWifiIconId)
+ + " mBluetoothTetherIconId=0x" + Integer.toHexString(mBluetoothTetherIconId));
+ }
+
+ // update QS
+ for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
+ notifySignalsChangedCallbacks(cb);
+ }
+
+ if (mLastPhoneSignalIconId != mPhoneSignalIconId
+ || mLastWifiIconId != mWifiIconId
+ || mLastInetCondition != mInetCondition
+ || mLastWimaxIconId != mWimaxIconId
+ || mLastDataTypeIconId != mDataTypeIconId
+ || mLastAirplaneMode != mAirplaneMode
+ || mLastLocale != mLocale)
+ {
+ // NB: the mLast*s will be updated later
+ for (SignalCluster cluster : mSignalClusters) {
+ refreshSignalCluster(cluster);
+ }
+ }
+
+ if (mLastAirplaneMode != mAirplaneMode) {
+ mLastAirplaneMode = mAirplaneMode;
+ }
+
+ if (mLastLocale != mLocale) {
+ mLastLocale = mLocale;
+ }
+
+ // the phone icon on phones
+ if (mLastPhoneSignalIconId != mPhoneSignalIconId) {
+ mLastPhoneSignalIconId = mPhoneSignalIconId;
+ }
+
+ // the data icon on phones
+ if (mLastDataDirectionIconId != mDataDirectionIconId) {
+ mLastDataDirectionIconId = mDataDirectionIconId;
+ }
+
+ // the wifi icon on phones
+ if (mLastWifiIconId != mWifiIconId) {
+ mLastWifiIconId = mWifiIconId;
+ }
+
+ if (mLastInetCondition != mInetCondition) {
+ mLastInetCondition = mInetCondition;
+ }
+
+ // the wimax icon on phones
+ if (mLastWimaxIconId != mWimaxIconId) {
+ mLastWimaxIconId = mWimaxIconId;
+ }
+ // the combined data signal icon
+ if (mLastCombinedSignalIconId != combinedSignalIconId) {
+ mLastCombinedSignalIconId = combinedSignalIconId;
+ }
+
+ // the data network type overlay
+ if (mLastDataTypeIconId != mDataTypeIconId) {
+ mLastDataTypeIconId = mDataTypeIconId;
+ }
+
+ // the combinedLabel in the notification panel
+ if (!mLastCombinedLabel.equals(combinedLabel)) {
+ mLastCombinedLabel = combinedLabel;
+ N = mCombinedLabelViews.size();
+ for (int i=0; i<N; i++) {
+ TextView v = mCombinedLabelViews.get(i);
+ v.setText(combinedLabel);
+ }
+ }
+
+ // wifi label
+ N = mWifiLabelViews.size();
+ for (int i=0; i<N; i++) {
+ TextView v = mWifiLabelViews.get(i);
+ v.setText(wifiLabel);
+ if ("".equals(wifiLabel)) {
+ v.setVisibility(View.GONE);
+ } else {
+ v.setVisibility(View.VISIBLE);
+ }
+ }
+
+ // mobile label
+ N = mMobileLabelViews.size();
+ for (int i=0; i<N; i++) {
+ TextView v = mMobileLabelViews.get(i);
+ v.setText(mobileLabel);
+ if ("".equals(mobileLabel)) {
+ v.setVisibility(View.GONE);
+ } else {
+ v.setVisibility(View.VISIBLE);
+ }
+ }
+
+ // e-call label
+ N = mEmergencyLabelViews.size();
+ for (int i=0; i<N; i++) {
+ TextView v = mEmergencyLabelViews.get(i);
+ if (!emergencyOnly) {
+ v.setVisibility(View.GONE);
+ } else {
+ v.setText(mobileLabel); // comes from the telephony stack
+ v.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("NetworkController state:");
+ pw.println(String.format(" %s network type %d (%s)",
+ mConnected?"CONNECTED":"DISCONNECTED",
+ mConnectedNetworkType, mConnectedNetworkTypeName));
+ pw.println(" - telephony ------");
+ pw.print(" hasVoiceCallingFeature()=");
+ pw.println(hasVoiceCallingFeature());
+ pw.print(" hasService()=");
+ pw.println(hasService());
+ pw.print(" mHspaDataDistinguishable=");
+ pw.println(mHspaDataDistinguishable);
+ pw.print(" mDataConnected=");
+ pw.println(mDataConnected);
+ pw.print(" mSimState=");
+ pw.println(mSimState);
+ pw.print(" mPhoneState=");
+ pw.println(mPhoneState);
+ pw.print(" mDataState=");
+ pw.println(mDataState);
+ pw.print(" mDataActivity=");
+ pw.println(mDataActivity);
+ pw.print(" mDataNetType=");
+ pw.print(mDataNetType);
+ pw.print("/");
+ pw.println(TelephonyManager.getNetworkTypeName(mDataNetType));
+ pw.print(" mServiceState=");
+ pw.println(mServiceState);
+ pw.print(" mSignalStrength=");
+ pw.println(mSignalStrength);
+ pw.print(" mLastSignalLevel=");
+ pw.println(mLastSignalLevel);
+ pw.print(" mNetworkName=");
+ pw.println(mNetworkName);
+ pw.print(" mNetworkNameDefault=");
+ pw.println(mNetworkNameDefault);
+ pw.print(" mNetworkNameSeparator=");
+ pw.println(mNetworkNameSeparator.replace("\n","\\n"));
+ pw.print(" mPhoneSignalIconId=0x");
+ pw.print(Integer.toHexString(mPhoneSignalIconId));
+ pw.print("/");
+ pw.print(" mQSPhoneSignalIconId=0x");
+ pw.print(Integer.toHexString(mQSPhoneSignalIconId));
+ pw.print("/");
+ pw.println(getResourceName(mPhoneSignalIconId));
+ pw.print(" mDataDirectionIconId=");
+ pw.print(Integer.toHexString(mDataDirectionIconId));
+ pw.print("/");
+ pw.println(getResourceName(mDataDirectionIconId));
+ pw.print(" mDataSignalIconId=");
+ pw.print(Integer.toHexString(mDataSignalIconId));
+ pw.print("/");
+ pw.println(getResourceName(mDataSignalIconId));
+ pw.print(" mDataTypeIconId=");
+ pw.print(Integer.toHexString(mDataTypeIconId));
+ pw.print("/");
+ pw.println(getResourceName(mDataTypeIconId));
+ pw.print(" mQSDataTypeIconId=");
+ pw.print(Integer.toHexString(mQSDataTypeIconId));
+ pw.print("/");
+ pw.println(getResourceName(mQSDataTypeIconId));
+
+ pw.println(" - wifi ------");
+ pw.print(" mWifiEnabled=");
+ pw.println(mWifiEnabled);
+ pw.print(" mWifiConnected=");
+ pw.println(mWifiConnected);
+ pw.print(" mWifiRssi=");
+ pw.println(mWifiRssi);
+ pw.print(" mWifiLevel=");
+ pw.println(mWifiLevel);
+ pw.print(" mWifiSsid=");
+ pw.println(mWifiSsid);
+ pw.println(String.format(" mWifiIconId=0x%08x/%s",
+ mWifiIconId, getResourceName(mWifiIconId)));
+ pw.println(String.format(" mQSWifiIconId=0x%08x/%s",
+ mQSWifiIconId, getResourceName(mQSWifiIconId)));
+ pw.print(" mWifiActivity=");
+ pw.println(mWifiActivity);
+
+ if (mWimaxSupported) {
+ pw.println(" - wimax ------");
+ pw.print(" mIsWimaxEnabled="); pw.println(mIsWimaxEnabled);
+ pw.print(" mWimaxConnected="); pw.println(mWimaxConnected);
+ pw.print(" mWimaxIdle="); pw.println(mWimaxIdle);
+ pw.println(String.format(" mWimaxIconId=0x%08x/%s",
+ mWimaxIconId, getResourceName(mWimaxIconId)));
+ pw.println(String.format(" mWimaxSignal=%d", mWimaxSignal));
+ pw.println(String.format(" mWimaxState=%d", mWimaxState));
+ pw.println(String.format(" mWimaxExtraState=%d", mWimaxExtraState));
+ }
+
+ pw.println(" - Bluetooth ----");
+ pw.print(" mBtReverseTethered=");
+ pw.println(mBluetoothTethered);
+
+ pw.println(" - connectivity ------");
+ pw.print(" mInetCondition=");
+ pw.println(mInetCondition);
+
+ pw.println(" - icons ------");
+ pw.print(" mLastPhoneSignalIconId=0x");
+ pw.print(Integer.toHexString(mLastPhoneSignalIconId));
+ pw.print("/");
+ pw.println(getResourceName(mLastPhoneSignalIconId));
+ pw.print(" mLastDataDirectionIconId=0x");
+ pw.print(Integer.toHexString(mLastDataDirectionIconId));
+ pw.print("/");
+ pw.println(getResourceName(mLastDataDirectionIconId));
+ pw.print(" mLastWifiIconId=0x");
+ pw.print(Integer.toHexString(mLastWifiIconId));
+ pw.print("/");
+ pw.println(getResourceName(mLastWifiIconId));
+ pw.print(" mLastCombinedSignalIconId=0x");
+ pw.print(Integer.toHexString(mLastCombinedSignalIconId));
+ pw.print("/");
+ pw.println(getResourceName(mLastCombinedSignalIconId));
+ pw.print(" mLastDataTypeIconId=0x");
+ pw.print(Integer.toHexString(mLastDataTypeIconId));
+ pw.print("/");
+ pw.println(getResourceName(mLastDataTypeIconId));
+ pw.print(" mLastCombinedLabel=");
+ pw.print(mLastCombinedLabel);
+ pw.println("");
+ }
+
+ private String getResourceName(int resId) {
+ if (resId != 0) {
+ final Resources res = mContext.getResources();
+ try {
+ return res.getResourceName(resId);
+ } catch (android.content.res.Resources.NotFoundException ex) {
+ return "(unknown)";
+ }
+ } else {
+ return "(null)";
+ }
+ }
+
+ private boolean mDemoMode;
+ private int mDemoInetCondition;
+ private int mDemoWifiLevel;
+ private int mDemoDataTypeIconId;
+ private int mDemoMobileLevel;
+
+ @Override
+ public void dispatchDemoCommand(String command, Bundle args) {
+ if (!mDemoMode && command.equals(COMMAND_ENTER)) {
+ mDemoMode = true;
+ mDemoWifiLevel = mWifiLevel;
+ mDemoInetCondition = mInetCondition;
+ mDemoDataTypeIconId = mDataTypeIconId;
+ mDemoMobileLevel = mLastSignalLevel;
+ } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
+ mDemoMode = false;
+ for (SignalCluster cluster : mSignalClusters) {
+ refreshSignalCluster(cluster);
+ }
+ } else if (mDemoMode && command.equals(COMMAND_NETWORK)) {
+ String airplane = args.getString("airplane");
+ if (airplane != null) {
+ boolean show = airplane.equals("show");
+ for (SignalCluster cluster : mSignalClusters) {
+ cluster.setIsAirplaneMode(show, FLIGHT_MODE_ICON);
+ }
+ }
+ String fully = args.getString("fully");
+ if (fully != null) {
+ mDemoInetCondition = Boolean.parseBoolean(fully) ? 1 : 0;
+ }
+ String wifi = args.getString("wifi");
+ if (wifi != null) {
+ boolean show = wifi.equals("show");
+ String level = args.getString("level");
+ if (level != null) {
+ mDemoWifiLevel = level.equals("null") ? -1
+ : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
+ }
+ int iconId = mDemoWifiLevel < 0 ? R.drawable.stat_sys_wifi_signal_null
+ : WifiIcons.WIFI_SIGNAL_STRENGTH[mDemoInetCondition][mDemoWifiLevel];
+ for (SignalCluster cluster : mSignalClusters) {
+ cluster.setWifiIndicators(
+ show,
+ iconId,
+ mDemoInetCondition == 0,
+ "Demo");
+ }
+ }
+ String mobile = args.getString("mobile");
+ if (mobile != null) {
+ boolean show = mobile.equals("show");
+ String datatype = args.getString("datatype");
+ if (datatype != null) {
+ mDemoDataTypeIconId =
+ datatype.equals("1x") ? R.drawable.stat_sys_data_fully_connected_1x :
+ datatype.equals("3g") ? R.drawable.stat_sys_data_fully_connected_3g :
+ datatype.equals("4g") ? R.drawable.stat_sys_data_fully_connected_4g :
+ datatype.equals("e") ? R.drawable.stat_sys_data_fully_connected_e :
+ datatype.equals("g") ? R.drawable.stat_sys_data_fully_connected_g :
+ datatype.equals("h") ? R.drawable.stat_sys_data_fully_connected_h :
+ datatype.equals("lte") ? R.drawable.stat_sys_data_fully_connected_lte :
+ datatype.equals("roam")
+ ? R.drawable.stat_sys_data_fully_connected_roam :
+ 0;
+ }
+ int[][] icons = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH;
+ String level = args.getString("level");
+ if (level != null) {
+ mDemoMobileLevel = level.equals("null") ? -1
+ : Math.min(Integer.parseInt(level), icons[0].length - 1);
+ }
+ int iconId = mDemoMobileLevel < 0 ? R.drawable.stat_sys_signal_null :
+ icons[mDemoInetCondition][mDemoMobileLevel];
+ for (SignalCluster cluster : mSignalClusters) {
+ cluster.setMobileDataIndicators(
+ show,
+ iconId,
+ mDemoInetCondition == 0,
+ mDemoDataTypeIconId,
+ "Demo",
+ "Demo");
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
index 98d205a..1eb678d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,65 +16,15 @@
package com.android.systemui.statusbar.policy;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.os.UserHandle;
-
-import com.android.internal.view.RotationPolicy;
-
-import java.util.concurrent.CopyOnWriteArrayList;
-
-public final class RotationLockController {
- private final Context mContext;
- private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks =
- new CopyOnWriteArrayList<RotationLockControllerCallback>();
-
- private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
- new RotationPolicy.RotationPolicyListener() {
- @Override
- public void onChange() {
- notifyChanged();
- }
- };
+public interface RotationLockController extends Disposable {
+ int getRotationLockOrientation();
+ boolean isRotationLockAffordanceVisible();
+ boolean isRotationLocked();
+ void setRotationLocked(boolean locked);
+ void addRotationLockControllerCallback(RotationLockControllerCallback callback);
+ void removeRotationLockControllerCallback(RotationLockControllerCallback callback);
public interface RotationLockControllerCallback {
- public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible);
- }
-
- public RotationLockController(Context context) {
- mContext = context;
- RotationPolicy.registerRotationPolicyListener(mContext,
- mRotationPolicyListener, UserHandle.USER_ALL);
- }
-
- public void addRotationLockControllerCallback(RotationLockControllerCallback callback) {
- mCallbacks.add(callback);
- }
-
- public int getRotationLockOrientation() {
- return RotationPolicy.getRotationLockOrientation(mContext);
- }
-
- public boolean isRotationLocked() {
- return RotationPolicy.isRotationLocked(mContext);
- }
-
- public void setRotationLocked(boolean locked) {
- RotationPolicy.setRotationLock(mContext, locked);
- }
-
- public boolean isRotationLockAffordanceVisible() {
- return RotationPolicy.isRotationLockToggleVisible(mContext);
- }
-
- public void release() {
- RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener);
- }
-
- private void notifyChanged() {
- for (RotationLockControllerCallback callback : mCallbacks) {
- callback.onRotationLockStateChanged(RotationPolicy.isRotationLocked(mContext),
- RotationPolicy.isRotationLockToggleVisible(mContext));
- }
+ void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
new file mode 100644
index 0000000..caa07ef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.os.UserHandle;
+
+import com.android.internal.view.RotationPolicy;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/** Platform implementation of the rotation lock controller. **/
+public final class RotationLockControllerImpl implements RotationLockController {
+ private final Context mContext;
+ private final CopyOnWriteArrayList<RotationLockControllerCallback> mCallbacks =
+ new CopyOnWriteArrayList<RotationLockControllerCallback>();
+
+ private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
+ new RotationPolicy.RotationPolicyListener() {
+ @Override
+ public void onChange() {
+ notifyChanged();
+ }
+ };
+
+ public RotationLockControllerImpl(Context context) {
+ mContext = context;
+ RotationPolicy.registerRotationPolicyListener(mContext,
+ mRotationPolicyListener, UserHandle.USER_ALL);
+ }
+
+ public void addRotationLockControllerCallback(RotationLockControllerCallback callback) {
+ mCallbacks.add(callback);
+ }
+
+ public void removeRotationLockControllerCallback(RotationLockControllerCallback callback) {
+ mCallbacks.remove(callback);
+ }
+
+ public int getRotationLockOrientation() {
+ return RotationPolicy.getRotationLockOrientation(mContext);
+ }
+
+ public boolean isRotationLocked() {
+ return RotationPolicy.isRotationLocked(mContext);
+ }
+
+ public void setRotationLocked(boolean locked) {
+ RotationPolicy.setRotationLock(mContext, locked);
+ }
+
+ public boolean isRotationLockAffordanceVisible() {
+ return RotationPolicy.isRotationLockToggleVisible(mContext);
+ }
+
+ @Override
+ public void dispose() {
+ RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener);
+ }
+
+ private void notifyChanged() {
+ for (RotationLockControllerCallback callback : mCallbacks) {
+ callback.onRotationLockStateChanged(RotationPolicy.isRotationLocked(mContext),
+ RotationPolicy.isRotationLockToggleVisible(mContext));
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TetheringController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TetheringController.java
new file mode 100644
index 0000000..143ebaa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TetheringController.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+public interface TetheringController {
+ void addCallback(Callback callback);
+ void removeCallback(Callback callback);
+ boolean isHotspotEnabled();
+ boolean isHotspotSupported();
+
+ public interface Callback {
+ void onHotspotChanged(boolean hotspot);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
new file mode 100644
index 0000000..173af40
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.app.ActivityManagerNative;
+import android.bluetooth.BluetoothAdapter;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
+import android.os.AsyncTask;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.ContactsContract;
+import android.security.KeyChain;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.view.RotationPolicy;
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public final class UserInfoController {
+
+ private static final String TAG = "UserInfoController";
+
+ private final Context mContext;
+ private final ArrayList<OnUserInfoChangedListener> mCallbacks =
+ new ArrayList<OnUserInfoChangedListener>();
+ private AsyncTask<Void, Void, Pair<String, Drawable>> mUserInfoTask;
+
+ private boolean mUseDefaultAvatar;
+ private String mUserName;
+ private Drawable mUserDrawable;
+
+ public UserInfoController(Context context) {
+ mContext = context;
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
+ filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+ mContext.registerReceiver(mReceiver, filter);
+
+ IntentFilter profileFilter = new IntentFilter();
+ profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED);
+ profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
+ mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter,
+ null, null);
+ }
+
+ public void addListener(OnUserInfoChangedListener callback) {
+ mCallbacks.add(callback);
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+ reloadUserInfo();
+ } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+ if (mUseDefaultAvatar) {
+ reloadUserInfo();
+ }
+ }
+ }
+ };
+
+ private final BroadcastReceiver mProfileReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (ContactsContract.Intents.ACTION_PROFILE_CHANGED.equals(action) ||
+ Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
+ try {
+ final int currentUser = ActivityManagerNative.getDefault().getCurrentUser().id;
+ final int changedUser =
+ intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId());
+ if (changedUser == currentUser) {
+ reloadUserInfo();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Couldn't get current user id for profile change", e);
+ }
+ }
+ }
+ };
+
+ public void reloadUserInfo() {
+ if (mUserInfoTask != null) {
+ mUserInfoTask.cancel(false);
+ mUserInfoTask = null;
+ }
+ queryForUserInformation();
+ }
+
+ private Bitmap circularClip(Bitmap input) {
+ Bitmap output = Bitmap.createBitmap(input.getWidth(),
+ input.getHeight(), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(output);
+ final Paint paint = new Paint();
+ paint.setShader(new BitmapShader(input, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
+ paint.setAntiAlias(true);
+ canvas.drawCircle(input.getWidth() / 2, input.getHeight() / 2, input.getWidth() / 2, paint);
+ return output;
+ }
+
+ private void queryForUserInformation() {
+ Context currentUserContext;
+ UserInfo userInfo;
+ try {
+ userInfo = ActivityManagerNative.getDefault().getCurrentUser();
+ currentUserContext = mContext.createPackageContextAsUser("android", 0,
+ new UserHandle(userInfo.id));
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Couldn't create user context", e);
+ throw new RuntimeException(e);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Couldn't get user info", e);
+ throw new RuntimeException(e);
+ }
+ final int userId = userInfo.id;
+ final String userName = userInfo.name;
+
+ final Context context = currentUserContext;
+ mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() {
+ @Override
+ protected Pair<String, Drawable> doInBackground(Void... params) {
+ final UserManager um = UserManager.get(mContext);
+
+ // Fall back to the UserManager nickname if we can't read the name from the local
+ // profile below.
+ String name = userName;
+ Drawable avatar = null;
+ Bitmap rawAvatar = um.getUserIcon(userId);
+ if (rawAvatar != null) {
+ avatar = new BitmapDrawable(mContext.getResources(), circularClip(rawAvatar));
+ } else {
+ avatar = mContext.getResources().getDrawable(R.drawable.ic_qs_default_user);
+ mUseDefaultAvatar = true;
+ }
+
+ // If it's a single-user device, get the profile name, since the nickname is not
+ // usually valid
+ if (um.getUsers().size() <= 1) {
+ // Try and read the display name from the local profile
+ final Cursor cursor = context.getContentResolver().query(
+ ContactsContract.Profile.CONTENT_URI, new String[] {
+ ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME},
+ null, null, null);
+ if (cursor != null) {
+ try {
+ if (cursor.moveToFirst()) {
+ name = cursor.getString(cursor.getColumnIndex(
+ ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+ }
+ return new Pair<String, Drawable>(name, avatar);
+ }
+
+ @Override
+ protected void onPostExecute(Pair<String, Drawable> result) {
+ mUserName = result.first;
+ mUserDrawable = result.second;
+ mUserInfoTask = null;
+ notifyChanged();
+ }
+ };
+ mUserInfoTask.execute();
+ }
+
+ private void notifyChanged() {
+ for (OnUserInfoChangedListener listener : mCallbacks) {
+ listener.onUserInfoChanged(mUserName, mUserDrawable);
+ }
+ }
+
+ public interface OnUserInfoChangedListener {
+ public void onUserInfoChanged(String name, Drawable picture);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
new file mode 100644
index 0000000..6225c12
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.service.notification.Condition;
+
+public interface ZenModeController {
+ void addCallback(Callback callback);
+ void removeCallback(Callback callback);
+ void setZen(boolean zen);
+ boolean isZen();
+ void requestConditions(boolean request);
+ void select(Condition condition);
+
+ public static class Callback {
+ public void onZenChanged(boolean zen) {}
+ public void onConditionsChanged(Condition[] conditions) {}
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
new file mode 100644
index 0000000..d760f78
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.app.INotificationManager;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings.Global;
+import android.service.notification.Condition;
+import android.service.notification.IConditionListener;
+import android.util.Slog;
+
+import com.android.systemui.qs.GlobalSetting;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+
+/** Platform implementation of the zen mode controller. **/
+public class ZenModeControllerImpl implements ZenModeController {
+ private static final String TAG = "ZenModeControllerImpl";
+
+ private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+ private final Context mContext;
+ private final GlobalSetting mSetting;
+ private final INotificationManager mNoMan;
+ private final LinkedHashMap<Uri, Condition> mConditions = new LinkedHashMap<Uri, Condition>();
+
+ private boolean mRequesting;
+
+ public ZenModeControllerImpl(Context context, Handler handler) {
+ mContext = context;
+ mSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) {
+ @Override
+ protected void handleValueChanged(int value) {
+ fireZenChanged(value != 0);
+ }
+ };
+ mNoMan = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ }
+
+ @Override
+ public void addCallback(Callback callback) {
+ mCallbacks.add(callback);
+ }
+
+ @Override
+ public void removeCallback(Callback callback) {
+ mCallbacks.remove(callback);
+ }
+
+ @Override
+ public boolean isZen() {
+ return mSetting.getValue() != 0;
+ }
+
+ @Override
+ public void setZen(boolean zen) {
+ mSetting.setValue(zen ? 1 : 0);
+ }
+
+ @Override
+ public void requestConditions(boolean request) {
+ mRequesting = request;
+ try {
+ mNoMan.requestZenModeConditions(mListener, request ? Condition.FLAG_RELEVANT_NOW : 0);
+ } catch (RemoteException e) {
+ // noop
+ }
+ if (!mRequesting) {
+ mConditions.clear();
+ }
+ }
+
+ @Override
+ public void select(Condition condition) {
+ try {
+ mNoMan.setZenModeCondition(condition == null ? null : condition.id);
+ } catch (RemoteException e) {
+ // noop
+ }
+ }
+
+ private void fireZenChanged(boolean zen) {
+ for (Callback cb : mCallbacks) {
+ cb.onZenChanged(zen);
+ }
+ }
+
+ private void fireConditionsChanged(Condition[] conditions) {
+ for (Callback cb : mCallbacks) {
+ cb.onConditionsChanged(conditions);
+ }
+ }
+
+ private void updateConditions(Condition[] conditions) {
+ if (conditions == null || conditions.length == 0) return;
+ for (Condition c : conditions) {
+ if ((c.flags & Condition.FLAG_RELEVANT_NOW) == 0) continue;
+ mConditions.put(c.id, c);
+ }
+ fireConditionsChanged(
+ mConditions.values().toArray(new Condition[mConditions.values().size()]));
+ }
+
+ private final IConditionListener mListener = new IConditionListener.Stub() {
+ @Override
+ public void onConditionsReceived(Condition[] conditions) {
+ Slog.d(TAG, "onConditionsReceived " + (conditions == null ? 0 : conditions.length)
+ + " mRequesting=" + mRequesting);
+ if (!mRequesting) return;
+ updateConditions(conditions);
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index 4121a40..deab757 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -28,6 +28,8 @@
private int mScrollY;
private boolean mDimmed;
private View mActivatedChild;
+ private float mOverScrollTopAmount;
+ private float mOverScrollBottomAmount;
public int getScrollY() {
return mScrollY;
@@ -72,4 +74,16 @@
public View getActivatedChild() {
return mActivatedChild;
}
+
+ public void setOverScrollAmount(float amount, boolean onTop) {
+ if (onTop) {
+ mOverScrollTopAmount = amount;
+ } else {
+ mOverScrollBottomAmount = amount;
+ }
+ }
+
+ public float getOverScrollAmount(boolean top) {
+ return top ? mOverScrollTopAmount : mOverScrollBottomAmount;
+ }
}
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 afd5068..fbb6695 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -53,6 +53,7 @@
private static final String TAG = "NotificationStackScrollLayout";
private static final boolean DEBUG = false;
+ private static final float RUBBER_BAND_FACTOR = 0.35f;
/**
* Sentinel value for no current active pointer. Used by {@link #mActivePointerId}.
@@ -70,8 +71,8 @@
private int mTouchSlop;
private int mMinimumVelocity;
private int mMaximumVelocity;
- private int mOverscrollDistance;
private int mOverflingDistance;
+ private float mMaxOverScroll;
private boolean mIsBeingDragged;
private int mLastMotionY;
private int mActivePointerId;
@@ -80,9 +81,12 @@
private Paint mDebugPaint;
private int mContentHeight;
private int mCollapsedSize;
+ private int mBottomStackSlowDownHeight;
private int mBottomStackPeekSize;
private int mEmptyMarginBottom;
private int mPaddingBetweenElements;
+ private int mPaddingBetweenElementsDimmed;
+ private int mPaddingBetweenElementsNormal;
private int mTopPadding;
/**
@@ -104,6 +108,16 @@
private ArrayList<View> mSwipedOutViews = new ArrayList<View>();
private final StackStateAnimator mStateAnimator = new StackStateAnimator(this);
+ /**
+ * The raw amount of the overScroll on the top, which is not rubber-banded.
+ */
+ private float mOverScrolledTopPixels;
+
+ /**
+ * The raw amount of the overScroll on the bottom, which is not rubber-banded.
+ */
+ private float mOverScrolledBottomPixels;
+
private OnChildLocationsChangedListener mListener;
private ExpandableView.OnHeightChangedListener mOnHeightChangedListener;
private boolean mNeedsAnimation;
@@ -153,7 +167,10 @@
if (DEBUG) {
int y = mCollapsedSize;
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
- y = (int) (getLayoutHeight() - mBottomStackPeekSize - mCollapsedSize);
+ y = (int) (getLayoutHeight() - mBottomStackPeekSize
+ - mBottomStackSlowDownHeight);
+ canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
+ y = (int) (getLayoutHeight() - mBottomStackPeekSize);
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
y = (int) getLayoutHeight();
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
@@ -169,7 +186,6 @@
mTouchSlop = configuration.getScaledTouchSlop();
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
- mOverscrollDistance = configuration.getScaledOverscrollDistance();
mOverflingDistance = configuration.getScaledOverflingDistance();
float densityScale = getResources().getDisplayMetrics().density;
float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
@@ -183,9 +199,20 @@
.getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
mEmptyMarginBottom = context.getResources().getDimensionPixelSize(
R.dimen.notification_stack_margin_bottom);
- mPaddingBetweenElements = context.getResources()
- .getDimensionPixelSize(R.dimen.notification_padding);
mStackScrollAlgorithm = new StackScrollAlgorithm(context);
+ mPaddingBetweenElementsDimmed = context.getResources()
+ .getDimensionPixelSize(R.dimen.notification_padding_dimmed);
+ mPaddingBetweenElementsNormal = context.getResources()
+ .getDimensionPixelSize(R.dimen.notification_padding);
+ updatePadding(false);
+ }
+
+ private void updatePadding(boolean dimmed) {
+ mPaddingBetweenElements = dimmed
+ ? mPaddingBetweenElementsDimmed
+ : mPaddingBetweenElementsNormal;
+ mBottomStackSlowDownHeight = mStackScrollAlgorithm.getBottomStackSlowDownLength();
+ updateContentHeight();
}
@Override
@@ -527,7 +554,7 @@
* will be false if being flinged.
*/
if (!mScroller.isFinished()) {
- mScroller.abortAnimation();
+ mScroller.forceFinished(true);
}
// Remember where the motion event started
@@ -555,40 +582,23 @@
if (mIsBeingDragged) {
// Scroll to follow the motion event
mLastMotionY = y;
-
- final int oldX = mScrollX;
- final int oldY = mOwnScrollY;
final int range = getScrollRange();
- final int overscrollMode = getOverScrollMode();
- final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
- (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
+
+ float scrollAmount;
+ if (deltaY < 0) {
+ scrollAmount = overScrollDown(deltaY);
+ } else {
+ scrollAmount = overScrollUp(deltaY, range);
+ }
// Calling overScrollBy will call onOverScrolled, which
// calls onScrollChanged if applicable.
- if (overScrollBy(0, deltaY, 0, mOwnScrollY,
- 0, range, 0, mOverscrollDistance, true)) {
- // Break our velocity if we hit a scroll barrier.
- mVelocityTracker.clear();
+ if (scrollAmount != 0.0f) {
+ // The scrolling motion could not be compensated with the
+ // existing overScroll, we have to scroll the view
+ overScrollBy(0, (int) scrollAmount, 0, mOwnScrollY,
+ 0, range, 0, getHeight() / 2, true);
}
- // TODO: Overscroll
-// if (canOverscroll) {
-// final int pulledToY = oldY + deltaY;
-// if (pulledToY < 0) {
-// mEdgeGlowTop.onPull((float) deltaY / getHeight());
-// if (!mEdgeGlowBottom.isFinished()) {
-// mEdgeGlowBottom.onRelease();
-// }
-// } else if (pulledToY > range) {
-// mEdgeGlowBottom.onPull((float) deltaY / getHeight());
-// if (!mEdgeGlowTop.isFinished()) {
-// mEdgeGlowTop.onRelease();
-// }
-// }
-// if (mEdgeGlowTop != null
-// && (!mEdgeGlowTop.isFinished() || !mEdgeGlowBottom.isFinished())){
-// postInvalidateOnAnimation();
-// }
-// }
}
break;
case MotionEvent.ACTION_UP:
@@ -635,6 +645,68 @@
return true;
}
+ /**
+ * Perform a scroll upwards and adapt the overscroll amounts accordingly
+ *
+ * @param deltaY The amount to scroll upwards, has to be positive.
+ * @return The amount of scrolling to be performed by the scroller,
+ * not handled by the overScroll amount.
+ */
+ private float overScrollUp(int deltaY, int range) {
+ deltaY = Math.max(deltaY, 0);
+ float currentTopAmount = getCurrentOverScrollAmount(true);
+ float newTopAmount = currentTopAmount - deltaY;
+ if (currentTopAmount > 0) {
+ setOverScrollAmount(newTopAmount, true /* onTop */,
+ false /* animate */);
+ }
+ // Top overScroll might not grab all scrolling motion,
+ // we have to scroll as well.
+ float scrollAmount = newTopAmount < 0 ? -newTopAmount : 0.0f;
+ float newScrollY = mOwnScrollY + scrollAmount;
+ if (newScrollY > range) {
+ float currentBottomPixels = getCurrentOverScrolledPixels(false);
+ // We overScroll on the top
+ setOverScrolledPixels(currentBottomPixels + newScrollY - range,
+ false /* onTop */,
+ false /* animate */);
+ mOwnScrollY = range;
+ scrollAmount = 0.0f;
+ }
+ return scrollAmount;
+ }
+
+ /**
+ * Perform a scroll downward and adapt the overscroll amounts accordingly
+ *
+ * @param deltaY The amount to scroll downwards, has to be negative.
+ * @return The amount of scrolling to be performed by the scroller,
+ * not handled by the overScroll amount.
+ */
+ private float overScrollDown(int deltaY) {
+ deltaY = Math.min(deltaY, 0);
+ float currentBottomAmount = getCurrentOverScrollAmount(false);
+ float newBottomAmount = currentBottomAmount + deltaY;
+ if (currentBottomAmount > 0) {
+ setOverScrollAmount(newBottomAmount, false /* onTop */,
+ false /* animate */);
+ }
+ // Bottom overScroll might not grab all scrolling motion,
+ // we have to scroll as well.
+ float scrollAmount = newBottomAmount < 0 ? newBottomAmount : 0.0f;
+ float newScrollY = mOwnScrollY + scrollAmount;
+ if (newScrollY < 0) {
+ float currentTopPixels = getCurrentOverScrolledPixels(true);
+ // We overScroll on the top
+ setOverScrolledPixels(currentTopPixels - newScrollY,
+ true /* onTop */,
+ false /* animate */);
+ mOwnScrollY = 0;
+ scrollAmount = 0.0f;
+ }
+ return scrollAmount;
+ }
+
private void onSecondaryPointerUp(MotionEvent ev) {
final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
MotionEvent.ACTION_POINTER_INDEX_SHIFT;
@@ -684,23 +756,16 @@
if (oldX != x || oldY != y) {
final int range = getScrollRange();
- final int overscrollMode = getOverScrollMode();
- final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
- (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
+ if (y < 0 && oldY >= 0 || y > range && oldY <= range) {
+ float currVelocity = mScroller.getCurrVelocity();
+ if (currVelocity >= mMinimumVelocity) {
+ mMaxOverScroll = Math.abs(currVelocity) / 1000 * mOverflingDistance;
+ }
+ }
overScrollBy(x - oldX, y - oldY, oldX, oldY, 0, range,
- 0, mOverflingDistance, false);
+ 0, (int) (mMaxOverScroll), false);
onScrollChanged(mScrollX, mOwnScrollY, oldX, oldY);
-
- if (canOverscroll) {
- // TODO: Overscroll
-// if (y < 0 && oldY >= 0) {
-// mEdgeGlowTop.onAbsorb((int) mScroller.getCurrVelocity());
-// } else if (y > range && oldY <= range) {
-// mEdgeGlowBottom.onAbsorb((int) mScroller.getCurrVelocity());
-// }
- }
- updateChildren();
}
// Keep on drawing until the animation has finished.
@@ -708,6 +773,81 @@
}
}
+ @Override
+ protected int computeVerticalScrollRange() {
+ // needed for the overScroller
+ return mContentHeight;
+ }
+
+ /**
+ * Set the amount of overScrolled pixels which will force the view to apply a rubber-banded
+ * overscroll effect based on numPixels. By default this will also cancel animations on the
+ * same overScroll edge.
+ *
+ * @param numPixels The amount of pixels to overScroll by. These will be scaled according to
+ * the rubber-banding logic.
+ * @param onTop Should the effect be applied on top of the scroller.
+ * @param animate Should an animation be performed.
+ */
+ public void setOverScrolledPixels(float numPixels, boolean onTop, boolean animate) {
+ setOverScrollAmount(numPixels * RUBBER_BAND_FACTOR, onTop, animate, true);
+ }
+
+ /**
+ * Set the effective overScroll amount which will be directly reflected in the layout.
+ * By default this will also cancel animations on the same overScroll edge.
+ *
+ * @param amount The amount to overScroll by.
+ * @param onTop Should the effect be applied on top of the scroller.
+ * @param animate Should an animation be performed.
+ */
+ public void setOverScrollAmount(float amount, boolean onTop, boolean animate) {
+ setOverScrollAmount(amount, onTop, animate, true);
+ }
+
+ /**
+ * Set the effective overScroll amount which will be directly reflected in the layout.
+ *
+ * @param amount The amount to overScroll by.
+ * @param onTop Should the effect be applied on top of the scroller.
+ * @param animate Should an animation be performed.
+ * @param cancelAnimators Should running animations be cancelled.
+ */
+ public void setOverScrollAmount(float amount, boolean onTop, boolean animate,
+ boolean cancelAnimators) {
+ if (cancelAnimators) {
+ mStateAnimator.cancelOverScrollAnimators(onTop);
+ }
+ setOverScrollAmountInternal(amount, onTop, animate);
+ }
+
+ private void setOverScrollAmountInternal(float amount, boolean onTop, boolean animate) {
+ amount = Math.max(0, amount);
+ if (animate) {
+ mStateAnimator.animateOverScrollToAmount(amount, onTop);
+ } else {
+ setOverScrolledPixels(amount / RUBBER_BAND_FACTOR, onTop);
+ mAmbientState.setOverScrollAmount(amount, onTop);
+ requestChildrenUpdate();
+ }
+ }
+
+ public float getCurrentOverScrollAmount(boolean top) {
+ return mAmbientState.getOverScrollAmount(top);
+ }
+
+ public float getCurrentOverScrolledPixels(boolean top) {
+ return top? mOverScrolledTopPixels : mOverScrolledBottomPixels;
+ }
+
+ private void setOverScrolledPixels(float amount, boolean onTop) {
+ if (onTop) {
+ mOverScrolledTopPixels = amount;
+ } else {
+ mOverScrolledBottomPixels = amount;
+ }
+ }
+
private void customScrollTo(int y) {
mOwnScrollY = y;
updateChildren();
@@ -721,33 +861,51 @@
final int oldY = mOwnScrollY;
mScrollX = scrollX;
mOwnScrollY = scrollY;
- invalidateParentIfNeeded();
- onScrollChanged(mScrollX, mOwnScrollY, oldX, oldY);
if (clampedY) {
- mScroller.springBack(mScrollX, mOwnScrollY, 0, 0, 0, getScrollRange());
+ springBack();
+ } else {
+ onScrollChanged(mScrollX, mOwnScrollY, oldX, oldY);
+ invalidateParentIfNeeded();
+ updateChildren();
}
- updateChildren();
} else {
customScrollTo(scrollY);
scrollTo(scrollX, mScrollY);
}
}
+ private void springBack() {
+ int scrollRange = getScrollRange();
+ boolean overScrolledTop = mOwnScrollY <= 0;
+ boolean overScrolledBottom = mOwnScrollY >= scrollRange;
+ if (overScrolledTop || overScrolledBottom) {
+ boolean onTop;
+ float newAmount;
+ if (overScrolledTop) {
+ onTop = true;
+ newAmount = -mOwnScrollY;
+ mOwnScrollY = 0;
+ } else {
+ onTop = false;
+ newAmount = mOwnScrollY - scrollRange;
+ mOwnScrollY = scrollRange;
+ }
+ setOverScrollAmount(newAmount, onTop, false);
+ setOverScrollAmount(0.0f, onTop, true);
+ mScroller.forceFinished(true);
+ }
+ }
+
private int getScrollRange() {
int scrollRange = 0;
ExpandableView firstChild = (ExpandableView) getFirstChildNotGone();
if (firstChild != null) {
int contentHeight = getContentHeight();
int firstChildMaxExpandHeight = getMaxExpandHeight(firstChild);
-
- scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight + mBottomStackPeekSize);
+ scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight + mBottomStackPeekSize
+ + mBottomStackSlowDownHeight);
if (scrollRange > 0) {
View lastChild = getLastChildNotGone();
- if (isViewExpanded(lastChild)) {
- // last child is expanded, so we have to ensure that it can exit the
- // bottom stack
- scrollRange += mCollapsedSize + mPaddingBetweenElements;
- }
// We want to at least be able collapse the first item and not ending in a weird
// end state.
scrollRange = Math.max(scrollRange, firstChildMaxExpandHeight - mCollapsedSize);
@@ -829,7 +987,23 @@
int height = (int) getLayoutHeight();
int bottom = getContentHeight();
- mScroller.fling(mScrollX, mOwnScrollY, 0, velocityY, 0, 0, 0,
+ float topAmount = getCurrentOverScrollAmount(true);
+ float bottomAmount = getCurrentOverScrollAmount(false);
+ if (velocityY < 0 && topAmount > 0) {
+ mOwnScrollY -= (int) topAmount;
+ setOverScrollAmount(0, true, false);
+ mMaxOverScroll = Math.abs(velocityY) / 1000f * RUBBER_BAND_FACTOR
+ * mOverflingDistance + topAmount;
+ } else if (velocityY > 0 && bottomAmount > 0) {
+ mOwnScrollY += bottomAmount;
+ setOverScrollAmount(0, false, false);
+ mMaxOverScroll = Math.abs(velocityY) / 1000f * RUBBER_BAND_FACTOR
+ * mOverflingDistance + bottomAmount;
+ } else {
+ // it will be set once we reach the boundary
+ mMaxOverScroll = 0.0f;
+ }
+ mScroller.fling(mScrollX, mOwnScrollY, 1, velocityY, 0, 0, 0,
Math.max(0, bottom - height), 0, height/2);
postInvalidateOnAnimation();
@@ -841,11 +1015,12 @@
recycleVelocityTracker();
- // TODO: Overscroll
-// if (mEdgeGlowTop != null) {
-// mEdgeGlowTop.onRelease();
-// mEdgeGlowBottom.onRelease();
-// }
+ if (getCurrentOverScrollAmount(true /* onTop */) > 0) {
+ setOverScrollAmount(0, true /* onTop */, true /* animate */);
+ }
+ if (getCurrentOverScrollAmount(false /* onTop */) > 0) {
+ setOverScrollAmount(0, false /* onTop */, true /* animate */);
+ }
}
@Override
@@ -1181,7 +1356,7 @@
public int getEmptyBottomMargin() {
int emptyMargin = mMaxLayoutHeight - mContentHeight;
if (needsHeightAdaption()) {
- emptyMargin = emptyMargin - mCollapsedSize - mBottomStackPeekSize;
+ emptyMargin = emptyMargin - mBottomStackSlowDownHeight - mBottomStackPeekSize;
}
return Math.max(emptyMargin, 0);
}
@@ -1226,7 +1401,9 @@
* See {@link AmbientState#setDimmed}.
*/
public void setDimmed(boolean dimmed, boolean animate) {
+ mStackScrollAlgorithm.setDimmed(dimmed);
mAmbientState.setDimmed(dimmed);
+ updatePadding(dimmed);
if (animate) {
mDimmedNeedsAnimation = true;
mNeedsAnimation = true;
@@ -1311,6 +1488,7 @@
// ANIMATION_TYPE_DIMMED
new AnimationFilter()
+ .animateY()
.animateScale()
.animateDimmed()
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java
index 38b544f..1c37c35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java
@@ -38,27 +38,26 @@
* the actual visual distance below the top card but is a maximum,
* achieved when the next card just starts transitioning into the stack and
* the stack is full.
- * If totalTransitionDistance is equal to this, we directly start at the peek,
- * otherwise the first element transitions between 0 and
- * totalTransitionDistance - peekSize.
+ * If distanceToPeekStart is 0, we directly start at the peek, otherwise the
+ * first element transitions between 0 and distanceToPeekStart.
* Visualization:
* --------------------------------------------------- ---
* | | |
- * | FIRST ITEM | | <- totalTransitionDistance
+ * | FIRST ITEM | | <- distanceToPeekStart
* | | |
- * |---------------------------------------------------| | ---
- * |__________________SECOND ITEM______________________| | | <- peekSize
- * |===================================================| _|_ _|_
+ * |---------------------------------------------------| --- ---
+ * |__________________SECOND ITEM______________________| | <- peekSize
+ * |===================================================| _|_
*
- * @param totalTransitionDistance The total transition distance an element has to go through
+ * @param distanceToPeekStart The distance to the start of the peak.
* @param linearPart The interpolation factor between the linear and the quadratic amount taken.
* This factor must be somewhere in [0 , 1]
*/
PiecewiseLinearIndentationFunctor(int maxItemsInStack,
int peekSize,
- int totalTransitionDistance,
+ int distanceToPeekStart,
float linearPart) {
- super(maxItemsInStack, peekSize, totalTransitionDistance);
+ super(maxItemsInStack, peekSize, distanceToPeekStart);
mBaseValues = new ArrayList<Float>(maxItemsInStack+1);
initBaseValues();
mLinearPart = linearPart;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java
index f72947a..034eba6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java
@@ -21,8 +21,8 @@
*/
public abstract class StackIndentationFunctor {
- protected final int mTotalTransitionDistance;
- protected final int mDistanceToPeekStart;
+ protected int mTotalTransitionDistance;
+ protected int mDistanceToPeekStart;
protected int mMaxItemsInStack;
protected int mPeekSize;
protected boolean mStackStartsAtPeek;
@@ -37,31 +37,41 @@
* the actual visual distance below the top card but is a maximum,
* achieved when the next card just starts transitioning into the stack and
* the stack is full.
- * If totalTransitionDistance is equal to this, we directly start at the peek,
- * otherwise the first element transitions between 0 and
- * totalTransitionDistance - peekSize.
+ * If distanceToPeekStart is 0, we directly start at the peek, otherwise the
+ * first element transitions between 0 and distanceToPeekStart.
* Visualization:
* --------------------------------------------------- ---
* | | |
- * | FIRST ITEM | | <- totalTransitionDistance
+ * | FIRST ITEM | | <- distanceToPeekStart
* | | |
- * |---------------------------------------------------| | ---
- * |__________________SECOND ITEM______________________| | | <- peekSize
- * |===================================================| _|_ _|_
+ * |---------------------------------------------------| --- ---
+ * |__________________SECOND ITEM______________________| | <- peekSize
+ * |===================================================| _|_
*
- * @param totalTransitionDistance The total transition distance an element has to go through
+ * @param distanceToPeekStart The distance to the start of the peak.
*/
- StackIndentationFunctor(int maxItemsInStack, int peekSize, int totalTransitionDistance) {
- mTotalTransitionDistance = totalTransitionDistance;
- mDistanceToPeekStart = mTotalTransitionDistance - peekSize;
+ StackIndentationFunctor(int maxItemsInStack, int peekSize, int distanceToPeekStart) {
+ mDistanceToPeekStart = distanceToPeekStart;
mStackStartsAtPeek = mDistanceToPeekStart == 0;
mMaxItemsInStack = maxItemsInStack;
mPeekSize = peekSize;
+ updateTotalTransitionDistance();
}
+ private void updateTotalTransitionDistance() {
+ mTotalTransitionDistance = mDistanceToPeekStart + mPeekSize;
+ }
+
public void setPeekSize(int mPeekSize) {
this.mPeekSize = mPeekSize;
+ updateTotalTransitionDistance();
+ }
+
+ public void setDistanceToPeekStart(int distanceToPeekStart) {
+ mDistanceToPeekStart = distanceToPeekStart;
+ mStackStartsAtPeek = mDistanceToPeekStart == 0;
+ updateTotalTransitionDistance();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 5e4d496..d572ea5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -65,13 +65,40 @@
private ExpandableView mFirstChildWhileExpanding;
private boolean mExpandedOnStart;
private int mTopStackTotalSize;
+ private int mPaddingBetweenElementsDimmed;
+ private int mPaddingBetweenElementsNormal;
+ private int mBottomStackSlowDownLength;
public StackScrollAlgorithm(Context context) {
initConstants(context);
+ updatePadding(false);
+ }
+
+ private void updatePadding(boolean dimmed) {
+ mPaddingBetweenElements = dimmed
+ ? mPaddingBetweenElementsDimmed
+ : mPaddingBetweenElementsNormal;
+ mTopStackTotalSize = mCollapsedSize + mPaddingBetweenElements;
+ mTopStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
+ MAX_ITEMS_IN_TOP_STACK,
+ mTopStackPeekSize,
+ mTopStackTotalSize - mTopStackPeekSize,
+ 0.5f);
+ mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
+ MAX_ITEMS_IN_BOTTOM_STACK,
+ mBottomStackPeekSize,
+ getBottomStackSlowDownLength(),
+ 0.5f);
+ }
+
+ public int getBottomStackSlowDownLength() {
+ return mBottomStackSlowDownLength + mPaddingBetweenElements;
}
private void initConstants(Context context) {
- mPaddingBetweenElements = context.getResources()
+ mPaddingBetweenElementsDimmed = context.getResources()
+ .getDimensionPixelSize(R.dimen.notification_padding_dimmed);
+ mPaddingBetweenElementsNormal = context.getResources()
.getDimensionPixelSize(R.dimen.notification_padding);
mCollapsedSize = context.getResources()
.getDimensionPixelSize(R.dimen.notification_min_height);
@@ -82,17 +109,8 @@
mZDistanceBetweenElements = context.getResources()
.getDimensionPixelSize(R.dimen.z_distance_between_notifications);
mZBasicHeight = (MAX_ITEMS_IN_BOTTOM_STACK + 1) * mZDistanceBetweenElements;
- mTopStackTotalSize = mCollapsedSize + mPaddingBetweenElements;
- mTopStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
- MAX_ITEMS_IN_TOP_STACK,
- mTopStackPeekSize,
- mTopStackTotalSize,
- 0.5f);
- mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
- MAX_ITEMS_IN_BOTTOM_STACK,
- mBottomStackPeekSize,
- mCollapsedSize + mBottomStackPeekSize + mPaddingBetweenElements,
- 0.5f);
+ mBottomStackSlowDownLength = context.getResources()
+ .getDimensionPixelSize(R.dimen.bottom_stack_slow_down_length);
}
@@ -110,7 +128,10 @@
algorithmState.scrolledPixelsTop = 0;
algorithmState.itemsInBottomStack = 0.0f;
algorithmState.partialInBottom = 0.0f;
- algorithmState.scrollY = ambientState.getScrollY() + mCollapsedSize;
+ float topOverScroll = ambientState.getOverScrollAmount(true /* onTop */);
+ float bottomOverScroll = ambientState.getOverScrollAmount(false /* onTop */);
+ algorithmState.scrollY = (int) (ambientState.getScrollY() + mCollapsedSize
+ + bottomOverScroll - topOverScroll);
updateVisibleChildren(resultState, algorithmState);
@@ -197,7 +218,6 @@
*
* @param resultState The result state to update if a change to the properties of a child occurs
* @param algorithmState The state in which the current pass of the algorithm is currently in
- * and which will be updated
*/
private void updatePositionsForState(StackScrollState resultState,
StackScrollAlgorithmState algorithmState) {
@@ -206,7 +226,7 @@
float bottomPeekStart = mInnerHeight - mBottomStackPeekSize;
// The position where the bottom stack starts.
- float bottomStackStart = bottomPeekStart - mCollapsedSize;
+ float bottomStackStart = bottomPeekStart - mBottomStackSlowDownLength;
// The y coordinate of the current child.
float currentYPosition = 0.0f;
@@ -277,7 +297,7 @@
// The first card is always rendered.
if (i == 0) {
childViewState.alpha = 1.0f;
- childViewState.yTranslation = 0;
+ childViewState.yTranslation = Math.max(mCollapsedSize - algorithmState.scrollY, 0);
childViewState.location = StackScrollState.ViewState.LOCATION_FIRST_CARD;
}
if (childViewState.location == StackScrollState.ViewState.LOCATION_UNKNOWN) {
@@ -352,7 +372,7 @@
algorithmState.itemsInBottomStack += algorithmState.partialInBottom;
childViewState.yTranslation = transitioningPositionStart + offset - childHeight
- mPaddingBetweenElements;
-
+
// We want at least to be at the end of the top stack when collapsing
clampPositionToTopStackEnd(childViewState, childHeight);
childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA;
@@ -436,7 +456,6 @@
*
* @param resultState The result state to update if a height change of an child occurs
* @param algorithmState The state in which the current pass of the algorithm is currently in
- * and which will be updated
*/
private void findNumberOfItemsInTopStackAndUpdateState(StackScrollState resultState,
StackScrollAlgorithmState algorithmState) {
@@ -454,7 +473,7 @@
+ childHeight
+ mPaddingBetweenElements;
if (yPositionInScrollView < algorithmState.scrollY) {
- if (i == 0 && algorithmState.scrollY == mCollapsedSize) {
+ if (i == 0 && algorithmState.scrollY <= mCollapsedSize) {
// The starting position of the bottom stack peek
int bottomPeekStart = mInnerHeight - mBottomStackPeekSize;
@@ -621,6 +640,10 @@
}
}
+ public void setDimmed(boolean dimmed) {
+ updatePadding(dimmed);
+ }
+
class StackScrollAlgorithmState {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index ca383aa..5ac51f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -18,7 +18,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
@@ -73,6 +72,9 @@
private AnimationFilter mAnimationFilter = new AnimationFilter();
private long mCurrentLength;
+ private ValueAnimator mTopOverScrollAnimator;
+ private ValueAnimator mBottomOverScrollAnimator;
+
public StackStateAnimator(NotificationStackScrollLayout hostLayout) {
mHostLayout = hostLayout;
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(hostLayout.getContext(),
@@ -510,7 +512,7 @@
ArrayList<NotificationStackScrollLayout.AnimationEvent> animationEvents,
StackScrollState finalState) {
mNewEvents.clear();
- for (NotificationStackScrollLayout.AnimationEvent event: animationEvents) {
+ for (NotificationStackScrollLayout.AnimationEvent event : animationEvents) {
View changingView = event.changingView;
if (!mHandledEvents.contains(event)) {
if (event.animationType == NotificationStackScrollLayout.AnimationEvent
@@ -532,4 +534,34 @@
}
}
}
+
+ public void animateOverScrollToAmount(float targetAmount, final boolean onTop) {
+ final float startOverScrollAmount = mHostLayout.getCurrentOverScrollAmount(onTop);
+ cancelOverScrollAnimators(onTop);
+ ValueAnimator overScrollAnimator = ValueAnimator.ofFloat(startOverScrollAmount,
+ targetAmount);
+ overScrollAnimator.setDuration(ANIMATION_DURATION_STANDARD);
+ overScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float currentOverScroll = (float) animation.getAnimatedValue();
+ mHostLayout.setOverScrollAmount(currentOverScroll, onTop, false /* animate */,
+ false /* cancelAnimators */);
+ }
+ });
+ overScrollAnimator.setInterpolator(mFastOutSlowInInterpolator);
+ overScrollAnimator.start();
+ if (onTop) {
+ mTopOverScrollAnimator = overScrollAnimator;
+ } else {
+ mBottomOverScrollAnimator = overScrollAnimator;
+ }
+ }
+
+ public void cancelOverScrollAnimators(boolean onTop) {
+ ValueAnimator currentAnimator = onTop ? mTopOverScrollAnimator : mBottomOverScrollAnimator;
+ if (currentAnimator != null) {
+ currentAnimator.cancel();
+ }
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index fec9dda..673ce0b 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -183,11 +183,17 @@
mDialog = createDialog();
prepareDialog();
- WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
- attrs.setTitle("GlobalActions");
- mDialog.getWindow().setAttributes(attrs);
- mDialog.show();
- mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
+ // If we only have 1 item and it's a simple press action, just do this action.
+ if (mAdapter.getCount() == 1
+ && mAdapter.getItem(0) instanceof SinglePressAction) {
+ ((SinglePressAction) mAdapter.getItem(0)).onPress();
+ } else {
+ WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
+ attrs.setTitle("GlobalActions");
+ mDialog.getWindow().setAttributes(attrs);
+ mDialog.show();
+ mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
+ }
}
/**
@@ -398,7 +404,7 @@
@Override
public boolean showBeforeProvisioning() {
- return false;
+ return true;
}
};
}
@@ -1024,6 +1030,7 @@
mEnableAccessibilityController = null;
super.setCanceledOnTouchOutside(true);
}
+
super.onStart();
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index b1fea03..f6c8001 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -44,6 +44,7 @@
import android.app.KeyguardManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -301,6 +302,11 @@
throw new AndroidRuntimeException(
"You cannot combine swipe dismissal and the action bar.");
}
+
+ if (featureId == FEATURE_INDETERMINATE_PROGRESS &&
+ getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ throw new AndroidRuntimeException("You cannot use indeterminate progress on a watch.");
+ }
return super.requestFeature(featureId);
}
@@ -4160,4 +4166,22 @@
void sendCloseSystemWindows(String reason) {
PhoneWindowManager.sendCloseSystemWindows(getContext(), reason);
}
+
+ @Override
+ public int getStatusBarColor() {
+ return 0;
+ }
+
+ @Override
+ public void setStatusBarColor(int color) {
+ }
+
+ @Override
+ public int getNavigationBarColor() {
+ return 0;
+ }
+
+ @Override
+ public void setNavigationBarColor(int color) {
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ae6aeee..4ee8103 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -4777,9 +4777,16 @@
mHandler.post(new Runnable() {
@Override public void run() {
if (mBootMsgDialog == null) {
- int theme = mContext.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WATCH) ?
- com.android.internal.R.style.Theme_Micro_Dialog_Alert : 0;
+ int theme;
+ if (mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WATCH)) {
+ theme = com.android.internal.R.style.Theme_Micro_Dialog_Alert;
+ } else if (mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TELEVISION)) {
+ theme = com.android.internal.R.style.Theme_Leanback_Dialog_Alert;
+ } else {
+ theme = 0;
+ }
mBootMsgDialog = new ProgressDialog(mContext, theme) {
// This dialog will consume all events coming in to
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 3619112..36b5cfb 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -38,6 +38,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.graphics.Point;
import android.graphics.Rect;
@@ -197,6 +198,8 @@
private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
+ private final UserManager mUserManager;
+
private int mCurrentUserId = UserHandle.USER_OWNER;
private final LongArray mTempLongArray = new LongArray();
@@ -210,15 +213,6 @@
return getUserStateLocked(mCurrentUserId);
}
- private UserState getUserStateLocked(int userId) {
- UserState state = mUserStates.get(userId);
- if (state == null) {
- state = new UserState(userId);
- mUserStates.put(userId, state);
- }
- return state;
- }
-
/**
* Creates a new instance.
*
@@ -228,6 +222,7 @@
mContext = context;
mPackageManager = mContext.getPackageManager();
mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mSecurityPolicy = new SecurityPolicy();
mMainHandler = new MainHandler(mContext.getMainLooper());
registerBroadcastReceivers();
@@ -235,11 +230,22 @@
context.getContentResolver());
}
+ private UserState getUserStateLocked(int userId) {
+ UserState state = mUserStates.get(userId);
+ if (state == null) {
+ state = new UserState(userId);
+ mUserStates.put(userId, state);
+ }
+ return state;
+ }
+
private void registerBroadcastReceivers() {
PackageMonitor monitor = new PackageMonitor() {
@Override
public void onSomePackagesChanged() {
synchronized (mLock) {
+ // Only the profile parent can install accessibility services.
+ // Therefore we ignore packages from linked profiles.
if (getChangingUserId() != mCurrentUserId) {
return;
}
@@ -262,6 +268,8 @@
public void onPackageRemoved(String packageName, int uid) {
synchronized (mLock) {
final int userId = getChangingUserId();
+ // Only the profile parent can install accessibility services.
+ // Therefore we ignore packages from linked profiles.
if (userId != mCurrentUserId) {
return;
}
@@ -297,6 +305,8 @@
int uid, boolean doit) {
synchronized (mLock) {
final int userId = getChangingUserId();
+ // Only the profile parent can install accessibility services.
+ // Therefore we ignore packages from linked profiles.
if (userId != mCurrentUserId) {
return false;
}
@@ -359,6 +369,9 @@
@Override
public int addClient(IAccessibilityManagerClient client, int userId) {
synchronized (mLock) {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
// If the client is from a process that runs across users such as
@@ -388,6 +401,9 @@
@Override
public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) {
synchronized (mLock) {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution..
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
// This method does nothing for a background user.
@@ -414,6 +430,9 @@
@Override
public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
synchronized (mLock) {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
// The automation service is a fake one and should not be reported
@@ -435,6 +454,9 @@
int userId) {
List<AccessibilityServiceInfo> result = null;
synchronized (mLock) {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
@@ -468,6 +490,9 @@
public void interrupt(int userId) {
CopyOnWriteArrayList<Service> services;
synchronized (mLock) {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
// This method does nothing for a background user.
@@ -491,6 +516,9 @@
public int addAccessibilityInteractionConnection(IWindow windowToken,
IAccessibilityInteractionConnection connection, int userId) throws RemoteException {
synchronized (mLock) {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
final int windowId = sNextWindowId++;
@@ -527,6 +555,9 @@
@Override
public void removeAccessibilityInteractionConnection(IWindow window) {
synchronized (mLock) {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
UserHandle.getCallingUserId());
IBinder token = window.asBinder();
@@ -675,6 +706,9 @@
Manifest.permission.RETRIEVE_WINDOW_TOKEN,
GET_WINDOW_TOKEN);
synchronized (mLock) {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(
UserHandle.getCallingUserId());
@@ -770,7 +804,7 @@
}
// Disconnect from services for the old user.
- UserState oldUserState = getUserStateLocked(mCurrentUserId);
+ UserState oldUserState = getCurrentUserStateLocked();
oldUserState.onSwitchToAnotherUser();
// Disable the local managers for the old user.
@@ -2034,6 +2068,9 @@
@Override
public List<AccessibilityWindowInfo> getWindows() {
synchronized (mLock) {
+ // We treat calls from a profile as if made by its perent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(
UserHandle.getCallingUserId());
@@ -2062,6 +2099,9 @@
@Override
public AccessibilityWindowInfo getWindow(int windowId) {
synchronized (mLock) {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(
UserHandle.getCallingUserId());
@@ -2092,6 +2132,9 @@
final int resolvedWindowId;
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(
UserHandle.getCallingUserId());
@@ -2136,9 +2179,12 @@
final int resolvedWindowId;
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.getCallingUserId());
+ UserHandle.getCallingUserId());
if (resolvedUserId != mCurrentUserId) {
return false;
}
@@ -2180,9 +2226,12 @@
final int resolvedWindowId;
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.getCallingUserId());
+ UserHandle.getCallingUserId());
if (resolvedUserId != mCurrentUserId) {
return false;
}
@@ -2224,9 +2273,12 @@
final int resolvedWindowId;
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.getCallingUserId());
+ UserHandle.getCallingUserId());
if (resolvedUserId != mCurrentUserId) {
return false;
}
@@ -2268,9 +2320,12 @@
final int resolvedWindowId;
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.getCallingUserId());
+ UserHandle.getCallingUserId());
if (resolvedUserId != mCurrentUserId) {
return false;
}
@@ -2311,9 +2366,12 @@
final int resolvedWindowId;
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.getCallingUserId());
+ UserHandle.getCallingUserId());
if (resolvedUserId != mCurrentUserId) {
return false;
}
@@ -2346,9 +2404,12 @@
public boolean performGlobalAction(int action) {
synchronized (mLock) {
+ // We treat calls from a profile as if made by its parent as profiles
+ // share the accessibility state of the parent. The call below
+ // performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.getCallingUserId());
+ UserHandle.getCallingUserId());
if (resolvedUserId != mCurrentUserId) {
return false;
}
@@ -3407,16 +3468,35 @@
& AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
}
+ private int resolveProfileParentLocked(int userId) {
+ if (userId != mCurrentUserId) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ UserInfo parent = mUserManager.getProfileParent(userId);
+ if (parent != null) {
+ return parent.getUserHandle().getIdentifier();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ return userId;
+ }
+
public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) {
final int callingUid = Binder.getCallingUid();
if (callingUid == 0
|| callingUid == Process.SYSTEM_UID
|| callingUid == Process.SHELL_UID) {
- return mCurrentUserId;
+ if (userId == UserHandle.USER_CURRENT
+ || userId == UserHandle.USER_CURRENT_OR_SELF) {
+ return mCurrentUserId;
+ }
+ return resolveProfileParentLocked(userId);
}
final int callingUserId = UserHandle.getUserId(callingUid);
if (callingUserId == userId) {
- return userId;
+ return resolveProfileParentLocked(userId);
}
if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS)
&& !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) {
@@ -3618,17 +3698,8 @@
private final Uri mEnhancedWebAccessibilityUri = Settings.Secure
.getUriFor(Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION);
- private final Uri mDisplayContrastEnabledUri = Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED);
- private final Uri mDisplayContrastUri = Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST);
- private final Uri mDisplayBrightnessUri = Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_BRIGHTNESS);
-
private final Uri mDisplayInversionEnabledUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
- private final Uri mDisplayInversionUri = Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION);
private final Uri mDisplayDaltonizerEnabledUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED);
@@ -3654,16 +3725,8 @@
contentResolver.registerContentObserver(mEnhancedWebAccessibilityUri,
false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
- mDisplayContrastEnabledUri, false, this, UserHandle.USER_ALL);
- contentResolver.registerContentObserver(
- mDisplayContrastUri, false, this, UserHandle.USER_ALL);
- contentResolver.registerContentObserver(
- mDisplayBrightnessUri, false, this, UserHandle.USER_ALL);
- contentResolver.registerContentObserver(
mDisplayInversionEnabledUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
- mDisplayInversionUri, false, this, UserHandle.USER_ALL);
- contentResolver.registerContentObserver(
mDisplayDaltonizerEnabledUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
mDisplayDaltonizerUri, false, this, UserHandle.USER_ALL);
@@ -3673,8 +3736,10 @@
public void onChange(boolean selfChange, Uri uri) {
if (mAccessibilityEnabledUri.equals(uri)) {
synchronized (mLock) {
- // We will update when the automation service dies.
+ // Profiles share the accessibility state of the parent. Therefore,
+ // we are checking for changes only the parent settings.
UserState userState = getCurrentUserStateLocked();
+ // We will update when the automation service dies.
if (userState.mUiAutomationService == null) {
if (readAccessibilityEnabledSettingLocked(userState)) {
onUserStateChangedLocked(userState);
@@ -3683,8 +3748,10 @@
}
} else if (mTouchExplorationEnabledUri.equals(uri)) {
synchronized (mLock) {
- // We will update when the automation service dies.
+ // Profiles share the accessibility state of the parent. Therefore,
+ // we are checking for changes only the parent settings.
UserState userState = getCurrentUserStateLocked();
+ // We will update when the automation service dies.
if (userState.mUiAutomationService == null) {
if (readTouchExplorationEnabledSettingLocked(userState)) {
onUserStateChangedLocked(userState);
@@ -3693,8 +3760,10 @@
}
} else if (mDisplayMagnificationEnabledUri.equals(uri)) {
synchronized (mLock) {
- // We will update when the automation service dies.
+ // Profiles share the accessibility state of the parent. Therefore,
+ // we are checking for changes only the parent settings.
UserState userState = getCurrentUserStateLocked();
+ // We will update when the automation service dies.
if (userState.mUiAutomationService == null) {
if (readDisplayMagnificationEnabledSettingLocked(userState)) {
onUserStateChangedLocked(userState);
@@ -3703,8 +3772,10 @@
}
} else if (mEnabledAccessibilityServicesUri.equals(uri)) {
synchronized (mLock) {
- // We will update when the automation service dies.
+ // Profiles share the accessibility state of the parent. Therefore,
+ // we are checking for changes only the parent settings.
UserState userState = getCurrentUserStateLocked();
+ // We will update when the automation service dies.
if (userState.mUiAutomationService == null) {
if (readEnabledAccessibilityServicesLocked(userState)) {
onUserStateChangedLocked(userState);
@@ -3713,8 +3784,10 @@
}
} else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) {
synchronized (mLock) {
- // We will update when the automation service dies.
+ // Profiles share the accessibility state of the parent. Therefore,
+ // we are checking for changes only the parent settings.
UserState userState = getCurrentUserStateLocked();
+ // We will update when the automation service dies.
if (userState.mUiAutomationService == null) {
if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) {
onUserStateChangedLocked(userState);
@@ -3723,24 +3796,24 @@
}
} else if (mEnhancedWebAccessibilityUri.equals(uri)) {
synchronized (mLock) {
- // We will update when the automation service dies.
+ // Profiles share the accessibility state of the parent. Therefore,
+ // we are checking for changes only the parent settings.
UserState userState = getCurrentUserStateLocked();
+ // We will update when the automation service dies.
if (userState.mUiAutomationService == null) {
if (readEnhancedWebAccessibilityEnabledChangedLocked(userState)) {
onUserStateChangedLocked(userState);
}
}
}
- } else if (mDisplayContrastEnabledUri.equals(uri)
- || mDisplayInversionEnabledUri.equals(uri)
+ } else if (mDisplayInversionEnabledUri.equals(uri)
|| mDisplayDaltonizerEnabledUri.equals(uri)
- || mDisplayContrastUri.equals(uri)
- || mDisplayBrightnessUri.equals(uri)
- || mDisplayInversionUri.equals(uri)
|| mDisplayDaltonizerUri.equals(uri)) {
synchronized (mLock) {
- // We will update when the automation service dies.
+ // Profiles share the accessibility state of the parent. Therefore,
+ // we are checking for changes only the parent settings.
UserState userState = getCurrentUserStateLocked();
+ // We will update when the automation service dies.
if (userState.mUiAutomationService == null) {
if (readDisplayColorAdjustmentSettingsLocked(userState)) {
updateDisplayColorAdjustmentSettingsLocked(userState);
diff --git a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
index 52bdeda..394c196 100644
--- a/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/DisplayAdjustmentUtils.java
@@ -41,22 +41,6 @@
0, 0, 0, 1
};
- /** Matrix and offset used for standard display inversion. */
- private static final float[] INVERSION_MATRIX_STANDARD = new float[] {
- -1, 0, 0, 0,
- 0, -1, 0, 0,
- 0, 0, -1, 0,
- 1, 1, 1, 1
- };
-
- /** Matrix and offset used for hue-only display inversion. */
- private static final float[] INVERSION_MATRIX_HUE_ONLY = new float[] {
- 0, .5f, .5f, 0,
- .5f, 0, .5f, 0,
- .5f, .5f, 0, 0,
- 0, 0, 0, 1
- };
-
/** Matrix and offset used for value-only display inversion. */
private static final float[] INVERSION_MATRIX_VALUE_ONLY = new float[] {
0, -.5f, -.5f, 0,
@@ -65,15 +49,6 @@
1, 1, 1, 1
};
- /** Default contrast for display contrast enhancement. */
- private static final float DEFAULT_DISPLAY_CONTRAST = 2;
-
- /** Default brightness for display contrast enhancement. */
- private static final float DEFAULT_DISPLAY_BRIGHTNESS = 0;
-
- /** Default inversion mode for display color inversion. */
- private static final int DEFAULT_DISPLAY_INVERSION = AccessibilityManager.INVERSION_STANDARD;
-
/** Default inversion mode for display color correction. */
private static final int DEFAULT_DISPLAY_DALTONIZER =
AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY;
@@ -90,11 +65,6 @@
if (!hasColorTransform) {
hasColorTransform |= Settings.Secure.getIntForUser(
- cr, Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED, 0, userId) == 1;
- }
-
- if (!hasColorTransform) {
- hasColorTransform |= Settings.Secure.getIntForUser(
cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) == 1;
}
@@ -115,21 +85,7 @@
final boolean inversionEnabled = Settings.Secure.getIntForUser(
cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) == 1;
if (inversionEnabled) {
- final int inversionMode = Settings.Secure.getIntForUser(cr,
- Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION, DEFAULT_DISPLAY_INVERSION,
- userId);
- final float[] inversionMatrix;
- switch (inversionMode) {
- case AccessibilityManager.INVERSION_HUE_ONLY:
- inversionMatrix = INVERSION_MATRIX_HUE_ONLY;
- break;
- case AccessibilityManager.INVERSION_VALUE_ONLY:
- inversionMatrix = INVERSION_MATRIX_VALUE_ONLY;
- break;
- default:
- inversionMatrix = INVERSION_MATRIX_STANDARD;
- }
-
+ final float[] inversionMatrix = INVERSION_MATRIX_VALUE_ONLY;
Matrix.multiplyMM(outputMatrix, 0, colorMatrix, 0, inversionMatrix, 0);
colorMatrix = outputMatrix;
@@ -138,31 +94,6 @@
hasColorTransform = true;
}
- final boolean contrastEnabled = Settings.Secure.getIntForUser(
- cr, Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED, 0, userId) == 1;
- if (contrastEnabled) {
- final float contrast = Settings.Secure.getFloatForUser(cr,
- Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST, DEFAULT_DISPLAY_CONTRAST,
- userId);
- final float brightness = Settings.Secure.getFloatForUser(cr,
- Settings.Secure.ACCESSIBILITY_DISPLAY_BRIGHTNESS, DEFAULT_DISPLAY_BRIGHTNESS,
- userId);
- final float off = brightness * contrast - 0.5f * contrast + 0.5f;
- final float[] contrastMatrix = {
- contrast, 0, 0, 0,
- 0, contrast, 0, 0,
- 0, 0, contrast, 0,
- off, off, off, 1
- };
-
- Matrix.multiplyMM(outputMatrix, 0, colorMatrix, 0, contrastMatrix, 0);
-
- colorMatrix = outputMatrix;
- outputMatrix = colorMatrix;
-
- hasColorTransform = true;
- }
-
final boolean daltonizerEnabled = Settings.Secure.getIntForUser(
cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0;
if (daltonizerEnabled) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index dfffa8a..0708e55 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -20,15 +20,26 @@
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
+import static android.net.ConnectivityManager.NetworkCallbacks;
import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
import static android.net.ConnectivityManager.TYPE_DUMMY;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
+import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
+import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
+import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
+import static android.net.ConnectivityManager.TYPE_MOBILE_IMS;
+import static android.net.ConnectivityManager.TYPE_MOBILE_CBS;
+import static android.net.ConnectivityManager.TYPE_MOBILE_IA;
+import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
+import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIMAX;
import static android.net.ConnectivityManager.TYPE_PROXY;
import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.ConnectivityManager.isNetworkTypeValid;
+import static android.net.ConnectivityServiceProtocol.NetworkFactoryProtocol;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
@@ -65,10 +76,14 @@
import android.net.LinkProperties.CompareResult;
import android.net.LinkQualityInfo;
import android.net.MobileDataStateTracker;
+import android.net.Network;
+import android.net.NetworkAgent;
+import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkQuotaInfo;
+import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.NetworkStateTracker;
import android.net.NetworkUtils;
@@ -78,7 +93,6 @@
import android.net.RouteInfo;
import android.net.SamplingDataTracker;
import android.net.Uri;
-import android.net.wifi.WifiStateTracker;
import android.net.wimax.WimaxManagerConstants;
import android.os.AsyncTask;
import android.os.Binder;
@@ -118,11 +132,14 @@
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.util.AsyncChannel;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.DataConnectionStats;
import com.android.server.connectivity.Nat464Xlat;
+import com.android.server.connectivity.NetworkAgentInfo;
+import com.android.server.connectivity.NetworkMonitor;
import com.android.server.connectivity.PacManager;
import com.android.server.connectivity.Tethering;
import com.android.server.connectivity.Vpn;
@@ -165,6 +182,8 @@
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
+import static android.net.ConnectivityManager.INVALID_NET_ID;
+
/**
* @hide
*/
@@ -172,7 +191,7 @@
private static final String TAG = "ConnectivityService";
private static final boolean DBG = true;
- private static final boolean VDBG = false;
+ private static final boolean VDBG = true; // STOPSHIP
private static final boolean LOGD_RULES = false;
@@ -238,6 +257,17 @@
*/
private NetworkStateTracker mNetTrackers[];
+ /**
+ * Holds references to all NetworkAgentInfos claiming to support the legacy
+ * NetworkType. We used to have a static set of of NetworkStateTrackers
+ * for each network type. This is the new model.
+ * Supports synchronous inspection of state.
+ * These are built out at startup such that an unsupported network
+ * doesn't get an ArrayList instance, making this a tristate:
+ * unsupported, supported but not active and active.
+ */
+ private ArrayList<NetworkAgentInfo> mNetworkAgentInfoForType[];
+
/* Handles captive portal check on a network */
private CaptivePortalTracker mCaptivePortalTracker;
@@ -299,12 +329,6 @@
private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 2;
/**
- * used internally to change our network preference setting
- * arg1 = networkType to prefer
- */
- private static final int EVENT_SET_NETWORK_PREFERENCE = 3;
-
- /**
* used internally to synchronize inet condition reports
* arg1 = networkType
* arg2 = condition (0 bad, 100 good)
@@ -360,7 +384,7 @@
private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 14;
/**
- * user internally to indicate that data sampling interval is up
+ * used internally to indicate that data sampling interval is up
*/
private static final int EVENT_SAMPLE_INTERVAL_ELAPSED = 15;
@@ -369,10 +393,48 @@
*/
private static final int EVENT_PROXY_HAS_CHANGED = 16;
+ /**
+ * used internally when registering NetworkFactories
+ * obj = Messenger
+ */
+ private static final int EVENT_REGISTER_NETWORK_FACTORY = 17;
+
+ /**
+ * used internally when registering NetworkAgents
+ * obj = Messenger
+ */
+ private static final int EVENT_REGISTER_NETWORK_AGENT = 18;
+
+ /**
+ * used to add a network request
+ * includes a NetworkRequestInfo
+ */
+ private static final int EVENT_REGISTER_NETWORK_REQUEST = 19;
+
+ /**
+ * indicates a timeout period is over - check if we had a network yet or not
+ * and if not, call the timeout calback (but leave the request live until they
+ * cancel it.
+ * includes a NetworkRequestInfo
+ */
+ private static final int EVENT_TIMEOUT_NETWORK_REQUEST = 20;
+
+ /**
+ * used to add a network listener - no request
+ * includes a NetworkRequestInfo
+ */
+ private static final int EVENT_REGISTER_NETWORK_LISTENER = 21;
+
+ /**
+ * used to remove a network request, either a listener or a real request
+ * includes a NetworkRequest
+ */
+ private static final int EVENT_RELEASE_NETWORK_REQUEST = 22;
+
/** Handler used for internal events. */
- private InternalHandler mHandler;
+ final private InternalHandler mHandler;
/** Handler used for incoming {@link NetworkStateTracker} events. */
- private NetworkStateTrackerHandler mTrackerHandler;
+ final private NetworkStateTrackerHandler mTrackerHandler;
// list of DeathRecipients used to make sure features are turned off when
// a process dies
@@ -442,6 +504,10 @@
TelephonyManager mTelephonyManager;
+ private final static int MIN_NET_ID = 10; // some reserved marks
+ private final static int MAX_NET_ID = 65535;
+ private int mNextNetId = MIN_NET_ID;
+
public ConnectivityService(Context context, INetworkManagementService netd,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
// Currently, omitting a NetworkFactory will create one internally
@@ -454,6 +520,14 @@
NetworkFactory netFactory) {
if (DBG) log("ConnectivityService starting up");
+ NetworkCapabilities netCap = new NetworkCapabilities();
+ netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+ mDefaultRequest = new NetworkRequest(netCap, true);
+ NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(),
+ NetworkRequestInfo.REQUEST);
+ mNetworkRequests.put(mDefaultRequest, nri);
+
HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
handlerThread.start();
mHandler = new InternalHandler(handlerThread.getLooper());
@@ -505,6 +579,9 @@
mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
com.android.internal.R.integer.config_networkTransitionTimeout);
+ mNetworkAgentInfoForType = (ArrayList<NetworkAgentInfo>[])
+ new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1];
+
mNetTrackers = new NetworkStateTracker[
ConnectivityManager.MAX_NETWORK_TYPE+1];
mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1];
@@ -559,6 +636,8 @@
"radio " + n.radio + " in network type " + n.type);
continue;
}
+ mNetworkAgentInfoForType[n.type] = new ArrayList<NetworkAgentInfo>();
+
mNetConfigs[n.type] = n;
mNetworksDefined++;
} catch(Exception e) {
@@ -601,21 +680,6 @@
}
}
- // Update mNetworkPreference according to user mannually first then overlay config.xml
- mNetworkPreference = getPersistedNetworkPreference();
- if (mNetworkPreference == -1) {
- for (int n : mPriorityList) {
- if (mNetConfigs[n].isDefault() && ConnectivityManager.isNetworkTypeValid(n)) {
- mNetworkPreference = n;
- break;
- }
- }
- if (mNetworkPreference == -1) {
- throw new IllegalStateException(
- "You should set at least one default Network in config.xml!");
- }
- }
-
mNetRequestersPids =
(List<Integer> [])new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];
for (int i : mPriorityList) {
@@ -706,9 +770,19 @@
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
}
+ private synchronized int nextNetId() {
+ int netId = mNextNetId;
+ if (++mNextNetId > MAX_NET_ID) mNextNetId = MIN_NET_ID;
+ return netId;
+ }
+
/**
* Factory that creates {@link NetworkStateTracker} instances using given
* {@link NetworkConfig}.
+ *
+ * TODO - this is obsolete and will be deleted. It's replaced by the
+ * registerNetworkFactory call and protocol.
+ * @Deprecated in favor of registerNetworkFactory dynamic bindings
*/
public interface NetworkFactory {
public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config);
@@ -726,10 +800,6 @@
@Override
public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config) {
switch (config.radio) {
- case TYPE_WIFI:
- return new WifiStateTracker(targetNetworkType, config.name);
- case TYPE_MOBILE:
- return new MobileDataStateTracker(targetNetworkType, config.name);
case TYPE_DUMMY:
return new DummyDataStateTracker(targetNetworkType, config.name);
case TYPE_BLUETOOTH:
@@ -830,41 +900,6 @@
return wimaxStateTracker;
}
- /**
- * Sets the preferred network.
- * @param preference the new preference
- */
- public void setNetworkPreference(int preference) {
- enforceChangePermission();
-
- mHandler.sendMessage(
- mHandler.obtainMessage(EVENT_SET_NETWORK_PREFERENCE, preference, 0));
- }
-
- public int getNetworkPreference() {
- enforceAccessPermission();
- int preference;
- synchronized(this) {
- preference = mNetworkPreference;
- }
- return preference;
- }
-
- private void handleSetNetworkPreference(int preference) {
- if (ConnectivityManager.isNetworkTypeValid(preference) &&
- mNetConfigs[preference] != null &&
- mNetConfigs[preference].isDefault()) {
- if (mNetworkPreference != preference) {
- final ContentResolver cr = mContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.NETWORK_PREFERENCE, preference);
- synchronized(this) {
- mNetworkPreference = preference;
- }
- enforcePreference();
- }
- }
- }
-
private int getConnectivityChangeDelay() {
final ContentResolver cr = mContext.getContentResolver();
@@ -876,41 +911,6 @@
defaultDelay);
}
- private int getPersistedNetworkPreference() {
- final ContentResolver cr = mContext.getContentResolver();
-
- final int networkPrefSetting = Settings.Global
- .getInt(cr, Settings.Global.NETWORK_PREFERENCE, -1);
-
- return networkPrefSetting;
- }
-
- /**
- * Make the state of network connectivity conform to the preference settings
- * In this method, we only tear down a non-preferred network. Establishing
- * a connection to the preferred network is taken care of when we handle
- * the disconnect event from the non-preferred network
- * (see {@link #handleDisconnect(NetworkInfo)}).
- */
- private void enforcePreference() {
- if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected())
- return;
-
- if (!mNetTrackers[mNetworkPreference].isAvailable())
- return;
-
- for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) {
- if (t != mNetworkPreference && mNetTrackers[t] != null &&
- mNetTrackers[t].getNetworkInfo().isConnected()) {
- if (DBG) {
- log("tearing down " + mNetTrackers[t].getNetworkInfo() +
- " in enforcePreference");
- }
- teardown(mNetTrackers[t]);
- }
- }
- }
-
private boolean teardown(NetworkStateTracker netTracker) {
if (netTracker.teardown()) {
netTracker.setTeardownRequested(true);
@@ -924,11 +924,12 @@
* Check if UID should be blocked from using the network represented by the
* given {@link NetworkStateTracker}.
*/
- private boolean isNetworkBlocked(NetworkStateTracker tracker, int uid) {
- final String iface = tracker.getLinkProperties().getInterfaceName();
-
+ private boolean isNetworkBlocked(int networkType, int uid) {
final boolean networkCostly;
final int uidRules;
+
+ LinkProperties lp = getLinkPropertiesForType(networkType);
+ final String iface = (lp == null ? "" : lp.getInterfaceName());
synchronized (mRulesLock) {
networkCostly = mMeteredIfaces.contains(iface);
uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
@@ -945,11 +946,11 @@
/**
* Return a filtered {@link NetworkInfo}, potentially marked
* {@link DetailedState#BLOCKED} based on
- * {@link #isNetworkBlocked(NetworkStateTracker, int)}.
+ * {@link #isNetworkBlocked}.
*/
- private NetworkInfo getFilteredNetworkInfo(NetworkStateTracker tracker, int uid) {
- NetworkInfo info = tracker.getNetworkInfo();
- if (isNetworkBlocked(tracker, uid)) {
+ private NetworkInfo getFilteredNetworkInfo(int networkType, int uid) {
+ NetworkInfo info = getNetworkInfoForType(networkType);
+ if (isNetworkBlocked(networkType, uid)) {
// network is blocked; clone and override state
info = new NetworkInfo(info);
info.setDetailedState(DetailedState.BLOCKED, null, null);
@@ -974,6 +975,15 @@
return getNetworkInfo(mActiveDefaultNetwork, uid);
}
+ // only called when the default request is satisfied
+ private void updateActiveDefaultNetwork(NetworkAgentInfo nai) {
+ if (nai != null) {
+ mActiveDefaultNetwork = nai.networkInfo.getType();
+ } else {
+ mActiveDefaultNetwork = TYPE_NONE;
+ }
+ }
+
/**
* Find the first Provisioning network.
*
@@ -1016,10 +1026,7 @@
public NetworkInfo getActiveNetworkInfoUnfiltered() {
enforceAccessPermission();
if (isNetworkTypeValid(mActiveDefaultNetwork)) {
- final NetworkStateTracker tracker = mNetTrackers[mActiveDefaultNetwork];
- if (tracker != null) {
- return tracker.getNetworkInfo();
- }
+ return getNetworkInfoForType(mActiveDefaultNetwork);
}
return null;
}
@@ -1040,9 +1047,8 @@
private NetworkInfo getNetworkInfo(int networkType, int uid) {
NetworkInfo info = null;
if (isNetworkTypeValid(networkType)) {
- final NetworkStateTracker tracker = mNetTrackers[networkType];
- if (tracker != null) {
- info = getFilteredNetworkInfo(tracker, uid);
+ if (getNetworkInfoForType(networkType) != null) {
+ info = getFilteredNetworkInfo(networkType, uid);
}
}
return info;
@@ -1054,9 +1060,10 @@
final int uid = Binder.getCallingUid();
final ArrayList<NetworkInfo> result = Lists.newArrayList();
synchronized (mRulesLock) {
- for (NetworkStateTracker tracker : mNetTrackers) {
- if (tracker != null) {
- result.add(getFilteredNetworkInfo(tracker, uid));
+ for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE;
+ networkType++) {
+ if (getNetworkInfoForType(networkType) != null) {
+ result.add(getFilteredNetworkInfo(networkType, uid));
}
}
}
@@ -1066,7 +1073,7 @@
@Override
public boolean isNetworkSupported(int networkType) {
enforceAccessPermission();
- return (isNetworkTypeValid(networkType) && (mNetTrackers[networkType] != null));
+ return (isNetworkTypeValid(networkType) && (getNetworkInfoForType(networkType) != null));
}
/**
@@ -1079,32 +1086,48 @@
*/
@Override
public LinkProperties getActiveLinkProperties() {
- return getLinkProperties(mActiveDefaultNetwork);
+ return getLinkPropertiesForType(mActiveDefaultNetwork);
}
@Override
- public LinkProperties getLinkProperties(int networkType) {
+ public LinkProperties getLinkPropertiesForType(int networkType) {
enforceAccessPermission();
if (isNetworkTypeValid(networkType)) {
- final NetworkStateTracker tracker = mNetTrackers[networkType];
- if (tracker != null) {
- return tracker.getLinkProperties();
- }
+ return getLinkPropertiesForTypeInternal(networkType);
}
return null;
}
+ // TODO - this should be ALL networks
+ @Override
+ public LinkProperties getLinkProperties(Network network) {
+ enforceAccessPermission();
+ NetworkAgentInfo nai = mNetworkForNetId.get(network.netId);
+ if (nai != null) return new LinkProperties(nai.linkProperties);
+ return null;
+ }
+
+ @Override
+ public NetworkCapabilities getNetworkCapabilities(Network network) {
+ enforceAccessPermission();
+ NetworkAgentInfo nai = mNetworkForNetId.get(network.netId);
+ if (nai != null) return new NetworkCapabilities(nai.networkCapabilities);
+ return null;
+ }
+
@Override
public NetworkState[] getAllNetworkState() {
enforceAccessPermission();
final int uid = Binder.getCallingUid();
final ArrayList<NetworkState> result = Lists.newArrayList();
synchronized (mRulesLock) {
- for (NetworkStateTracker tracker : mNetTrackers) {
- if (tracker != null) {
- final NetworkInfo info = getFilteredNetworkInfo(tracker, uid);
- result.add(new NetworkState(
- info, tracker.getLinkProperties(), tracker.getLinkCapabilities()));
+ for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE;
+ networkType++) {
+ if (getNetworkInfoForType(networkType) != null) {
+ final NetworkInfo info = getFilteredNetworkInfo(networkType, uid);
+ final LinkProperties lp = getLinkPropertiesForTypeInternal(networkType);
+ final NetworkCapabilities netcap = getNetworkCapabilitiesForType(networkType);
+ result.add(new NetworkState(info, lp, netcap));
}
}
}
@@ -1113,10 +1136,11 @@
private NetworkState getNetworkStateUnchecked(int networkType) {
if (isNetworkTypeValid(networkType)) {
- final NetworkStateTracker tracker = mNetTrackers[networkType];
- if (tracker != null) {
- return new NetworkState(tracker.getNetworkInfo(), tracker.getLinkProperties(),
- tracker.getLinkCapabilities());
+ NetworkInfo info = getNetworkInfoForType(networkType);
+ if (info != null) {
+ return new NetworkState(info,
+ getLinkPropertiesForTypeInternal(networkType),
+ getNetworkCapabilitiesForType(networkType));
}
}
return null;
@@ -1163,24 +1187,6 @@
return false;
}
- public boolean setRadios(boolean turnOn) {
- boolean result = true;
- enforceChangePermission();
- for (NetworkStateTracker t : mNetTrackers) {
- if (t != null) result = t.setRadio(turnOn) && result;
- }
- return result;
- }
-
- public boolean setRadio(int netType, boolean turnOn) {
- enforceChangePermission();
- if (!ConnectivityManager.isNetworkTypeValid(netType)) {
- return false;
- }
- NetworkStateTracker tracker = mNetTrackers[netType];
- return tracker != null && tracker.setRadio(turnOn);
- }
-
private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() {
@Override
public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos) {
@@ -1662,7 +1668,7 @@
final long token = Binder.clearCallingIdentity();
try {
LinkProperties lp = tracker.getLinkProperties();
- boolean ok = addRouteToAddress(lp, addr, exempt);
+ boolean ok = addRouteToAddress(lp, addr, exempt, tracker.getNetwork().netId);
if (DBG) log("requestRouteToHostAddress ok=" + ok);
return ok;
} finally {
@@ -1671,24 +1677,25 @@
}
private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable,
- boolean exempt) {
- return modifyRoute(p, r, 0, ADD, toDefaultTable, exempt);
+ boolean exempt, int netId) {
+ return modifyRoute(p, r, 0, ADD, toDefaultTable, exempt, netId);
}
- private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
- return modifyRoute(p, r, 0, REMOVE, toDefaultTable, UNEXEMPT);
+ private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable, int netId) {
+ return modifyRoute(p, r, 0, REMOVE, toDefaultTable, UNEXEMPT, netId);
}
- private boolean addRouteToAddress(LinkProperties lp, InetAddress addr, boolean exempt) {
- return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt);
+ private boolean addRouteToAddress(LinkProperties lp, InetAddress addr, boolean exempt,
+ int netId) {
+ return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt, netId);
}
- private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) {
- return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE, UNEXEMPT);
+ private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr, int netId) {
+ return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE, UNEXEMPT, netId);
}
private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd,
- boolean toDefaultTable, boolean exempt) {
+ boolean toDefaultTable, boolean exempt, int netId) {
RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr);
if (bestRoute == null) {
bestRoute = RouteInfo.makeHostRoute(addr, lp.getInterfaceName());
@@ -1703,11 +1710,11 @@
bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface);
}
}
- return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable, exempt);
+ return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable, exempt, netId);
}
private boolean modifyRoute(LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd,
- boolean toDefaultTable, boolean exempt) {
+ boolean toDefaultTable, boolean exempt, int netId) {
if ((lp == null) || (r == null)) {
if (DBG) log("modifyRoute got unexpected null: " + lp + ", " + r);
return false;
@@ -1736,7 +1743,7 @@
bestRoute.getGateway(),
ifaceName);
}
- modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt);
+ modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt, netId);
}
}
if (doAdd) {
@@ -1746,7 +1753,7 @@
synchronized (mRoutesLock) {
// only track default table - only one apps can effect
mAddedRoutes.add(r);
- mNetd.addRoute(ifaceName, r);
+ mNetd.addRoute(netId, r);
if (exempt) {
LinkAddress dest = r.getDestination();
if (!mExemptAddresses.contains(dest)) {
@@ -1756,7 +1763,7 @@
}
}
} else {
- mNetd.addSecondaryRoute(ifaceName, r);
+ mNetd.addRoute(netId, r);
}
} catch (Exception e) {
// never crash - catch them all
@@ -1772,7 +1779,7 @@
if (mAddedRoutes.contains(r) == false) {
if (VDBG) log("Removing " + r + " for interface " + ifaceName);
try {
- mNetd.removeRoute(ifaceName, r);
+ mNetd.removeRoute(netId, r);
LinkAddress dest = r.getDestination();
if (mExemptAddresses.contains(dest)) {
mNetd.clearHostExemption(dest);
@@ -1790,7 +1797,7 @@
} else {
if (VDBG) log("Removing " + r + " for interface " + ifaceName);
try {
- mNetd.removeSecondaryRoute(ifaceName, r);
+ mNetd.removeRoute(netId, r);
} catch (Exception e) {
// never crash - catch them all
if (VDBG) loge("Exception trying to remove a route: " + e);
@@ -1899,18 +1906,8 @@
}
private void handleSetMobileData(boolean enabled) {
- if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
- if (VDBG) {
- log(mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
- }
- mNetTrackers[ConnectivityManager.TYPE_MOBILE].setUserDataEnable(enabled);
- }
- if (mNetTrackers[ConnectivityManager.TYPE_WIMAX] != null) {
- if (VDBG) {
- log(mNetTrackers[ConnectivityManager.TYPE_WIMAX].toString() + enabled);
- }
- mNetTrackers[ConnectivityManager.TYPE_WIMAX].setUserDataEnable(enabled);
- }
+ // TODO - handle this - probably generalize passing in a transport type and send to the
+ // factories?
}
@Override
@@ -1923,12 +1920,13 @@
}
private void handleSetPolicyDataEnable(int networkType, boolean enabled) {
- if (isNetworkTypeValid(networkType)) {
- final NetworkStateTracker tracker = mNetTrackers[networkType];
- if (tracker != null) {
- tracker.setPolicyDataEnable(enabled);
- }
- }
+ // TODO - handle this passing to factories
+// if (isNetworkTypeValid(networkType)) {
+// final NetworkStateTracker tracker = mNetTrackers[networkType];
+// if (tracker != null) {
+// tracker.setPolicyDataEnable(enabled);
+// }
+// }
}
private void enforceAccessPermission() {
@@ -1984,11 +1982,13 @@
int prevNetType = info.getType();
mNetTrackers[prevNetType].setTeardownRequested(false);
+ int thisNetId = mNetTrackers[prevNetType].getNetwork().netId;
// Remove idletimer previously setup in {@code handleConnect}
- if (mNetConfigs[prevNetType].isDefault()) {
- removeDataActivityTracking(prevNetType);
- }
+// Already in place in new function. This is dead code.
+// if (mNetConfigs[prevNetType].isDefault()) {
+// removeDataActivityTracking(prevNetType);
+// }
/*
* If the disconnected network is not the active one, then don't report
@@ -2055,7 +2055,8 @@
}
// do this before we broadcast the change
- handleConnectivityChange(prevNetType, doReset);
+// Already done in new function. This is dead code.
+// handleConnectivityChange(prevNetType, doReset);
final Intent immediateIntent = new Intent(intent);
immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
@@ -2069,6 +2070,13 @@
sendConnectedBroadcastDelayed(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(),
getConnectivityChangeDelay());
}
+ try {
+// mNetd.removeNetwork(thisNetId);
+ } catch (Exception e) {
+ loge("Exception removing network: " + e);
+ } finally {
+ mNetTrackers[prevNetType].setNetId(INVALID_NET_ID);
+ }
}
private void tryFailover(int prevNetType) {
@@ -2083,6 +2091,11 @@
log("tryFailover: set mActiveDefaultNetwork=-1, prevNetType=" + prevNetType);
}
mActiveDefaultNetwork = -1;
+ try {
+ mNetd.clearDefaultNetId();
+ } catch (Exception e) {
+ loge("Exception clearing default network :" + e);
+ }
}
// don't signal a reconnect for anything lower or equal priority than our
@@ -2183,67 +2196,6 @@
}
}
- /**
- * Called when an attempt to fail over to another network has failed.
- * @param info the {@link NetworkInfo} for the failed network
- */
- private void handleConnectionFailure(NetworkInfo info) {
- mNetTrackers[info.getType()].setTeardownRequested(false);
-
- String reason = info.getReason();
- String extraInfo = info.getExtraInfo();
-
- String reasonText;
- if (reason == null) {
- reasonText = ".";
- } else {
- reasonText = " (" + reason + ").";
- }
- loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
-
- Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info));
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
- if (getActiveNetworkInfo() == null) {
- intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
- }
- if (reason != null) {
- intent.putExtra(ConnectivityManager.EXTRA_REASON, reason);
- }
- if (extraInfo != null) {
- intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo);
- }
- if (info.isFailover()) {
- intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
- info.setFailover(false);
- }
-
- if (mNetConfigs[info.getType()].isDefault()) {
- tryFailover(info.getType());
- if (mActiveDefaultNetwork != -1) {
- NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
- intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
- } else {
- mDefaultInetConditionPublished = 0;
- intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
- }
- }
-
- intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
-
- final Intent immediateIntent = new Intent(intent);
- immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
- sendStickyBroadcast(immediateIntent);
- sendStickyBroadcast(intent);
- /*
- * If the failover network is already connected, then immediately send
- * out a followup broadcast indicating successful failover
- */
- if (mActiveDefaultNetwork != -1) {
- sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
- }
- }
-
private void sendStickyBroadcast(Intent intent) {
synchronized(this) {
if (!mSystemReady) {
@@ -2336,17 +2288,23 @@
if (mNetConfigs[newNetType].isDefault()) {
if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != newNetType) {
if (isNewNetTypePreferredOverCurrentNetType(newNetType)) {
- // tear down the other
- NetworkStateTracker otherNet =
- mNetTrackers[mActiveDefaultNetwork];
- if (DBG) {
- log("Policy requires " + otherNet.getNetworkInfo().getTypeName() +
- " teardown");
- }
- if (!teardown(otherNet)) {
- loge("Network declined teardown request");
- teardown(thisNet);
- return;
+ String teardownPolicy = SystemProperties.get("net.teardownPolicy");
+ if (TextUtils.equals(teardownPolicy, "keep") == false) {
+ // tear down the other
+ NetworkStateTracker otherNet =
+ mNetTrackers[mActiveDefaultNetwork];
+ if (DBG) {
+ log("Policy requires " + otherNet.getNetworkInfo().getTypeName() +
+ " teardown");
+ }
+ if (!teardown(otherNet)) {
+ loge("Network declined teardown request");
+ teardown(thisNet);
+ return;
+ }
+ } else {
+ //TODO - remove
+ loge("network teardown skipped due to net.teardownPolicy setting");
}
} else {
// don't accept this one
@@ -2358,7 +2316,17 @@
return;
}
}
- setupDataActivityTracking(newNetType);
+ int thisNetId = nextNetId();
+ thisNet.setNetId(thisNetId);
+ try {
+// mNetd.createNetwork(thisNetId, thisIface);
+ } catch (Exception e) {
+ loge("Exception creating network :" + e);
+ teardown(thisNet);
+ return;
+ }
+// Already in place in new function. This is dead code.
+// setupDataActivityTracking(newNetType);
synchronized (ConnectivityService.this) {
// have a new default network, release the transition wakelock in a second
// if it's held. The second pause is to allow apps to reconnect over the
@@ -2371,6 +2339,11 @@
}
}
mActiveDefaultNetwork = newNetType;
+ try {
+ mNetd.setDefaultNetId(thisNetId);
+ } catch (Exception e) {
+ loge("Exception setting default network :" + e);
+ }
// this will cause us to come up initially as unconnected and switching
// to connected after our normal pause unless somebody reports us as reall
// disconnected
@@ -2380,10 +2353,21 @@
// Don't do this - if we never sign in stay, grey
//reportNetworkCondition(mActiveDefaultNetwork, 100);
updateNetworkSettings(thisNet);
+ } else {
+ int thisNetId = nextNetId();
+ thisNet.setNetId(thisNetId);
+ try {
+// mNetd.createNetwork(thisNetId, thisIface);
+ } catch (Exception e) {
+ loge("Exception creating network :" + e);
+ teardown(thisNet);
+ return;
+ }
}
thisNet.setTeardownRequested(false);
- updateMtuSizeSettings(thisNet);
- handleConnectivityChange(newNetType, false);
+// Already in place in new function. This is dead code.
+// updateMtuSizeSettings(thisNet);
+// handleConnectivityChange(newNetType, false);
sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
// notify battery stats service about this network
@@ -2401,37 +2385,39 @@
public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) {
enforceConnectivityInternalPermission();
if (DBG) log("captivePortalCheckCompleted: ni=" + info + " captive=" + isCaptivePortal);
- mNetTrackers[info.getType()].captivePortalCheckCompleted(isCaptivePortal);
+// mNetTrackers[info.getType()].captivePortalCheckCompleted(isCaptivePortal);
}
/**
- * Setup data activity tracking for the given network interface.
+ * Setup data activity tracking for the given network.
*
* Every {@code setupDataActivityTracking} should be paired with a
* {@link #removeDataActivityTracking} for cleanup.
*/
- private void setupDataActivityTracking(int type) {
- final NetworkStateTracker thisNet = mNetTrackers[type];
- final String iface = thisNet.getLinkProperties().getInterfaceName();
+ private void setupDataActivityTracking(NetworkAgentInfo networkAgent) {
+ final String iface = networkAgent.linkProperties.getInterfaceName();
final int timeout;
+ int type = ConnectivityManager.TYPE_NONE;
- if (ConnectivityManager.isNetworkTypeMobile(type)) {
+ if (networkAgent.networkCapabilities.hasTransport(
+ NetworkCapabilities.TRANSPORT_CELLULAR)) {
timeout = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
5);
- // Canonicalize mobile network type
type = ConnectivityManager.TYPE_MOBILE;
- } else if (ConnectivityManager.TYPE_WIFI == type) {
+ } else if (networkAgent.networkCapabilities.hasTransport(
+ NetworkCapabilities.TRANSPORT_WIFI)) {
timeout = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
0);
+ type = ConnectivityManager.TYPE_WIFI;
} else {
// do not track any other networks
timeout = 0;
}
- if (timeout > 0 && iface != null) {
+ if (timeout > 0 && iface != null && type != ConnectivityManager.TYPE_NONE) {
try {
mNetd.addIdleTimer(iface, timeout, type);
} catch (Exception e) {
@@ -2444,12 +2430,12 @@
/**
* Remove data activity tracking when network disconnects.
*/
- private void removeDataActivityTracking(int type) {
- final NetworkStateTracker net = mNetTrackers[type];
- final String iface = net.getLinkProperties().getInterfaceName();
+ private void removeDataActivityTracking(NetworkAgentInfo networkAgent) {
+ final String iface = networkAgent.linkProperties.getInterfaceName();
+ final NetworkCapabilities caps = networkAgent.networkCapabilities;
- if (iface != null && (ConnectivityManager.isNetworkTypeMobile(type) ||
- ConnectivityManager.TYPE_WIFI == type)) {
+ if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
+ caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) {
try {
// the call fails silently if no idletimer setup for this interface
mNetd.removeIdleTimer(iface);
@@ -2464,8 +2450,10 @@
* concerned with making sure that the list of DNS servers is set up
* according to which networks are connected, and ensuring that the
* right routing table entries exist.
+ *
+ * TODO - delete when we're sure all this functionallity is captured.
*/
- private void handleConnectivityChange(int netType, boolean doReset) {
+ private void handleConnectivityChange(int netType, LinkProperties curLp, boolean doReset) {
int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
boolean exempt = ConnectivityManager.isNetworkTypeExempt(netType);
if (VDBG) {
@@ -2479,7 +2467,6 @@
*/
handleDnsConfigurationChange(netType);
- LinkProperties curLp = mCurrentLinkProperties[netType];
LinkProperties newLp = null;
if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
@@ -2536,7 +2523,8 @@
}
}
mCurrentLinkProperties[netType] = newLp;
- boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt);
+ boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt,
+ mNetTrackers[netType].getNetwork().netId);
if (resetMask != 0 || resetDns) {
if (VDBG) log("handleConnectivityChange: resetting");
@@ -2558,40 +2546,20 @@
}
}
}
- if (resetDns) {
- flushVmDnsCache();
- if (VDBG) log("resetting DNS cache for " + iface);
- try {
- mNetd.flushInterfaceDnsCache(iface);
- } catch (Exception e) {
- // never crash - catch them all
- if (DBG) loge("Exception resetting dns cache: " + e);
- }
- }
} else {
loge("Can't reset connection for type "+netType);
}
}
- }
- }
-
- // Update 464xlat state.
- NetworkStateTracker tracker = mNetTrackers[netType];
- if (mClat.requiresClat(netType, tracker)) {
-
- // If the connection was previously using clat, but is not using it now, stop the clat
- // daemon. Normally, this happens automatically when the connection disconnects, but if
- // the disconnect is not reported, or if the connection's LinkProperties changed for
- // some other reason (e.g., handoff changes the IP addresses on the link), it would
- // still be running. If it's not running, then stopping it is a no-op.
- if (Nat464Xlat.isRunningClat(curLp) && !Nat464Xlat.isRunningClat(newLp)) {
- mClat.stopClat();
- }
- // If the link requires clat to be running, then start the daemon now.
- if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
- mClat.startClat(tracker);
- } else {
- mClat.stopClat();
+ if (resetDns) {
+ flushVmDnsCache();
+ if (VDBG) log("resetting DNS cache for type " + netType);
+ try {
+ mNetd.flushNetworkDnsCache(mNetTrackers[netType].getNetwork().netId);
+ } catch (Exception e) {
+ // never crash - catch them all
+ if (DBG) loge("Exception resetting dns cache: " + e);
+ }
+ }
}
}
@@ -2615,7 +2583,7 @@
* returns a boolean indicating the routes changed
*/
private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp,
- boolean isLinkDefault, boolean exempt) {
+ boolean isLinkDefault, boolean exempt, int netId) {
Collection<RouteInfo> routesToAdd = null;
CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>();
CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
@@ -2633,45 +2601,20 @@
for (RouteInfo r : routeDiff.removed) {
if (isLinkDefault || ! r.isDefaultRoute()) {
if (VDBG) log("updateRoutes: default remove route r=" + r);
- removeRoute(curLp, r, TO_DEFAULT_TABLE);
+ removeRoute(curLp, r, TO_DEFAULT_TABLE, netId);
}
if (isLinkDefault == false) {
// remove from a secondary route table
- removeRoute(curLp, r, TO_SECONDARY_TABLE);
- }
- }
-
- if (!isLinkDefault) {
- // handle DNS routes
- if (routesChanged) {
- // routes changed - remove all old dns entries and add new
- if (curLp != null) {
- for (InetAddress oldDns : curLp.getDnses()) {
- removeRouteToAddress(curLp, oldDns);
- }
- }
- if (newLp != null) {
- for (InetAddress newDns : newLp.getDnses()) {
- addRouteToAddress(newLp, newDns, exempt);
- }
- }
- } else {
- // no change in routes, check for change in dns themselves
- for (InetAddress oldDns : dnsDiff.removed) {
- removeRouteToAddress(curLp, oldDns);
- }
- for (InetAddress newDns : dnsDiff.added) {
- addRouteToAddress(newLp, newDns, exempt);
- }
+ removeRoute(curLp, r, TO_SECONDARY_TABLE, netId);
}
}
for (RouteInfo r : routeDiff.added) {
if (isLinkDefault || ! r.isDefaultRoute()) {
- addRoute(newLp, r, TO_DEFAULT_TABLE, exempt);
+ addRoute(newLp, r, TO_DEFAULT_TABLE, exempt, netId);
} else {
// add to a secondary route table
- addRoute(newLp, r, TO_SECONDARY_TABLE, UNEXEMPT);
+ addRoute(newLp, r, TO_SECONDARY_TABLE, UNEXEMPT, netId);
// many radios add a default route even when we don't want one.
// remove the default route unless somebody else has asked for it
@@ -2680,7 +2623,7 @@
if (!TextUtils.isEmpty(ifaceName) && !mAddedRoutes.contains(r)) {
if (VDBG) log("Removing " + r + " for interface " + ifaceName);
try {
- mNetd.removeRoute(ifaceName, r);
+ mNetd.removeRoute(netId, r);
} catch (Exception e) {
// never crash - catch them all
if (DBG) loge("Exception trying to remove a route: " + e);
@@ -2693,26 +2636,30 @@
return routesChanged;
}
- /**
+ /**
* Reads the network specific MTU size from reources.
* and set it on it's iface.
*/
- private void updateMtuSizeSettings(NetworkStateTracker nt) {
- final String iface = nt.getLinkProperties().getInterfaceName();
- final int mtu = nt.getLinkProperties().getMtu();
+ private void updateMtu(LinkProperties newLp, LinkProperties oldLp) {
+ final String iface = newLp.getInterfaceName();
+ final int mtu = newLp.getMtu();
+ if (oldLp != null && newLp.isIdenticalMtu(oldLp)) {
+ if (VDBG) log("identical MTU - not setting");
+ return;
+ }
- if (mtu < 68 || mtu > 10000) {
- loge("Unexpected mtu value: " + mtu + ", " + nt);
- return;
- }
+ if (mtu < 68 || mtu > 10000) {
+ loge("Unexpected mtu value: " + mtu + ", " + iface);
+ return;
+ }
- try {
- if (VDBG) log("Setting MTU size: " + iface + ", " + mtu);
- mNetd.setMtu(iface, mtu);
- } catch (Exception e) {
- Slog.e(TAG, "exception in setMtu()" + e);
- }
- }
+ try {
+ if (VDBG) log("Setting MTU size: " + iface + ", " + mtu);
+ mNetd.setMtu(iface, mtu);
+ } catch (Exception e) {
+ Slog.e(TAG, "exception in setMtu()" + e);
+ }
+ }
/**
* Reads the network specific TCP buffer sizes from SystemProperties
@@ -2797,7 +2744,8 @@
if (p == null) continue;
if (mNetRequestersPids[i].contains(myPid)) {
try {
- mNetd.setDnsInterfaceForPid(p.getInterfaceName(), pid);
+ // TODO: Reimplement this via local variable in bionic.
+ // mNetd.setDnsNetworkForPid(nt.getNetwork().netId, pid);
} catch (Exception e) {
Slog.e(TAG, "exception reasseses pid dns: " + e);
}
@@ -2807,7 +2755,8 @@
}
// nothing found - delete
try {
- mNetd.clearDnsInterfaceForPid(pid);
+ // TODO: Reimplement this via local variable in bionic.
+ // mNetd.clearDnsNetworkForPid(pid);
} catch (Exception e) {
Slog.e(TAG, "exception clear interface from pid: " + e);
}
@@ -2832,8 +2781,8 @@
}
// Caller must grab mDnsLock.
- private void updateDnsLocked(String network, String iface,
- Collection<InetAddress> dnses, String domains, boolean defaultDns) {
+ private void updateDnsLocked(String network, int netId,
+ Collection<InetAddress> dnses, String domains) {
int last = 0;
if (dnses.size() == 0 && mDefaultDns != null) {
dnses = new ArrayList();
@@ -2844,10 +2793,7 @@
}
try {
- mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains);
- if (defaultDns) {
- mNetd.setDefaultInterfaceForDns(iface);
- }
+ mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses), domains);
for (InetAddress dns : dnses) {
++last;
@@ -2872,14 +2818,15 @@
LinkProperties p = nt.getLinkProperties();
if (p == null) return;
Collection<InetAddress> dnses = p.getDnses();
+ int netId = nt.getNetwork().netId;
if (mNetConfigs[netType].isDefault()) {
String network = nt.getNetworkInfo().getTypeName();
synchronized (mDnsLock) {
- updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains(), true);
+ updateDnsLocked(network, netId, dnses, p.getDomains());
}
} else {
try {
- mNetd.setDnsServersForInterface(p.getInterfaceName(),
+ mNetd.setDnsServersForNetwork(netId,
NetworkUtils.makeStrings(dnses), p.getDomains());
} catch (Exception e) {
if (DBG) loge("exception setting dns servers: " + e);
@@ -2888,7 +2835,8 @@
List<Integer> pids = mNetRequestersPids[netType];
for (Integer pid : pids) {
try {
- mNetd.setDnsInterfaceForPid(p.getInterfaceName(), pid);
+ // TODO: Reimplement this via local variable in bionic.
+ // mNetd.setDnsNetworkForPid(netId, pid);
} catch (Exception e) {
Slog.e(TAG, "exception setting interface for pid: " + e);
}
@@ -2930,44 +2878,39 @@
return;
}
- // TODO: add locking to get atomic snapshot
- pw.println();
- for (int i = 0; i < mNetTrackers.length; i++) {
- final NetworkStateTracker nst = mNetTrackers[i];
- if (nst != null) {
- pw.println("NetworkStateTracker for " + getNetworkTypeName(i) + ":");
- pw.increaseIndent();
- if (nst.getNetworkInfo().isConnected()) {
- pw.println("Active network: " + nst.getNetworkInfo().
- getTypeName());
- }
- pw.println(nst.getNetworkInfo());
- pw.println(nst.getLinkProperties());
- pw.println(nst);
- pw.println();
- pw.decreaseIndent();
- }
+ NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId);
+ pw.print("Active default network: ");
+ if (defaultNai == null) {
+ pw.println("none");
+ } else {
+ pw.println(defaultNai.network.netId);
}
-
- pw.print("Active default network: "); pw.println(getNetworkTypeName(mActiveDefaultNetwork));
pw.println();
- pw.println("Network Requester Pids:");
+ pw.println("Current Networks:");
pw.increaseIndent();
- for (int net : mPriorityList) {
- String pidString = net + ": ";
- for (Integer pid : mNetRequestersPids[net]) {
- pidString = pidString + pid.toString() + ", ";
+ for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ pw.println(nai.toString());
+ pw.increaseIndent();
+ pw.println("Requests:");
+ pw.increaseIndent();
+ for (int i = 0; i < nai.networkRequests.size(); i++) {
+ pw.println(nai.networkRequests.valueAt(i).toString());
}
- pw.println(pidString);
+ pw.decreaseIndent();
+ pw.println("Lingered:");
+ pw.increaseIndent();
+ for (NetworkRequest nr : nai.networkLingered) pw.println(nr.toString());
+ pw.decreaseIndent();
+ pw.decreaseIndent();
}
- pw.println();
pw.decreaseIndent();
+ pw.println();
- pw.println("FeatureUsers:");
+ pw.println("Network Requests:");
pw.increaseIndent();
- for (Object requester : mFeatureUsers) {
- pw.println(requester.toString());
+ for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+ pw.println(nri.toString());
}
pw.println();
pw.decreaseIndent();
@@ -3002,6 +2945,59 @@
public void handleMessage(Message msg) {
NetworkInfo info;
switch (msg.what) {
+ case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
+ handleAsyncChannelHalfConnect(msg);
+ break;
+ }
+ case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
+ NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
+ if (nai != null) nai.asyncChannel.disconnect();
+ break;
+ }
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+ handleAsyncChannelDisconnected(msg);
+ break;
+ }
+ case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
+ NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
+ if (nai == null) {
+ loge("EVENT_NETWORK_CAPABILITIES_CHANGED from unknown NetworkAgent");
+ } else {
+ updateCapabilities(nai, (NetworkCapabilities)msg.obj);
+ }
+ break;
+ }
+ case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: {
+ NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
+ if (nai == null) {
+ loge("NetworkAgent not found for EVENT_NETWORK_PROPERTIES_CHANGED");
+ } else {
+ LinkProperties oldLp = nai.linkProperties;
+ nai.linkProperties = (LinkProperties)msg.obj;
+ updateLinkProperties(nai, oldLp);
+ }
+ break;
+ }
+ case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {
+ NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
+ if (nai == null) {
+ loge("EVENT_NETWORK_INFO_CHANGED from unknown NetworkAgent");
+ break;
+ }
+ info = (NetworkInfo) msg.obj;
+ updateNetworkInfo(nai, info);
+ break;
+ }
+ case NetworkMonitor.EVENT_NETWORK_VALIDATED: {
+ NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
+ handleConnectionValidated(nai);
+ break;
+ }
+ case NetworkMonitor.EVENT_NETWORK_LINGER_COMPLETE: {
+ NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj;
+ handleLingerComplete(nai);
+ break;
+ }
case NetworkStateTracker.EVENT_STATE_CHANGED: {
info = (NetworkInfo) msg.obj;
NetworkInfo.State state = info.getState();
@@ -3034,10 +3030,7 @@
EventLogTags.writeConnectivityStateChanged(
info.getType(), info.getSubtype(), info.getDetailedState().ordinal());
- if (info.getDetailedState() ==
- NetworkInfo.DetailedState.FAILED) {
- handleConnectionFailure(info);
- } else if (info.isConnectedToProvisioningNetwork()) {
+ if (info.isConnectedToProvisioningNetwork()) {
/**
* TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING
* for now its an in between network, its a network that
@@ -3048,7 +3041,7 @@
* to the link that may have incorrectly setup by the lower
* levels.
*/
- LinkProperties lp = getLinkProperties(info.getType());
+ LinkProperties lp = getLinkPropertiesForTypeInternal(info.getType());
if (DBG) {
log("EVENT_STATE_CHANGED: connected to provisioning network, lp=" + lp);
}
@@ -3058,21 +3051,13 @@
// connection will fail until the provisioning network
// is enabled.
for (RouteInfo r : lp.getRoutes()) {
- removeRoute(lp, r, TO_DEFAULT_TABLE);
+ removeRoute(lp, r, TO_DEFAULT_TABLE,
+ mNetTrackers[info.getType()].getNetwork().netId);
}
} else if (state == NetworkInfo.State.DISCONNECTED) {
- handleDisconnect(info);
} else if (state == NetworkInfo.State.SUSPENDED) {
- // TODO: need to think this over.
- // the logic here is, handle SUSPENDED the same as
- // DISCONNECTED. The only difference being we are
- // broadcasting an intent with NetworkInfo that's
- // suspended. This allows the applications an
- // opportunity to handle DISCONNECTED and SUSPENDED
- // differently, or not.
- handleDisconnect(info);
} else if (state == NetworkInfo.State.CONNECTED) {
- handleConnect(info);
+ // handleConnect(info);
}
if (mLockdownTracker != null) {
mLockdownTracker.onNetworkInfoChanged(info);
@@ -3084,7 +3069,8 @@
// TODO: Temporary allowing network configuration
// change not resetting sockets.
// @see bug/4455071
- handleConnectivityChange(info.getType(), false);
+ handleConnectivityChange(info.getType(), mCurrentLinkProperties[info.getType()],
+ false);
break;
}
case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: {
@@ -3097,6 +3083,173 @@
}
}
+ private void handleAsyncChannelHalfConnect(Message msg) {
+ AsyncChannel ac = (AsyncChannel) msg.obj;
+ if (mNetworkFactories.contains(ac)) {
+ if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+ if (VDBG) log("NetworkFactory connected");
+ // A network factory has connected. Send it all current NetworkRequests.
+ for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+ NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
+ ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK,
+ (nai != null ? nai.currentScore : 0), 0, nri.request);
+ }
+ } else {
+ loge("Error connecting NetworkFactory");
+ mNetworkFactories.remove(ac);
+ }
+ } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {
+ if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+ if (VDBG) log("NetworkAgent connected");
+ // A network agent has requested a connection. Establish the connection.
+ mNetworkAgentInfos.get(msg.replyTo).asyncChannel.
+ sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+ } else {
+ loge("Error connecting NetworkAgent");
+ NetworkAgentInfo nai = mNetworkAgentInfos.remove(msg.replyTo);
+ try {
+ mNetworkAgentInfoForType[nai.networkInfo.getType()].remove(nai);
+ } catch (NullPointerException e) {}
+ if (nai != null) {
+ mNetworkForNetId.remove(nai.network.netId);
+ }
+ }
+ }
+ }
+ private void handleAsyncChannelDisconnected(Message msg) {
+ NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
+ if (nai != null) {
+ if (DBG) {
+ log(nai.name() + " got DISCONNECTED, was satisfying " + nai.networkRequests.size());
+ }
+ // A network agent has disconnected.
+ // Tell netd to clean up the configuration for this network
+ // (routing rules, DNS, etc).
+ try {
+ mNetd.removeNetwork(nai.network.netId);
+ } catch (Exception e) {
+ loge("Exception removing network: " + e);
+ }
+ notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
+ nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
+ mNetworkAgentInfos.remove(msg.replyTo);
+ updateClat(null, nai.linkProperties, nai);
+ try {
+ mNetworkAgentInfoForType[nai.networkInfo.getType()].remove(nai);
+ } catch (NullPointerException e) {}
+
+ mNetworkForNetId.remove(nai.network.netId);
+ // Since we've lost the network, go through all the requests that
+ // it was satisfying and see if any other factory can satisfy them.
+ final ArrayList<NetworkAgentInfo> toActivate = new ArrayList<NetworkAgentInfo>();
+ for (int i = 0; i < nai.networkRequests.size(); i++) {
+ NetworkRequest request = nai.networkRequests.valueAt(i);
+ NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId);
+ if (VDBG) {
+ log(" checking request " + request + ", currentNetwork = " +
+ currentNetwork != null ? currentNetwork.name() : "null");
+ }
+ if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
+ mNetworkForRequestId.remove(request.requestId);
+ sendUpdatedScoreToFactories(request, 0);
+ NetworkAgentInfo alternative = null;
+ for (Map.Entry entry : mNetworkAgentInfos.entrySet()) {
+ NetworkAgentInfo existing = (NetworkAgentInfo)entry.getValue();
+ if (existing.networkInfo.isConnected() &&
+ request.networkCapabilities.satisfiedByNetworkCapabilities(
+ existing.networkCapabilities) &&
+ (alternative == null ||
+ alternative.currentScore < existing.currentScore)) {
+ alternative = existing;
+ }
+ }
+ if (alternative != null && !toActivate.contains(alternative)) {
+ toActivate.add(alternative);
+ }
+ }
+ }
+ if (nai.networkRequests.get(mDefaultRequest.requestId) != null) {
+ removeDataActivityTracking(nai);
+ mActiveDefaultNetwork = ConnectivityManager.TYPE_NONE;
+ }
+ for (NetworkAgentInfo networkToActivate : toActivate) {
+ networkToActivate.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
+ }
+ }
+ }
+
+ private void handleRegisterNetworkRequest(Message msg) {
+ final NetworkRequestInfo nri = (NetworkRequestInfo) (msg.obj);
+ final NetworkCapabilities newCap = nri.request.networkCapabilities;
+ int score = 0;
+
+ // Check for the best currently alive network that satisfies this request
+ NetworkAgentInfo bestNetwork = null;
+ for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
+ if (VDBG) log("handleRegisterNetworkRequest checking " + network.name());
+ if (newCap.satisfiedByNetworkCapabilities(network.networkCapabilities)) {
+ if (VDBG) log("apparently satisfied. currentScore=" + network.currentScore);
+ if ((bestNetwork == null) || bestNetwork.currentScore < network.currentScore) {
+ bestNetwork = network;
+ }
+ }
+ }
+ if (bestNetwork != null) {
+ if (VDBG) log("using " + bestNetwork.name());
+ bestNetwork.networkRequests.put(nri.request.requestId, nri.request);
+ notifyNetworkCallback(bestNetwork, nri);
+ score = bestNetwork.currentScore;
+ }
+ mNetworkRequests.put(nri.request, nri);
+ if (msg.what == EVENT_REGISTER_NETWORK_REQUEST) {
+ if (DBG) log("sending new NetworkRequest to factories");
+ for (AsyncChannel ac : mNetworkFactories) {
+ ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request);
+ }
+ }
+ }
+
+ private void handleReleaseNetworkRequest(NetworkRequest request) {
+ if (DBG) log("releasing NetworkRequest " + request);
+ NetworkRequestInfo nri = mNetworkRequests.remove(request);
+ if (nri != null) {
+ // tell the network currently servicing this that it's no longer interested
+ NetworkAgentInfo affectedNetwork = mNetworkForRequestId.get(nri.request.requestId);
+ if (affectedNetwork != null) {
+ affectedNetwork.networkRequests.remove(nri.request.requestId);
+ if (VDBG) {
+ log(" Removing from current network " + affectedNetwork.name() + ", leaving " +
+ affectedNetwork.networkRequests.size() + " requests.");
+ }
+ }
+
+ if (nri.isRequest) {
+ for (AsyncChannel factory : mNetworkFactories) {
+ factory.sendMessage(NetworkFactoryProtocol.CMD_CANCEL_REQUEST, nri.request);
+ }
+
+ if (affectedNetwork != null) {
+ // check if this network still has live requests - otherwise, tear down
+ // TODO - probably push this to the NF/NA
+ boolean keep = false;
+ for (int i = 0; i < affectedNetwork.networkRequests.size(); i++) {
+ NetworkRequest r = affectedNetwork.networkRequests.valueAt(i);
+ if (mNetworkRequests.get(r).isRequest) {
+ keep = true;
+ break;
+ }
+ }
+ if (keep == false) {
+ if (DBG) log("no live requests for " + affectedNetwork.name() +
+ "; disconnecting");
+ affectedNetwork.asyncChannel.disconnect();
+ }
+ }
+ }
+ callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED);
+ }
+ }
+
private class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
@@ -3137,11 +3290,6 @@
handleInetConditionHoldEnd(netType, sequence);
break;
}
- case EVENT_SET_NETWORK_PREFERENCE: {
- int preference = msg.arg1;
- handleSetNetworkPreference(preference);
- break;
- }
case EVENT_SET_MOBILE_DATA: {
boolean enabled = (msg.arg1 == ENABLED);
handleSetMobileData(enabled);
@@ -3195,6 +3343,23 @@
handleApplyDefaultProxy((ProxyInfo)msg.obj);
break;
}
+ case EVENT_REGISTER_NETWORK_FACTORY: {
+ handleRegisterNetworkFactory((Messenger)msg.obj);
+ break;
+ }
+ case EVENT_REGISTER_NETWORK_AGENT: {
+ handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj);
+ break;
+ }
+ case EVENT_REGISTER_NETWORK_REQUEST:
+ case EVENT_REGISTER_NETWORK_LISTENER: {
+ handleRegisterNetworkRequest(msg);
+ break;
+ }
+ case EVENT_RELEASE_NETWORK_REQUEST: {
+ handleReleaseNetworkRequest((NetworkRequest) msg.obj);
+ break;
+ }
}
}
}
@@ -3341,6 +3506,10 @@
EVENT_INET_CONDITION_CHANGE, networkType, percentage));
}
+ public void reportBadNetwork(Network network) {
+ //TODO
+ }
+
private void handleInetConditionChange(int netType, int condition) {
if (mActiveDefaultNetwork == -1) {
if (DBG) log("handleInetConditionChange: no active default network - ignore");
@@ -3400,7 +3569,7 @@
// if (DBG) log("no change in condition - aborting");
// return;
//}
- NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
+ NetworkInfo networkInfo = getNetworkInfoForType(mActiveDefaultNetwork);
if (networkInfo.isConnected() == false) {
if (DBG) log("handleInetConditionHoldEnd: default network not connected - ignoring");
return;
@@ -3821,7 +3990,8 @@
// Apply DNS changes.
synchronized (mDnsLock) {
- updateDnsLocked("VPN", iface, addresses, domains, false);
+ // TODO: Re-enable this when the netId of the VPN is known.
+ // updateDnsLocked("VPN", netId, addresses, domains);
}
// Temporarily disable the default proxy (not global).
@@ -3889,21 +4059,21 @@
public void addUidForwarding(String interfaze, int uidStart, int uidEnd,
boolean forwardDns) {
- try {
- mNetd.setUidRangeRoute(interfaze,uidStart, uidEnd);
- if (forwardDns) mNetd.setDnsInterfaceForUidRange(interfaze, uidStart, uidEnd);
- } catch (RemoteException e) {
- }
+ // TODO: Re-enable this when the netId of the VPN is known.
+ // try {
+ // mNetd.setUidRangeRoute(netId, uidStart, uidEnd, forwardDns);
+ // } catch (RemoteException e) {
+ // }
}
public void clearUidForwarding(String interfaze, int uidStart, int uidEnd,
boolean forwardDns) {
- try {
- mNetd.clearUidRangeRoute(interfaze, uidStart, uidEnd);
- if (forwardDns) mNetd.clearDnsInterfaceForUidRange(interfaze, uidStart, uidEnd);
- } catch (RemoteException e) {
- }
+ // TODO: Re-enable this when the netId of the VPN is known.
+ // try {
+ // mNetd.clearUidRangeRoute(interfaze, uidStart, uidEnd);
+ // } catch (RemoteException e) {
+ // }
}
}
@@ -4164,7 +4334,10 @@
CheckMp.Params params =
new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb);
if (DBG) log("checkMobileProvisioning: params=" + params);
- checkMp.execute(params);
+ // TODO: Reenable when calls to the now defunct
+ // MobileDataStateTracker.isProvisioningNetwork() are removed.
+ // This code should be moved to the Telephony code.
+ // checkMp.execute(params);
} finally {
Binder.restoreCallingIdentity(token);
if (DBG) log("checkMobileProvisioning: X");
@@ -4407,7 +4580,7 @@
log("isMobileOk: addresses=" + inetAddressesToString(addresses));
// Get the type of addresses supported by this link
- LinkProperties lp = mCs.getLinkProperties(
+ LinkProperties lp = mCs.getLinkPropertiesForTypeInternal(
ConnectivityManager.TYPE_MOBILE_HIPRI);
boolean linkHasIpv4 = lp.hasIPv4Address();
boolean linkHasIpv6 = lp.hasIPv6Address();
@@ -4652,11 +4825,11 @@
// otherwise launch browser with the intent directly.
if (mIsProvisioningNetwork.get()) {
if (DBG) log("handleMobileProvisioningAction: on prov network enable then launch");
- mIsStartingProvisioning.set(true);
- MobileDataStateTracker mdst = (MobileDataStateTracker)
- mNetTrackers[ConnectivityManager.TYPE_MOBILE];
- mdst.setEnableFailFastMobileData(DctConstants.ENABLED);
- mdst.enableMobileProvisioning(url);
+// mIsStartingProvisioning.set(true);
+// MobileDataStateTracker mdst = (MobileDataStateTracker)
+// mNetTrackers[ConnectivityManager.TYPE_MOBILE];
+// mdst.setEnableFailFastMobileData(DctConstants.ENABLED);
+// mdst.enableMobileProvisioning(url);
} else {
if (DBG) log("handleMobileProvisioningAction: not prov network");
// Check for apps that can handle provisioning first
@@ -4952,7 +5125,7 @@
@Override
public LinkQualityInfo getLinkQualityInfo(int networkType) {
enforceAccessPermission();
- if (isNetworkTypeValid(networkType)) {
+ if (isNetworkTypeValid(networkType) && mNetTrackers[networkType] != null) {
return mNetTrackers[networkType].getLinkQualityInfo();
} else {
return null;
@@ -4962,7 +5135,8 @@
@Override
public LinkQualityInfo getActiveLinkQualityInfo() {
enforceAccessPermission();
- if (isNetworkTypeValid(mActiveDefaultNetwork)) {
+ if (isNetworkTypeValid(mActiveDefaultNetwork) &&
+ mNetTrackers[mActiveDefaultNetwork] != null) {
return mNetTrackers[mActiveDefaultNetwork].getLinkQualityInfo();
} else {
return null;
@@ -5035,4 +5209,615 @@
long wakeupTime = SystemClock.elapsedRealtime() + timeoutInMilliseconds;
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, intent);
}
+
+ private final ArrayList<AsyncChannel> mNetworkFactories = new ArrayList<AsyncChannel>();
+ private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests =
+ new HashMap<NetworkRequest, NetworkRequestInfo>();
+
+
+ private class NetworkRequestInfo implements IBinder.DeathRecipient {
+ static final boolean REQUEST = true;
+ static final boolean LISTEN = false;
+
+ final NetworkRequest request;
+ IBinder mBinder;
+ final int mPid;
+ final int mUid;
+ final Messenger messenger;
+ final boolean isRequest;
+
+ NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder, boolean isRequest) {
+ super();
+ messenger = m;
+ request = r;
+ mBinder = binder;
+ mPid = getCallingPid();
+ mUid = getCallingUid();
+ this.isRequest = isRequest;
+
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ binderDied();
+ }
+ }
+
+ void unlinkDeathRecipient() {
+ mBinder.unlinkToDeath(this, 0);
+ }
+
+ public void binderDied() {
+ log("ConnectivityService NetworkRequestInfo binderDied(" +
+ request + ", " + mBinder + ")");
+ releaseNetworkRequest(request);
+ }
+ }
+
+ @Override
+ public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
+ Messenger messenger, int timeoutSec, IBinder binder) {
+ if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ == false) {
+ enforceConnectivityInternalPermission();
+ } else {
+ enforceChangePermission();
+ }
+
+ if (timeoutSec < 0 || timeoutSec > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_SEC) {
+ throw new IllegalArgumentException("Bad timeout specified");
+ }
+ NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
+ networkCapabilities));
+ if (DBG) log("requestNetwork for " + networkRequest);
+ NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
+ NetworkRequestInfo.REQUEST);
+
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
+ if (timeoutSec > 0) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST,
+ nri), timeoutSec * 1000);
+ }
+ return networkRequest;
+ }
+
+ @Override
+ public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities,
+ PendingIntent operation) {
+ // TODO
+ return null;
+ }
+
+ @Override
+ public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,
+ Messenger messenger, IBinder binder) {
+ enforceAccessPermission();
+
+ NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
+ networkCapabilities));
+ if (DBG) log("listenForNetwork for " + networkRequest);
+ NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
+ NetworkRequestInfo.LISTEN);
+
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
+ return networkRequest;
+ }
+
+ @Override
+ public void pendingListenForNetwork(NetworkCapabilities networkCapabilities,
+ PendingIntent operation) {
+ }
+
+ @Override
+ public void releaseNetworkRequest(NetworkRequest networkRequest) {
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST,
+ networkRequest));
+ }
+
+ @Override
+ public void registerNetworkFactory(Messenger messenger) {
+ enforceConnectivityInternalPermission();
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, messenger));
+ }
+
+ private void handleRegisterNetworkFactory(Messenger messenger) {
+ if (VDBG) log("Got NetworkFactory Messenger");
+ AsyncChannel ac = new AsyncChannel();
+ mNetworkFactories.add(ac);
+ ac.connect(mContext, mTrackerHandler, messenger);
+ for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+ if (nri.isRequest) {
+ int score = 0;
+ NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
+ if (currentNetwork != null) score = currentNetwork.currentScore;
+ ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request);
+ }
+ }
+ }
+
+ /**
+ * NetworkAgentInfo supporting a request by requestId.
+ * These have already been vetted (their Capabilities satisfy the request)
+ * and the are the highest scored network available.
+ * the are keyed off the Requests requestId.
+ */
+ private final SparseArray<NetworkAgentInfo> mNetworkForRequestId =
+ new SparseArray<NetworkAgentInfo>();
+
+ private final SparseArray<NetworkAgentInfo> mNetworkForNetId =
+ new SparseArray<NetworkAgentInfo>();
+
+ // NetworkAgentInfo keyed off its connecting messenger
+ // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays
+ private final HashMap<Messenger, NetworkAgentInfo> mNetworkAgentInfos =
+ new HashMap<Messenger, NetworkAgentInfo>();
+
+ private final NetworkRequest mDefaultRequest;
+
+ public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
+ LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
+ int currentScore) {
+ enforceConnectivityInternalPermission();
+
+ NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), nextNetId(),
+ new NetworkInfo(networkInfo), new LinkProperties(linkProperties),
+ new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler);
+
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
+ }
+
+ private void handleRegisterNetworkAgent(NetworkAgentInfo na) {
+ if (VDBG) log("Got NetworkAgent Messenger");
+ mNetworkAgentInfos.put(na.messenger, na);
+ try {
+ mNetworkAgentInfoForType[na.networkInfo.getType()].add(na);
+ } catch (NullPointerException e) {
+ loge("registered NetworkAgent for unsupported type: " + na);
+ }
+ mNetworkForNetId.put(na.network.netId, na);
+ na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);
+ NetworkInfo networkInfo = na.networkInfo;
+ na.networkInfo = null;
+ updateNetworkInfo(na, networkInfo);
+ }
+
+ private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) {
+ LinkProperties newLp = networkAgent.linkProperties;
+ int netId = networkAgent.network.netId;
+
+ updateInterfaces(newLp, oldLp, netId);
+ updateMtu(newLp, oldLp);
+ // TODO - figure out what to do for clat
+// for (LinkProperties lp : newLp.getStackedLinks()) {
+// updateMtu(lp, null);
+// }
+ updateRoutes(newLp, oldLp, netId);
+ updateDnses(newLp, oldLp, netId);
+ updateClat(newLp, oldLp, networkAgent);
+ }
+
+ private void updateClat(LinkProperties newLp, LinkProperties oldLp, NetworkAgentInfo na) {
+ // Update 464xlat state.
+ if (mClat.requiresClat(na)) {
+
+ // If the connection was previously using clat, but is not using it now, stop the clat
+ // daemon. Normally, this happens automatically when the connection disconnects, but if
+ // the disconnect is not reported, or if the connection's LinkProperties changed for
+ // some other reason (e.g., handoff changes the IP addresses on the link), it would
+ // still be running. If it's not running, then stopping it is a no-op.
+ if (Nat464Xlat.isRunningClat(oldLp) && !Nat464Xlat.isRunningClat(newLp)) {
+ mClat.stopClat();
+ }
+ // If the link requires clat to be running, then start the daemon now.
+ if (newLp != null && na.networkInfo.isConnected()) {
+ mClat.startClat(na);
+ } else {
+ mClat.stopClat();
+ }
+ }
+ }
+
+ private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId) {
+ CompareResult<String> interfaceDiff = new CompareResult<String>();
+ if (oldLp != null) {
+ interfaceDiff = oldLp.compareAllInterfaceNames(newLp);
+ } else if (newLp != null) {
+ interfaceDiff.added = newLp.getAllInterfaceNames();
+ }
+ for (String iface : interfaceDiff.added) {
+ try {
+ mNetd.addInterfaceToNetwork(iface, netId);
+ } catch (Exception e) {
+ loge("Exception adding interface: " + e);
+ }
+ }
+ for (String iface : interfaceDiff.removed) {
+ try {
+ mNetd.removeInterfaceFromNetwork(iface, netId);
+ } catch (Exception e) {
+ loge("Exception removing interface: " + e);
+ }
+ }
+ }
+
+ private void updateRoutes(LinkProperties newLp, LinkProperties oldLp, int netId) {
+ CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
+ if (oldLp != null) {
+ routeDiff = oldLp.compareAllRoutes(newLp);
+ } else if (newLp != null) {
+ routeDiff.added = newLp.getAllRoutes();
+ }
+
+ // add routes before removing old in case it helps with continuous connectivity
+
+ // do this twice, adding non-nexthop routes first, then routes they are dependent on
+ for (RouteInfo route : routeDiff.added) {
+ if (route.hasGateway()) continue;
+ try {
+ mNetd.addRoute(netId, route);
+ } catch (Exception e) {
+ loge("Exception in addRoute for non-gateway: " + e);
+ }
+ }
+ for (RouteInfo route : routeDiff.added) {
+ if (route.hasGateway() == false) continue;
+ try {
+ mNetd.addRoute(netId, route);
+ } catch (Exception e) {
+ loge("Exception in addRoute for gateway: " + e);
+ }
+ }
+
+ for (RouteInfo route : routeDiff.removed) {
+ try {
+ mNetd.removeRoute(netId, route);
+ } catch (Exception e) {
+ loge("Exception in removeRoute: " + e);
+ }
+ }
+ }
+ private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId) {
+ if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) {
+ Collection<InetAddress> dnses = newLp.getDnses();
+ if (dnses.size() == 0 && mDefaultDns != null) {
+ dnses = new ArrayList();
+ dnses.add(mDefaultDns);
+ if (DBG) {
+ loge("no dns provided for netId " + netId + ", so using defaults");
+ }
+ }
+ try {
+ mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses),
+ newLp.getDomains());
+ } catch (Exception e) {
+ loge("Exception in setDnsServersForNetwork: " + e);
+ }
+ // TODO - setprop "net.dnsX"
+ }
+ }
+
+ private void updateCapabilities(NetworkAgentInfo networkAgent,
+ NetworkCapabilities networkCapabilities) {
+ // TODO - what else here? Verify still satisfies everybody?
+ // Check if satisfies somebody new? call callbacks?
+ networkAgent.networkCapabilities = networkCapabilities;
+ }
+
+ private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) {
+ if (VDBG) log("sending new Min Network Score(" + score + "): " + networkRequest.toString());
+ for (AsyncChannel ac : mNetworkFactories) {
+ ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, networkRequest);
+ }
+ }
+
+ private void callCallbackForRequest(NetworkRequestInfo nri,
+ NetworkAgentInfo networkAgent, int notificationType) {
+ if (nri.messenger == null) return; // Default request has no msgr
+ Object o;
+ int a1 = 0;
+ int a2 = 0;
+ switch (notificationType) {
+ case ConnectivityManager.CALLBACK_LOSING:
+ a1 = 30; // TODO - read this from NetworkMonitor
+ // fall through
+ case ConnectivityManager.CALLBACK_PRECHECK:
+ case ConnectivityManager.CALLBACK_AVAILABLE:
+ case ConnectivityManager.CALLBACK_LOST:
+ case ConnectivityManager.CALLBACK_CAP_CHANGED:
+ case ConnectivityManager.CALLBACK_IP_CHANGED: {
+ o = new NetworkRequest(nri.request);
+ a2 = networkAgent.network.netId;
+ break;
+ }
+ case ConnectivityManager.CALLBACK_UNAVAIL:
+ case ConnectivityManager.CALLBACK_RELEASED: {
+ o = new NetworkRequest(nri.request);
+ break;
+ }
+ default: {
+ loge("Unknown notificationType " + notificationType);
+ return;
+ }
+ }
+ Message msg = Message.obtain();
+ msg.arg1 = a1;
+ msg.arg2 = a2;
+ msg.obj = o;
+ msg.what = notificationType;
+ try {
+ if (VDBG) log("sending notification " + notificationType + " for " + nri.request);
+ nri.messenger.send(msg);
+ } catch (RemoteException e) {
+ // may occur naturally in the race of binder death.
+ loge("RemoteException caught trying to send a callback msg for " + nri.request);
+ }
+ }
+
+ private void handleLingerComplete(NetworkAgentInfo oldNetwork) {
+ if (oldNetwork == null) {
+ loge("Unknown NetworkAgentInfo in handleLingerComplete");
+ return;
+ }
+ if (DBG) log("handleLingerComplete for " + oldNetwork.name());
+ if (DBG) {
+ if (oldNetwork.networkRequests.size() != 0) {
+ loge("Dead network still had " + oldNetwork.networkRequests.size() + " requests");
+ }
+ }
+ oldNetwork.asyncChannel.disconnect();
+ }
+
+ private void handleConnectionValidated(NetworkAgentInfo newNetwork) {
+ if (newNetwork == null) {
+ loge("Unknown NetworkAgentInfo in handleConnectionValidated");
+ return;
+ }
+ boolean keep = false;
+ boolean isNewDefault = false;
+ if (DBG) log("handleConnectionValidated for "+newNetwork.name());
+ // check if any NetworkRequest wants this NetworkAgent
+ // first check if it satisfies the NetworkCapabilities
+ ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>();
+ if (VDBG) log(" new Network has: " + newNetwork.networkCapabilities);
+ for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+ if (VDBG) log(" checking if request is satisfied: " + nri.request);
+ if (nri.request.networkCapabilities.satisfiedByNetworkCapabilities(
+ newNetwork.networkCapabilities)) {
+ // next check if it's better than any current network we're using for
+ // this request
+ NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
+ if (VDBG) {
+ log("currentScore = " +
+ (currentNetwork != null ? currentNetwork.currentScore : 0) +
+ ", newScore = " + newNetwork.currentScore);
+ }
+ if (currentNetwork == null ||
+ currentNetwork.currentScore < newNetwork.currentScore) {
+ if (currentNetwork != null) {
+ if (VDBG) log(" accepting network in place of " + currentNetwork.name());
+ currentNetwork.networkRequests.remove(nri.request.requestId);
+ currentNetwork.networkLingered.add(nri.request);
+ affectedNetworks.add(currentNetwork);
+ } else {
+ if (VDBG) log(" accepting network in place of null");
+ }
+ mNetworkForRequestId.put(nri.request.requestId, newNetwork);
+ newNetwork.networkRequests.put(nri.request.requestId, nri.request);
+ keep = true;
+ // TODO - this could get expensive if we have alot of requests for this
+ // network. Think about if there is a way to reduce this. Push
+ // netid->request mapping to each factory?
+ sendUpdatedScoreToFactories(nri.request, newNetwork.currentScore);
+ if (mDefaultRequest.requestId == nri.request.requestId) {
+ isNewDefault = true;
+ updateActiveDefaultNetwork(newNetwork);
+ }
+ }
+ }
+ }
+ for (NetworkAgentInfo nai : affectedNetworks) {
+ boolean teardown = true;
+ for (int i = 0; i < nai.networkRequests.size(); i++) {
+ NetworkRequest nr = nai.networkRequests.valueAt(i);
+ try {
+ if (mNetworkRequests.get(nr).isRequest) {
+ teardown = false;
+ }
+ } catch (Exception e) {
+ loge("Request " + nr + " not found in mNetworkRequests.");
+ loge(" it came from request list of " + nai.name());
+ }
+ }
+ if (teardown) {
+ nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_LINGER);
+ notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING);
+ } else {
+ // not going to linger, so kill the list of linger networks.. only
+ // notify them of linger if it happens as the result of gaining another,
+ // but if they transition and old network stays up, don't tell them of linger
+ // or very delayed loss
+ nai.networkLingered.clear();
+ if (VDBG) log("Lingered for " + nai.name() + " cleared");
+ }
+ }
+ if (keep) {
+ if (isNewDefault) {
+ if (VDBG) log("Switching to new default network: " + newNetwork);
+ setupDataActivityTracking(newNetwork);
+ try {
+ mNetd.setDefaultNetId(newNetwork.network.netId);
+ } catch (Exception e) {
+ loge("Exception setting default network :" + e);
+ }
+ if (newNetwork.equals(mNetworkForRequestId.get(mDefaultRequest.requestId))) {
+ handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
+ }
+ synchronized (ConnectivityService.this) {
+ // have a new default network, release the transition wakelock in
+ // a second if it's held. The second pause is to allow apps
+ // to reconnect over the new network
+ if (mNetTransitionWakeLock.isHeld()) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
+ mNetTransitionWakeLockSerialNumber, 0),
+ 1000);
+ }
+ }
+
+ // this will cause us to come up initially as unconnected and switching
+ // to connected after our normal pause unless somebody reports us as
+ // really disconnected
+ mDefaultInetConditionPublished = 0;
+ mDefaultConnectionSequence++;
+ mInetConditionChangeInFlight = false;
+ // TODO - read the tcp buffer size config string from somewhere
+ // updateNetworkSettings();
+ }
+ // notify battery stats service about this network
+// try {
+ // TODO
+ //BatteryStatsService.getService().noteNetworkInterfaceType(iface, netType);
+// } catch (RemoteException e) { }
+ notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_AVAILABLE);
+ } else {
+ if (DBG && newNetwork.networkRequests.size() != 0) {
+ loge("tearing down network with live requests:");
+ for (int i=0; i < newNetwork.networkRequests.size(); i++) {
+ loge(" " + newNetwork.networkRequests.valueAt(i));
+ }
+ }
+ if (VDBG) log("Validated network turns out to be unwanted. Tear it down.");
+ newNetwork.asyncChannel.disconnect();
+ }
+ }
+
+
+ private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
+ NetworkInfo.State state = newInfo.getState();
+ NetworkInfo oldInfo = networkAgent.networkInfo;
+ networkAgent.networkInfo = newInfo;
+
+ if (oldInfo != null && oldInfo.getState() == state) {
+ if (VDBG) log("ignoring duplicate network state non-change");
+ return;
+ }
+ if (DBG) {
+ log(networkAgent.name() + " EVENT_NETWORK_INFO_CHANGED, going from " +
+ (oldInfo == null ? "null" : oldInfo.getState()) +
+ " to " + state);
+ }
+
+ if (state == NetworkInfo.State.CONNECTED) {
+ // TODO - check if we want it (optimization)
+ try {
+ mNetd.createNetwork(networkAgent.network.netId);
+ } catch (Exception e) {
+ loge("Error creating Network " + networkAgent.network.netId);
+ }
+ updateLinkProperties(networkAgent, null);
+ notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);
+ networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
+ } else if (state == NetworkInfo.State.DISCONNECTED ||
+ state == NetworkInfo.State.SUSPENDED) {
+ networkAgent.asyncChannel.disconnect();
+ }
+ }
+
+ // notify only this one new request of the current state
+ protected void notifyNetworkCallback(NetworkAgentInfo nai, NetworkRequestInfo nri) {
+ int notifyType = ConnectivityManager.CALLBACK_AVAILABLE;
+ // TODO - read state from monitor to decide what to send.
+// if (nai.networkMonitor.isLingering()) {
+// notifyType = NetworkCallbacks.LOSING;
+// } else if (nai.networkMonitor.isEvaluating()) {
+// notifyType = NetworkCallbacks.callCallbackForRequest(request, nai, notifyType);
+// }
+ if (nri.request.needsBroadcasts) {
+ // TODO
+// sendNetworkBroadcast(nai, notifyType);
+ }
+ callCallbackForRequest(nri, nai, notifyType);
+ }
+
+ protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType) {
+ if (VDBG) log("notifyType " + notifyType + " for " + networkAgent.name());
+ boolean needsBroadcasts = false;
+ for (int i = 0; i < networkAgent.networkRequests.size(); i++) {
+ NetworkRequest nr = networkAgent.networkRequests.valueAt(i);
+ NetworkRequestInfo nri = mNetworkRequests.get(nr);
+ if (VDBG) log(" sending notification for " + nr);
+ if (nr.needsBroadcasts) needsBroadcasts = true;
+ callCallbackForRequest(nri, networkAgent, notifyType);
+ }
+ if (needsBroadcasts) {
+ if (notifyType == ConnectivityManager.CALLBACK_AVAILABLE) {
+ sendConnectedBroadcastDelayed(networkAgent.networkInfo,
+ getConnectivityChangeDelay());
+ } else if (notifyType == ConnectivityManager.CALLBACK_LOST) {
+ NetworkInfo info = new NetworkInfo(networkAgent.networkInfo);
+ Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
+ if (info.isFailover()) {
+ intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
+ networkAgent.networkInfo.setFailover(false);
+ }
+ if (info.getReason() != null) {
+ intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
+ }
+ if (info.getExtraInfo() != null) {
+ intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
+ }
+ NetworkAgentInfo newDefaultAgent = null;
+ if (networkAgent.networkRequests.get(mDefaultRequest.requestId) != null) {
+ newDefaultAgent = mNetworkForRequestId.get(mDefaultRequest.requestId);
+ if (newDefaultAgent != null) {
+ intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO,
+ newDefaultAgent.networkInfo);
+ } else {
+ intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
+ }
+ }
+ intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION,
+ mDefaultInetConditionPublished);
+ final Intent immediateIntent = new Intent(intent);
+ immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE);
+ sendStickyBroadcast(immediateIntent);
+ sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
+ if (newDefaultAgent != null) {
+ sendConnectedBroadcastDelayed(newDefaultAgent.networkInfo,
+ getConnectivityChangeDelay());
+ }
+ }
+ }
+ }
+
+ private LinkProperties getLinkPropertiesForTypeInternal(int networkType) {
+ ArrayList<NetworkAgentInfo> list = mNetworkAgentInfoForType[networkType];
+ if (list == null) return null;
+ try {
+ return new LinkProperties(list.get(0).linkProperties);
+ } catch (IndexOutOfBoundsException e) {
+ return new LinkProperties();
+ }
+ }
+
+ private NetworkInfo getNetworkInfoForType(int networkType) {
+ ArrayList<NetworkAgentInfo> list = mNetworkAgentInfoForType[networkType];
+ if (list == null) return null;
+ try {
+ return new NetworkInfo(list.get(0).networkInfo);
+ } catch (IndexOutOfBoundsException e) {
+ return new NetworkInfo(networkType, 0, "Unknown", "");
+ }
+ }
+
+ private NetworkCapabilities getNetworkCapabilitiesForType(int networkType) {
+ ArrayList<NetworkAgentInfo> list = mNetworkAgentInfoForType[networkType];
+ if (list == null) return null;
+ try {
+ return new NetworkCapabilities(list.get(0).networkCapabilities);
+ } catch (IndexOutOfBoundsException e) {
+ return new NetworkCapabilities();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 10315a7..0b9570d 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -1464,6 +1464,7 @@
private boolean needsToShowImeSwitchOngoingNotification() {
if (!mShowOngoingImeSwitcherForPhones) return false;
+ if (mSwitchingDialog != null) return false;
if (isScreenLocked()) return false;
synchronized (mMethodMap) {
List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
@@ -2812,6 +2813,7 @@
mSwitchingDialog.getWindow().getAttributes().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
mSwitchingDialog.getWindow().getAttributes().setTitle("Select input method");
+ updateImeWindowStatusLocked();
mSwitchingDialog.show();
}
}
@@ -2869,6 +2871,7 @@
mSwitchingDialog = null;
}
+ updateImeWindowStatusLocked();
mDialogBuilder = null;
mIms = null;
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index d6ecb46..e54e5d0 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -427,7 +427,7 @@
}
// bind to fused provider if supported
- if (FlpHardwareProvider.isSupported()) {
+ if (FlpHardwareProvider.getInstance(mContext).isSupported()) {
FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
FusedProxy fusedProxy = FusedProxy.createAndBind(
mContext,
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
index 0d1e122..96f9ab0 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/services/core/java/com/android/server/NativeDaemonConnector.java
@@ -50,6 +50,8 @@
final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor {
private static final boolean LOGD = false;
+ private final static boolean VDBG = false;
+
private final String TAG;
private String mSocket;
@@ -409,7 +411,7 @@
loge("timed-out waiting for response to " + logCmd);
throw new NativeDaemonFailureException(logCmd, event);
}
- log("RMV <- {" + event + "}");
+ if (VDBG) log("RMV <- {" + event + "}");
events.add(event);
} while (event.isClassContinue());
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 7ce45f7..cf91782 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import static android.Manifest.permission.CHANGE_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.SHUTDOWN;
@@ -867,46 +868,25 @@
}
@Override
- public void addRoute(String interfaceName, RouteInfo route) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- modifyRoute(interfaceName, ADD, route, DEFAULT);
+ public void addRoute(int netId, RouteInfo route) {
+ modifyRoute(netId, ADD, route);
}
@Override
- public void removeRoute(String interfaceName, RouteInfo route) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- modifyRoute(interfaceName, REMOVE, route, DEFAULT);
+ public void removeRoute(int netId, RouteInfo route) {
+ modifyRoute(netId, REMOVE, route);
}
- @Override
- public void addSecondaryRoute(String interfaceName, RouteInfo route) {
+ private void modifyRoute(int netId, String action, RouteInfo route) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- modifyRoute(interfaceName, ADD, route, SECONDARY);
- }
- @Override
- public void removeSecondaryRoute(String interfaceName, RouteInfo route) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- modifyRoute(interfaceName, REMOVE, route, SECONDARY);
- }
+ final Command cmd = new Command("network", "route", action, netId);
- private void modifyRoute(String interfaceName, String action, RouteInfo route, String type) {
- final Command cmd = new Command("interface", "route", action, interfaceName, type);
-
- // create triplet: dest-ip-addr prefixlength gateway-ip-addr
+ // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
final LinkAddress la = route.getDestination();
- cmd.appendArg(la.getAddress().getHostAddress());
- cmd.appendArg(la.getNetworkPrefixLength());
-
- if (route.getGateway() == null) {
- if (la.getAddress() instanceof Inet4Address) {
- cmd.appendArg("0.0.0.0");
- } else {
- cmd.appendArg("::0");
- }
- } else {
- cmd.appendArg(route.getGateway().getHostAddress());
- }
+ cmd.appendArg(route.getInterface());
+ cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getNetworkPrefixLength());
+ cmd.appendArg(route.getGateway().getHostAddress());
try {
mConnector.execute(cmd);
@@ -1624,20 +1604,10 @@
}
@Override
- public void setDefaultInterfaceForDns(String iface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- try {
- mConnector.execute("resolver", "setdefaultif", iface);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- }
-
- @Override
- public void setDnsServersForInterface(String iface, String[] servers, String domains) {
+ public void setDnsServersForNetwork(int netId, String[] servers, String domains) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- final Command cmd = new Command("resolver", "setifdns", iface,
+ final Command cmd = new Command("resolver", "setnetdns", netId,
(domains == null ? "" : domains));
for (String s : servers) {
@@ -1655,11 +1625,11 @@
}
@Override
- public void setUidRangeRoute(String iface, int uid_start, int uid_end) {
+ public void setUidRangeRoute(String iface, int uid_start, int uid_end, boolean forward_dns) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
mConnector.execute("interface", "fwmark",
- "uid", "add", iface, uid_start, uid_end);
+ "uid", "add", iface, uid_start, uid_end, forward_dns ? 1 : 0);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
@@ -1670,7 +1640,7 @@
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
mConnector.execute("interface", "fwmark",
- "uid", "remove", iface, uid_start, uid_end);
+ "uid", "remove", iface, uid_start, uid_end, 0);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
@@ -1767,51 +1737,10 @@
}
@Override
- public void setDnsInterfaceForUidRange(String iface, int uid_start, int uid_end) {
+ public void flushNetworkDnsCache(int netId) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("resolver", "setifaceforuidrange", iface, uid_start, uid_end);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- }
-
- @Override
- public void clearDnsInterfaceForUidRange(String iface, int uid_start, int uid_end) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- try {
- mConnector.execute("resolver", "clearifaceforuidrange", iface, uid_start, uid_end);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- }
-
- @Override
- public void clearDnsInterfaceMaps() {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- try {
- mConnector.execute("resolver", "clearifacemapping");
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- }
-
-
- @Override
- public void flushDefaultDnsCache() {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- try {
- mConnector.execute("resolver", "flushdefaultif");
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- }
-
- @Override
- public void flushInterfaceDnsCache(String iface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- try {
- mConnector.execute("resolver", "flushif", iface);
+ mConnector.execute("resolver", "flushnet", netId);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
@@ -1890,28 +1819,6 @@
}
@Override
- public void setDnsInterfaceForPid(String iface, int pid) throws IllegalStateException {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- try {
- mConnector.execute("resolver", "setifaceforpid", iface, pid);
- } catch (NativeDaemonConnectorException e) {
- throw new IllegalStateException(
- "Error communicating with native deamon to set interface for pid" + iface, e);
- }
- }
-
- @Override
- public void clearDnsInterfaceForPid(int pid) throws IllegalStateException {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- try {
- mConnector.execute("resolver", "clearifaceforpid", pid);
- } catch (NativeDaemonConnectorException e) {
- throw new IllegalStateException(
- "Error communicating with native deamon to clear interface for pid " + pid, e);
- }
- }
-
- @Override
public void startClatd(String interfaceName) throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
@@ -2029,4 +1936,133 @@
pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
}
+
+ @Override
+ public void createNetwork(int netId) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+ try {
+ mConnector.execute("network", "create", netId);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void removeNetwork(int netId) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+ try {
+ mConnector.execute("network", "destroy", netId);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void addInterfaceToNetwork(String iface, int netId) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+ try {
+ mConnector.execute("network", "addiface", netId, iface);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void removeInterfaceFromNetwork(String iface, int netId) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+ try {
+ mConnector.execute("network", "removeiface", netId, iface);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
+ modifyLegacyRouteForNetId(netId, routeInfo, uid, ADD);
+ }
+
+ @Override
+ public void removeLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
+ modifyLegacyRouteForNetId(netId, routeInfo, uid, REMOVE);
+ }
+
+ private void modifyLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid, String action) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+ final Command cmd = new Command("network", "legacy", uid, "route", action, netId);
+
+ // create quadlet: dest-ip-addr prefixlength gateway-ip-addr iface
+ final LinkAddress la = routeInfo.getDestination();
+ cmd.appendArg(la.getAddress().getHostAddress());
+ cmd.appendArg(la.getNetworkPrefixLength());
+ cmd.appendArg(routeInfo.getGateway().getHostAddress());
+ cmd.appendArg(routeInfo.getInterface());
+
+ try {
+ mConnector.execute(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void setDefaultNetId(int netId) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+ try {
+ mConnector.execute("network", "default", "set", netId);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void clearDefaultNetId() {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+ try {
+ mConnector.execute("network", "default", "clear");
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void setPermission(boolean internal, boolean changeNetState, int[] uids) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+ final Command cmd = new Command("network", "permission", "user", "set");
+ if (internal) cmd.appendArg(CONNECTIVITY_INTERNAL);
+ if (changeNetState) cmd.appendArg(CHANGE_NETWORK_STATE);
+ for (int i=0; i<uids.length; i++) {
+ cmd.appendArg(uids[i]);
+ }
+
+ try {
+ mConnector.execute(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
+ public void clearPermission(int[] uids) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+ final Command cmd = new Command("network", "permission", "user", "clear");
+ for (int i=0; i<uids.length; i++) {
+ cmd.appendArg(uids[i]);
+ }
+
+ try {
+ mConnector.execute(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 4f0c9b5..512ebc6 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -171,6 +171,7 @@
return;
}
writer.println("Current scorer: " + currentScorer);
+ writer.flush();
for (INetworkScoreCache scoreCache : getScoreCaches()) {
try {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index d4565b6..cfaf016 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -22,8 +22,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
-import android.net.LinkCapabilities;
import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -120,7 +120,7 @@
private LinkProperties mDataConnectionLinkProperties;
- private LinkCapabilities mDataConnectionLinkCapabilities;
+ private NetworkCapabilities mDataConnectionNetworkCapabilities;
private Bundle mCellLocation = new Bundle();
@@ -553,7 +553,7 @@
public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
String reason, String apn, String apnType, LinkProperties linkProperties,
- LinkCapabilities linkCapabilities, int networkType, boolean roaming) {
+ NetworkCapabilities networkCapabilities, int networkType, boolean roaming) {
if (!checkNotifyPermission("notifyDataConnection()" )) {
return;
}
@@ -587,7 +587,7 @@
mDataConnectionPossible = isDataConnectivityPossible;
mDataConnectionReason = reason;
mDataConnectionLinkProperties = linkProperties;
- mDataConnectionLinkCapabilities = linkCapabilities;
+ mDataConnectionNetworkCapabilities = networkCapabilities;
if (mDataConnectionNetworkType != networkType) {
mDataConnectionNetworkType = networkType;
// need to tell registered listeners about the new network type
@@ -624,7 +624,7 @@
handleRemoveListLocked();
}
broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
- apnType, linkProperties, linkCapabilities, roaming);
+ apnType, linkProperties, networkCapabilities, roaming);
broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, reason,
linkProperties, "");
}
@@ -794,7 +794,8 @@
pw.println(" mDataConnectionReason=" + mDataConnectionReason);
pw.println(" mDataConnectionApn=" + mDataConnectionApn);
pw.println(" mDataConnectionLinkProperties=" + mDataConnectionLinkProperties);
- pw.println(" mDataConnectionLinkCapabilities=" + mDataConnectionLinkCapabilities);
+ pw.println(" mDataConnectionNetworkCapabilities=" +
+ mDataConnectionNetworkCapabilities);
pw.println(" mCellLocation=" + mCellLocation);
pw.println(" mCellInfo=" + mCellInfo);
pw.println(" mDcRtInfo=" + mDcRtInfo);
@@ -862,7 +863,7 @@
private void broadcastDataConnectionStateChanged(int state,
boolean isDataConnectivityPossible,
String reason, String apn, String apnType, LinkProperties linkProperties,
- LinkCapabilities linkCapabilities, boolean roaming) {
+ NetworkCapabilities networkCapabilities, boolean roaming) {
// Note: not reporting to the battery stats service here, because the
// status bar takes care of that after taking into account all of the
// required info.
@@ -882,8 +883,8 @@
intent.putExtra(PhoneConstants.DATA_IFACE_NAME_KEY, iface);
}
}
- if (linkCapabilities != null) {
- intent.putExtra(PhoneConstants.DATA_LINK_CAPABILITIES_KEY, linkCapabilities);
+ if (networkCapabilities != null) {
+ intent.putExtra(PhoneConstants.DATA_NETWORK_CAPABILITIES_KEY, networkCapabilities);
}
if (roaming) intent.putExtra(PhoneConstants.DATA_NETWORK_ROAMING_KEY, true);
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index ea9de1e..82c13e0 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -360,8 +360,9 @@
// Lock held on mVibrations
private void startVibrationLocked(final Vibration vib) {
try {
- if (mLowPowerMode && vib.mStreamHint != AudioManager.STREAM_RING)
- return;
+ if (mLowPowerMode && vib.mStreamHint != AudioManager.STREAM_RING) {
+ return;
+ }
int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
vib.mStreamHint, vib.mUid, vib.mOpPkg);
@@ -443,7 +444,7 @@
}
mLowPowerMode = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.LOW_POWER_MODE, 0) != 0;
+ Settings.Global.LOW_POWER_MODE, 0) != 0;
if (mVibrateInputDevicesSetting) {
if (!mInputDeviceListenerRegistered) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index f587ccc..b2aaf74 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -34,6 +34,7 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentValues;
@@ -857,7 +858,7 @@
checkManageAccountsPermission();
UserHandle user = Binder.getCallingUserHandle();
UserAccounts accounts = getUserAccountsForCaller();
- if (!canUserModifyAccounts(Binder.getCallingUid())) {
+ if (!canUserModifyAccounts(Binder.getCallingUid(), account.type)) {
try {
response.onError(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
"User cannot modify accounts");
@@ -1512,7 +1513,7 @@
checkManageAccountsPermission();
// Is user disallowed from modifying accounts?
- if (!canUserModifyAccounts(Binder.getCallingUid())) {
+ if (!canUserModifyAccounts(Binder.getCallingUid(), accountType)) {
try {
response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
"User is not allowed to add an account!");
@@ -2758,7 +2759,7 @@
Manifest.permission.USE_CREDENTIALS);
}
- private boolean canUserModifyAccounts(int callingUid) {
+ private boolean canUserModifyAccounts(int callingUid, String accountType) {
if (callingUid != Process.myUid()) {
if (getUserManager().getUserRestrictions(
new UserHandle(UserHandle.getUserId(callingUid)))
@@ -2766,6 +2767,15 @@
return false;
}
}
+
+ DevicePolicyManager dpm = (DevicePolicyManager) mContext
+ .getSystemService(Context.DEVICE_POLICY_SERVICE);
+ String[] typesArray = dpm.getAccountTypesWithManagementDisabled();
+ for (String forbiddenType : typesArray) {
+ if (forbiddenType.equals(accountType)) {
+ return false;
+ }
+ }
return true;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 09e7e12..bab5b9c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -32,9 +32,11 @@
import android.app.AppOpsManager;
import android.app.IActivityContainer;
import android.app.IActivityContainerCallback;
+import android.app.IAppTask;
import android.appwidget.AppWidgetManager;
import android.graphics.Rect;
import android.os.BatteryStats;
+import android.os.PersistableBundle;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArrayMap;
@@ -721,6 +723,8 @@
private static final String TAG_URI_GRANTS = "uri-grants";
private static final String TAG_URI_GRANT = "uri-grant";
private static final String ATTR_USER_HANDLE = "userHandle";
+ private static final String ATTR_SOURCE_USER_ID = "sourceUserId";
+ private static final String ATTR_TARGET_USER_ID = "targetUserId";
private static final String ATTR_SOURCE_PKG = "sourcePkg";
private static final String ATTR_TARGET_PKG = "targetPkg";
private static final String ATTR_URI = "uri";
@@ -738,10 +742,12 @@
mGrantedUriPermissions = new SparseArray<ArrayMap<GrantUri, UriPermission>>();
public static class GrantUri {
+ public final int sourceUserId;
public final Uri uri;
- public final boolean prefix;
+ public boolean prefix;
- public GrantUri(Uri uri, boolean prefix) {
+ public GrantUri(int sourceUserId, Uri uri, boolean prefix) {
+ this.sourceUserId = sourceUserId;
this.uri = uri;
this.prefix = prefix;
}
@@ -755,18 +761,28 @@
public boolean equals(Object o) {
if (o instanceof GrantUri) {
GrantUri other = (GrantUri) o;
- return uri.equals(other.uri) && prefix == other.prefix;
+ return uri.equals(other.uri) && (sourceUserId == other.sourceUserId)
+ && prefix == other.prefix;
}
return false;
}
@Override
public String toString() {
- if (prefix) {
- return uri.toString() + " [prefix]";
- } else {
- return uri.toString();
- }
+ String result = Integer.toString(sourceUserId) + " @ " + uri.toString();
+ if (prefix) result += " [prefix]";
+ return result;
+ }
+
+ public String toSafeString() {
+ String result = Integer.toString(sourceUserId) + " @ " + uri.toSafeString();
+ if (prefix) result += " [prefix]";
+ return result;
+ }
+
+ public static GrantUri resolve(int defaultSourceUserHandle, Uri uri) {
+ return new GrantUri(ContentProvider.getUserIdFromUri(uri, defaultSourceUserHandle),
+ ContentProvider.getUriWithoutUserId(uri), false);
}
}
@@ -1327,12 +1343,12 @@
String host = "";
String port = "";
String exclList = "";
- String pacFileUrl = null;
+ Uri pacFileUrl = Uri.EMPTY;
if (proxy != null) {
host = proxy.getHost();
port = Integer.toString(proxy.getPort());
exclList = proxy.getExclusionListAsString();
- pacFileUrl = proxy.getPacFileUrl().toString();
+ pacFileUrl = proxy.getPacFileUrl();
}
synchronized (ActivityManagerService.this) {
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
@@ -2904,7 +2920,7 @@
debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
}
- String requiredAbi = app.info.requiredCpuAbi;
+ String requiredAbi = app.info.cpuAbi;
if (requiredAbi == null) {
requiredAbi = Build.SUPPORTED_ABIS[0];
}
@@ -5427,22 +5443,21 @@
}
@Override
- public final void activityPaused(IBinder token) {
+ public final void activityPaused(IBinder token, PersistableBundle persistentState) {
final long origId = Binder.clearCallingIdentity();
synchronized(this) {
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
- stack.activityPausedLocked(token, false);
+ stack.activityPausedLocked(token, false, persistentState);
}
}
Binder.restoreCallingIdentity(origId);
}
@Override
- public final void activityStopped(IBinder token, Bundle icicle, Bitmap thumbnail,
- CharSequence description) {
- if (localLOGV) Slog.v(
- TAG, "Activity stopped: token=" + token);
+ public final void activityStopped(IBinder token, Bundle icicle,
+ PersistableBundle persistentState, CharSequence description) {
+ if (localLOGV) Slog.v(TAG, "Activity stopped: token=" + token);
// Refuse possible leaked file descriptors
if (icicle != null && icicle.hasFileDescriptors()) {
@@ -5454,7 +5469,7 @@
synchronized (this) {
ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
- r.task.stack.activityStoppedLocked(r, icicle, thumbnail, description);
+ r.task.stack.activityStoppedLocked(r, icicle, persistentState, description);
}
}
@@ -5991,9 +6006,9 @@
* in {@link ContentProvider}.
*/
private final boolean checkHoldingPermissionsLocked(
- IPackageManager pm, ProviderInfo pi, Uri uri, int uid, final int modeFlags) {
+ IPackageManager pm, ProviderInfo pi, GrantUri grantUri, int uid, final int modeFlags) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
- "checkHoldingPermissionsLocked: uri=" + uri + " uid=" + uid);
+ "checkHoldingPermissionsLocked: uri=" + grantUri + " uid=" + uid);
if (pi.applicationInfo.uid == uid) {
return true;
@@ -6022,7 +6037,7 @@
// check if target holds any <path-permission> that match uri
final PathPermission[] pps = pi.pathPermissions;
if (pps != null) {
- final String path = uri.getPath();
+ final String path = grantUri.uri.getPath();
int i = pps.length;
while (i > 0 && (!readMet || !writeMet)) {
i--;
@@ -6087,32 +6102,33 @@
return pi;
}
- private UriPermission findUriPermissionLocked(int targetUid, GrantUri uri) {
+ private UriPermission findUriPermissionLocked(int targetUid, GrantUri grantUri) {
final ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
if (targetUris != null) {
- return targetUris.get(uri);
+ return targetUris.get(grantUri);
}
return null;
}
private UriPermission findOrCreateUriPermissionLocked(String sourcePkg,
- String targetPkg, int targetUid, GrantUri uri) {
+ String targetPkg, int targetUid, GrantUri grantUri) {
ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
if (targetUris == null) {
targetUris = Maps.newArrayMap();
mGrantedUriPermissions.put(targetUid, targetUris);
}
- UriPermission perm = targetUris.get(uri);
+ UriPermission perm = targetUris.get(grantUri);
if (perm == null) {
- perm = new UriPermission(sourcePkg, targetPkg, targetUid, uri);
- targetUris.put(uri, perm);
+ perm = new UriPermission(sourcePkg, targetPkg, targetUid, grantUri);
+ targetUris.put(grantUri, perm);
}
return perm;
}
- private final boolean checkUriPermissionLocked(Uri uri, int uid, final int modeFlags) {
+ private final boolean checkUriPermissionLocked(GrantUri grantUri, int uid,
+ final int modeFlags) {
final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
final int minStrength = persistable ? UriPermission.STRENGTH_PERSISTABLE
: UriPermission.STRENGTH_OWNED;
@@ -6126,7 +6142,7 @@
if (perms == null) return false;
// First look for exact match
- final UriPermission exactPerm = perms.get(new GrantUri(uri, false));
+ final UriPermission exactPerm = perms.get(grantUri);
if (exactPerm != null && exactPerm.getStrength(modeFlags) >= minStrength) {
return true;
}
@@ -6135,7 +6151,7 @@
final int N = perms.size();
for (int i = 0; i < N; i++) {
final UriPermission perm = perms.valueAt(i);
- if (perm.uri.prefix && uri.isPathPrefixMatch(perm.uri.uri)
+ if (perm.uri.prefix && grantUri.uri.isPathPrefixMatch(perm.uri.uri)
&& perm.getStrength(modeFlags) >= minStrength) {
return true;
}
@@ -6145,7 +6161,8 @@
}
@Override
- public int checkUriPermission(Uri uri, int pid, int uid, final int modeFlags) {
+ public int checkUriPermission(Uri uri, int pid, int uid,
+ final int modeFlags, int userId) {
enforceNotIsolatedCaller("checkUriPermission");
// Another redirected-binder-call permissions check as in
@@ -6161,7 +6178,7 @@
return PackageManager.PERMISSION_GRANTED;
}
synchronized (this) {
- return checkUriPermissionLocked(uri, uid, modeFlags)
+ return checkUriPermissionLocked(new GrantUri(userId, uri, false), uid, modeFlags)
? PackageManager.PERMISSION_GRANTED
: PackageManager.PERMISSION_DENIED;
}
@@ -6176,30 +6193,31 @@
* If you already know the uid of the target, you can supply it in
* lastTargetUid else set that to -1.
*/
- int checkGrantUriPermissionLocked(int callingUid, String targetPkg,
- Uri uri, final int modeFlags, int lastTargetUid) {
+ int checkGrantUriPermissionLocked(int callingUid, String targetPkg, GrantUri grantUri,
+ final int modeFlags, int lastTargetUid) {
if (!Intent.isAccessUriMode(modeFlags)) {
return -1;
}
if (targetPkg != null) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
- "Checking grant " + targetPkg + " permission to " + uri);
+ "Checking grant " + targetPkg + " permission to " + grantUri);
}
final IPackageManager pm = AppGlobals.getPackageManager();
// If this is not a content: uri, we can't do anything with it.
- if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
+ if (!ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
- "Can't grant URI permission for non-content URI: " + uri);
+ "Can't grant URI permission for non-content URI: " + grantUri);
return -1;
}
- final String authority = uri.getAuthority();
- final ProviderInfo pi = getProviderInfoLocked(authority, UserHandle.getUserId(callingUid));
+ final String authority = grantUri.uri.getAuthority();
+ final ProviderInfo pi = getProviderInfoLocked(authority, grantUri.sourceUserId);
if (pi == null) {
- Slog.w(TAG, "No content provider found for permission check: " + uri.toSafeString());
+ Slog.w(TAG, "No content provider found for permission check: " +
+ grantUri.uri.toSafeString());
return -1;
}
@@ -6219,10 +6237,10 @@
if (targetUid >= 0) {
// First... does the target actually need this permission?
- if (checkHoldingPermissionsLocked(pm, pi, uri, targetUid, modeFlags)) {
+ if (checkHoldingPermissionsLocked(pm, pi, grantUri, targetUid, modeFlags)) {
// No need to grant the target this permission.
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
- "Target " + targetPkg + " already has full permission to " + uri);
+ "Target " + targetPkg + " already has full permission to " + grantUri);
return -1;
}
} else {
@@ -6248,14 +6266,14 @@
throw new SecurityException("Provider " + pi.packageName
+ "/" + pi.name
+ " does not allow granting of Uri permissions (uri "
- + uri + ")");
+ + grantUri + ")");
}
if (pi.uriPermissionPatterns != null) {
final int N = pi.uriPermissionPatterns.length;
boolean allowed = false;
for (int i=0; i<N; i++) {
if (pi.uriPermissionPatterns[i] != null
- && pi.uriPermissionPatterns[i].match(uri.getPath())) {
+ && pi.uriPermissionPatterns[i].match(grantUri.uri.getPath())) {
allowed = true;
break;
}
@@ -6264,35 +6282,35 @@
throw new SecurityException("Provider " + pi.packageName
+ "/" + pi.name
+ " does not allow granting of permission to path of Uri "
- + uri);
+ + grantUri);
}
}
// Third... does the caller itself have permission to access
// this uri?
- if (callingUid != Process.myUid()) {
- if (!checkHoldingPermissionsLocked(pm, pi, uri, callingUid, modeFlags)) {
+ if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
+ if (!checkHoldingPermissionsLocked(pm, pi, grantUri, callingUid, modeFlags)) {
// Require they hold a strong enough Uri permission
- if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
+ if (!checkUriPermissionLocked(grantUri, callingUid, modeFlags)) {
throw new SecurityException("Uid " + callingUid
- + " does not have permission to uri " + uri);
+ + " does not have permission to uri " + grantUri);
}
}
}
-
return targetUid;
}
@Override
- public int checkGrantUriPermission(int callingUid, String targetPkg,
- Uri uri, final int modeFlags) {
+ public int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri,
+ final int modeFlags, int userId) {
enforceNotIsolatedCaller("checkGrantUriPermission");
synchronized(this) {
- return checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags, -1);
+ return checkGrantUriPermissionLocked(callingUid, targetPkg,
+ new GrantUri(userId, uri, false), modeFlags, -1);
}
}
- void grantUriPermissionUncheckedLocked(int targetUid, String targetPkg, Uri uri,
+ void grantUriPermissionUncheckedLocked(int targetUid, String targetPkg, GrantUri grantUri,
final int modeFlags, UriPermissionOwner owner) {
if (!Intent.isAccessUriMode(modeFlags)) {
return;
@@ -6303,36 +6321,40 @@
// the target.
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
- "Granting " + targetPkg + "/" + targetUid + " permission to " + uri);
+ "Granting " + targetPkg + "/" + targetUid + " permission to " + grantUri);
- final String authority = uri.getAuthority();
- final ProviderInfo pi = getProviderInfoLocked(authority, UserHandle.getUserId(targetUid));
+ final String authority = grantUri.uri.getAuthority();
+ final ProviderInfo pi = getProviderInfoLocked(authority, grantUri.sourceUserId);
if (pi == null) {
- Slog.w(TAG, "No content provider found for grant: " + uri.toSafeString());
+ Slog.w(TAG, "No content provider found for grant: " + grantUri.toSafeString());
return;
}
- final boolean prefix = (modeFlags & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) != 0;
+ if ((modeFlags & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) != 0) {
+ grantUri.prefix = true;
+ }
final UriPermission perm = findOrCreateUriPermissionLocked(
- pi.packageName, targetPkg, targetUid, new GrantUri(uri, prefix));
+ pi.packageName, targetPkg, targetUid, grantUri);
perm.grantModes(modeFlags, owner);
}
- void grantUriPermissionLocked(int callingUid, String targetPkg, Uri uri,
+ void grantUriPermissionLocked(int callingUid, String targetPkg, GrantUri grantUri,
final int modeFlags, UriPermissionOwner owner) {
if (targetPkg == null) {
throw new NullPointerException("targetPkg");
}
- int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags, -1);
+ int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, modeFlags,
+ -1);
if (targetUid < 0) {
return;
}
- grantUriPermissionUncheckedLocked(targetUid, targetPkg, uri, modeFlags, owner);
+ grantUriPermissionUncheckedLocked(targetUid, targetPkg, grantUri, modeFlags,
+ owner);
}
- static class NeededUriGrants extends ArrayList<Uri> {
+ static class NeededUriGrants extends ArrayList<GrantUri> {
final String targetPkg;
final int targetUid;
final int flags;
@@ -6369,13 +6391,14 @@
}
if (data != null) {
- int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, data,
- mode, needed != null ? needed.targetUid : -1);
+ GrantUri grantUri = GrantUri.resolve(UserHandle.getUserId(callingUid), data);
+ int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, mode,
+ needed != null ? needed.targetUid : -1);
if (targetUid > 0) {
if (needed == null) {
needed = new NeededUriGrants(targetPkg, targetUid, mode);
}
- needed.add(data);
+ needed.add(grantUri);
}
}
if (clip != null) {
@@ -6383,13 +6406,14 @@
Uri uri = clip.getItemAt(i).getUri();
if (uri != null) {
int targetUid = -1;
- targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, uri,
- mode, needed != null ? needed.targetUid : -1);
+ GrantUri grantUri = GrantUri.resolve(UserHandle.getUserId(callingUid), uri);
+ targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, grantUri, mode,
+ needed != null ? needed.targetUid : -1);
if (targetUid > 0) {
if (needed == null) {
needed = new NeededUriGrants(targetPkg, targetUid, mode);
}
- needed.add(uri);
+ needed.add(grantUri);
}
} else {
Intent clipIntent = clip.getItemAt(i).getIntent();
@@ -6414,8 +6438,9 @@
UriPermissionOwner owner) {
if (needed != null) {
for (int i=0; i<needed.size(); i++) {
+ GrantUri grantUri = needed.get(i);
grantUriPermissionUncheckedLocked(needed.targetUid, needed.targetPkg,
- needed.get(i), needed.flags, owner);
+ grantUri, needed.flags, owner);
}
}
}
@@ -6432,20 +6457,21 @@
}
@Override
- public void grantUriPermission(IApplicationThread caller, String targetPkg,
- Uri uri, final int modeFlags) {
+ public void grantUriPermission(IApplicationThread caller, String targetPkg, Uri uri,
+ final int modeFlags, int userId) {
enforceNotIsolatedCaller("grantUriPermission");
+ GrantUri grantUri = new GrantUri(userId, uri, false);
synchronized(this) {
final ProcessRecord r = getRecordForAppLocked(caller);
if (r == null) {
throw new SecurityException("Unable to find app for caller "
+ caller
- + " when granting permission to uri " + uri);
+ + " when granting permission to uri " + grantUri);
}
if (targetPkg == null) {
throw new IllegalArgumentException("null target");
}
- if (uri == null) {
+ if (grantUri == null) {
throw new IllegalArgumentException("null uri");
}
@@ -6454,7 +6480,7 @@
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
| Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
- grantUriPermissionLocked(r.uid, targetPkg, uri, modeFlags, null);
+ grantUriPermissionLocked(r.uid, targetPkg, grantUri, modeFlags, null);
}
}
@@ -6474,24 +6500,25 @@
}
}
- private void revokeUriPermissionLocked(int callingUid, Uri uri, final int modeFlags) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Revoking all granted permissions to " + uri);
+ private void revokeUriPermissionLocked(int callingUid, GrantUri grantUri, final int modeFlags) {
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Revoking all granted permissions to " + grantUri);
final IPackageManager pm = AppGlobals.getPackageManager();
- final String authority = uri.getAuthority();
- final ProviderInfo pi = getProviderInfoLocked(authority, UserHandle.getUserId(callingUid));
+ final String authority = grantUri.uri.getAuthority();
+ final ProviderInfo pi = getProviderInfoLocked(authority, grantUri.sourceUserId);
if (pi == null) {
- Slog.w(TAG, "No content provider found for permission revoke: " + uri.toSafeString());
+ Slog.w(TAG, "No content provider found for permission revoke: "
+ + grantUri.toSafeString());
return;
}
// Does the caller have this permission on the URI?
- if (!checkHoldingPermissionsLocked(pm, pi, uri, callingUid, modeFlags)) {
+ if (!checkHoldingPermissionsLocked(pm, pi, grantUri, callingUid, modeFlags)) {
// Right now, if you are not the original owner of the permission,
// you are not allowed to revoke it.
//if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
throw new SecurityException("Uid " + callingUid
- + " does not have permission to uri " + uri);
+ + " does not have permission to uri " + grantUri);
//}
}
@@ -6505,7 +6532,8 @@
for (Iterator<UriPermission> it = perms.values().iterator(); it.hasNext();) {
final UriPermission perm = it.next();
- if (perm.uri.uri.isPathPrefixMatch(uri)) {
+ if (perm.uri.sourceUserId == grantUri.sourceUserId
+ && perm.uri.uri.isPathPrefixMatch(grantUri.uri)) {
if (DEBUG_URI_PERMISSION)
Slog.v(TAG,
"Revoking " + perm.targetUid + " permission to " + perm.uri);
@@ -6530,8 +6558,8 @@
}
@Override
- public void revokeUriPermission(IApplicationThread caller, Uri uri,
- final int modeFlags) {
+ public void revokeUriPermission(IApplicationThread caller, Uri uri, final int modeFlags,
+ int userId) {
enforceNotIsolatedCaller("revokeUriPermission");
synchronized(this) {
final ProcessRecord r = getRecordForAppLocked(caller);
@@ -6551,14 +6579,14 @@
final IPackageManager pm = AppGlobals.getPackageManager();
final String authority = uri.getAuthority();
- final ProviderInfo pi = getProviderInfoLocked(authority, r.userId);
+ final ProviderInfo pi = getProviderInfoLocked(authority, userId);
if (pi == null) {
Slog.w(TAG, "No content provider found for permission revoke: "
+ uri.toSafeString());
return;
}
- revokeUriPermissionLocked(r.uid, uri, modeFlags);
+ revokeUriPermissionLocked(r.uid, new GrantUri(userId, uri, false), modeFlags);
}
}
@@ -6628,8 +6656,8 @@
}
@Override
- public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg,
- Uri uri, final int modeFlags) {
+ public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg, Uri uri,
+ final int modeFlags, int userId) {
synchronized(this) {
UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
if (owner == null) {
@@ -6649,12 +6677,13 @@
throw new IllegalArgumentException("null uri");
}
- grantUriPermissionLocked(fromUid, targetPkg, uri, modeFlags, owner);
+ grantUriPermissionLocked(fromUid, targetPkg, new GrantUri(userId, uri, false),
+ modeFlags, owner);
}
}
@Override
- public void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode) {
+ public void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode, int userId) {
synchronized(this) {
UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
if (owner == null) {
@@ -6664,7 +6693,7 @@
if (uri == null) {
owner.removeUriPermissionsLocked(mode);
} else {
- owner.removeUriPermissionLocked(uri, mode);
+ owner.removeUriPermissionLocked(new GrantUri(userId, uri, false), mode);
}
}
}
@@ -6703,7 +6732,8 @@
out.startTag(null, TAG_URI_GRANTS);
for (UriPermission.Snapshot perm : persist) {
out.startTag(null, TAG_URI_GRANT);
- writeIntAttribute(out, ATTR_USER_HANDLE, perm.userHandle);
+ writeIntAttribute(out, ATTR_SOURCE_USER_ID, perm.uri.sourceUserId);
+ writeIntAttribute(out, ATTR_TARGET_USER_ID, perm.targetUserId);
out.attribute(null, ATTR_SOURCE_PKG, perm.sourcePkg);
out.attribute(null, ATTR_TARGET_PKG, perm.targetPkg);
out.attribute(null, ATTR_URI, String.valueOf(perm.uri.uri));
@@ -6739,7 +6769,18 @@
final String tag = in.getName();
if (type == START_TAG) {
if (TAG_URI_GRANT.equals(tag)) {
- final int userHandle = readIntAttribute(in, ATTR_USER_HANDLE);
+ final int sourceUserId;
+ final int targetUserId;
+ final int userHandle = readIntAttribute(in,
+ ATTR_USER_HANDLE, UserHandle.USER_NULL);
+ if (userHandle != UserHandle.USER_NULL) {
+ // For backwards compatibility.
+ sourceUserId = userHandle;
+ targetUserId = userHandle;
+ } else {
+ sourceUserId = readIntAttribute(in, ATTR_SOURCE_USER_ID);
+ targetUserId = readIntAttribute(in, ATTR_TARGET_USER_ID);
+ }
final String sourcePkg = in.getAttributeValue(null, ATTR_SOURCE_PKG);
final String targetPkg = in.getAttributeValue(null, ATTR_TARGET_PKG);
final Uri uri = Uri.parse(in.getAttributeValue(null, ATTR_URI));
@@ -6749,17 +6790,18 @@
// Sanity check that provider still belongs to source package
final ProviderInfo pi = getProviderInfoLocked(
- uri.getAuthority(), userHandle);
+ uri.getAuthority(), sourceUserId);
if (pi != null && sourcePkg.equals(pi.packageName)) {
int targetUid = -1;
try {
targetUid = AppGlobals.getPackageManager()
- .getPackageUid(targetPkg, userHandle);
+ .getPackageUid(targetPkg, targetUserId);
} catch (RemoteException e) {
}
if (targetUid != -1) {
final UriPermission perm = findOrCreateUriPermissionLocked(
- sourcePkg, targetPkg, targetUid, new GrantUri(uri, prefix));
+ sourcePkg, targetPkg, targetUid,
+ new GrantUri(sourceUserId, uri, prefix));
perm.initPersistedModes(modeFlags, createdTime);
}
} else {
@@ -6781,7 +6823,7 @@
}
@Override
- public void takePersistableUriPermission(Uri uri, final int modeFlags) {
+ public void takePersistableUriPermission(Uri uri, final int modeFlags, int userId) {
enforceNotIsolatedCaller("takePersistableUriPermission");
Preconditions.checkFlagsArgument(modeFlags,
@@ -6790,9 +6832,12 @@
synchronized (this) {
final int callingUid = Binder.getCallingUid();
boolean persistChanged = false;
+ GrantUri grantUri = new GrantUri(userId, uri, false);
- UriPermission exactPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, false));
- UriPermission prefixPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, true));
+ UriPermission exactPerm = findUriPermissionLocked(callingUid,
+ new GrantUri(userId, uri, false));
+ UriPermission prefixPerm = findUriPermissionLocked(callingUid,
+ new GrantUri(userId, uri, true));
final boolean exactValid = (exactPerm != null)
&& ((modeFlags & exactPerm.persistableModeFlags) == modeFlags);
@@ -6801,7 +6846,7 @@
if (!(exactValid || prefixValid)) {
throw new SecurityException("No persistable permission grants found for UID "
- + callingUid + " and Uri " + uri.toSafeString());
+ + callingUid + " and Uri " + grantUri.toSafeString());
}
if (exactValid) {
@@ -6820,7 +6865,7 @@
}
@Override
- public void releasePersistableUriPermission(Uri uri, final int modeFlags) {
+ public void releasePersistableUriPermission(Uri uri, final int modeFlags, int userId) {
enforceNotIsolatedCaller("releasePersistableUriPermission");
Preconditions.checkFlagsArgument(modeFlags,
@@ -6830,8 +6875,10 @@
final int callingUid = Binder.getCallingUid();
boolean persistChanged = false;
- UriPermission exactPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, false));
- UriPermission prefixPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, true));
+ UriPermission exactPerm = findUriPermissionLocked(callingUid,
+ new GrantUri(userId, uri, false));
+ UriPermission prefixPerm = findUriPermissionLocked(callingUid,
+ new GrantUri(userId, uri, true));
if (exactPerm == null && prefixPerm == null) {
throw new SecurityException("No permission grants found for UID " + callingUid
+ " and Uri " + uri.toSafeString());
@@ -6973,6 +7020,33 @@
// =========================================================
@Override
+ public List<IAppTask> getAppTasks() {
+ int callingUid = Binder.getCallingUid();
+ long ident = Binder.clearCallingIdentity();
+ synchronized(this) {
+ ArrayList<IAppTask> list = new ArrayList<IAppTask>();
+ try {
+ if (localLOGV) Slog.v(TAG, "getAppTasks");
+
+ final int N = mRecentTasks.size();
+ for (int i = 0; i < N; i++) {
+ TaskRecord tr = mRecentTasks.get(i);
+ // Skip tasks that are not created by the caller
+ if (tr.creatorUid == callingUid) {
+ ActivityManager.RecentTaskInfo taskInfo =
+ createRecentTaskInfoFromTaskRecord(tr);
+ AppTaskImpl taskImpl = new AppTaskImpl(taskInfo.persistentId, callingUid);
+ list.add(taskImpl);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ return list;
+ }
+ }
+
+ @Override
public List<RunningTaskInfo> getTasks(int maxNum, int flags) {
final int callingUid = Binder.getCallingUid();
ArrayList<RunningTaskInfo> list = new ArrayList<RunningTaskInfo>();
@@ -7000,6 +7074,66 @@
return mRecentTasks.get(0);
}
+ /**
+ * Creates a new RecentTaskInfo from a TaskRecord.
+ */
+ private ActivityManager.RecentTaskInfo createRecentTaskInfoFromTaskRecord(TaskRecord tr) {
+ ActivityManager.RecentTaskInfo rti
+ = new ActivityManager.RecentTaskInfo();
+ rti.id = tr.numActivities > 0 ? tr.taskId : -1;
+ rti.persistentId = tr.taskId;
+ rti.baseIntent = new Intent(tr.getBaseIntent());
+ rti.origActivity = tr.origActivity;
+ rti.description = tr.lastDescription;
+ rti.stackId = tr.stack.mStackId;
+ rti.userId = tr.userId;
+
+ // Traverse upwards looking for any break between main task activities and
+ // utility activities.
+ final ArrayList<ActivityRecord> activities = tr.mActivities;
+ int activityNdx;
+ final int numActivities = activities.size();
+ for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
+ ++activityNdx) {
+ final ActivityRecord r = activities.get(activityNdx);
+ if (r.intent != null &&
+ (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
+ != 0) {
+ break;
+ }
+ }
+ if (activityNdx > 0) {
+ // Traverse downwards starting below break looking for set label, icon.
+ // Note that if there are activities in the task but none of them set the
+ // recent activity values, then we do not fall back to the last set
+ // values in the TaskRecord.
+ rti.activityValues = new ActivityManager.RecentsActivityValues();
+ for (--activityNdx; activityNdx >= 0; --activityNdx) {
+ final ActivityRecord r = activities.get(activityNdx);
+ if (r.activityValues != null) {
+ if (rti.activityValues.label == null) {
+ rti.activityValues.label = r.activityValues.label;
+ tr.lastActivityValues.label = r.activityValues.label;
+ }
+ if (rti.activityValues.icon == null) {
+ rti.activityValues.icon = r.activityValues.icon;
+ tr.lastActivityValues.icon = r.activityValues.icon;
+ }
+ if (rti.activityValues.colorPrimary == 0) {
+ rti.activityValues.colorPrimary = r.activityValues.colorPrimary;
+ tr.lastActivityValues.colorPrimary = r.activityValues.colorPrimary;
+ }
+ }
+ }
+ } else {
+ // If there are no activity records in this task, then we use the last
+ // resolved values
+ rti.activityValues =
+ new ActivityManager.RecentsActivityValues(tr.lastActivityValues);
+ }
+ return rti;
+ }
+
@Override
public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
int flags, int userId) {
@@ -7056,63 +7190,11 @@
continue;
}
}
- ActivityManager.RecentTaskInfo rti
- = new ActivityManager.RecentTaskInfo();
- rti.id = tr.numActivities > 0 ? tr.taskId : -1;
- rti.persistentId = tr.taskId;
- rti.baseIntent = new Intent(
- tr.intent != null ? tr.intent : tr.affinityIntent);
+
+ ActivityManager.RecentTaskInfo rti = createRecentTaskInfoFromTaskRecord(tr);
if (!detailed) {
rti.baseIntent.replaceExtras((Bundle)null);
}
- rti.origActivity = tr.origActivity;
- rti.description = tr.lastDescription;
- rti.stackId = tr.stack.mStackId;
- rti.userId = tr.userId;
-
- // Traverse upwards looking for any break between main task activities and
- // utility activities.
- final ArrayList<ActivityRecord> activities = tr.mActivities;
- int activityNdx;
- final int numActivities = activities.size();
- for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
- ++activityNdx) {
- final ActivityRecord r = activities.get(activityNdx);
- if (r.intent != null &&
- (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
- != 0) {
- break;
- }
- }
- if (activityNdx > 0) {
- // Traverse downwards starting below break looking for set label, icon.
- // Note that if there are activities in the task but none of them set the
- // recent activity values, then we do not fall back to the last set
- // values in the TaskRecord.
- rti.activityValues = new ActivityManager.RecentsActivityValues();
- for (--activityNdx; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = activities.get(activityNdx);
- if (r.activityValues != null) {
- if (rti.activityValues.label == null) {
- rti.activityValues.label = r.activityValues.label;
- tr.lastActivityValues.label = r.activityValues.label;
- }
- if (rti.activityValues.icon == null) {
- rti.activityValues.icon = r.activityValues.icon;
- tr.lastActivityValues.icon = r.activityValues.icon;
- }
- if (rti.activityValues.colorPrimary == 0) {
- rti.activityValues.colorPrimary = r.activityValues.colorPrimary;
- tr.lastActivityValues.colorPrimary = r.activityValues.colorPrimary;
- }
- }
- }
- } else {
- // If there are no activity records in this task, then we use the last
- // resolved values
- rti.activityValues =
- new ActivityManager.RecentsActivityValues(tr.lastActivityValues);
- }
if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0) {
// Check whether this activity is currently available.
@@ -7676,9 +7758,25 @@
* in {@link ContentProvider}.
*/
private final String checkContentProviderPermissionLocked(
- ProviderInfo cpi, ProcessRecord r) {
+ ProviderInfo cpi, ProcessRecord r, int userId) {
final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
final int callingUid = (r != null) ? r.uid : Binder.getCallingUid();
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
+ // Looking for cross-user grants before to enforce the typical cross-users permissions
+ if (userId != UserHandle.getUserId(callingUid)) {
+ if (perms != null) {
+ for (GrantUri grantUri : perms.keySet()) {
+ if (grantUri.sourceUserId == userId) {
+ String authority = grantUri.uri.getAuthority();
+ if (authority.equals(cpi.authority)) {
+ return null;
+ }
+ }
+ }
+ }
+ }
+ userId = handleIncomingUser(callingPid, callingUid, userId,
+ false, true, "checkContentProviderPermissionLocked", null);
if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
cpi.applicationInfo.uid, cpi.exported)
== PackageManager.PERMISSION_GRANTED) {
@@ -7709,10 +7807,9 @@
}
}
- final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
if (perms != null) {
- for (GrantUri uri : perms.keySet()) {
- if (uri.uri.getAuthority().equals(cpi.authority)) {
+ for (GrantUri grantUri : perms.keySet()) {
+ if (grantUri.uri.getAuthority().equals(cpi.authority)) {
return null;
}
}
@@ -7820,7 +7917,7 @@
if (providerRunning) {
cpi = cpr.info;
String msg;
- if ((msg=checkContentProviderPermissionLocked(cpi, r)) != null) {
+ if ((msg=checkContentProviderPermissionLocked(cpi, r, userId)) != null) {
throw new SecurityException(msg);
}
@@ -7908,7 +8005,7 @@
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
String msg;
- if ((msg=checkContentProviderPermissionLocked(cpi, r)) != null) {
+ if ((msg=checkContentProviderPermissionLocked(cpi, r, userId)) != null) {
throw new SecurityException(msg);
}
@@ -8074,6 +8171,7 @@
return cpr != null ? cpr.newHolder(conn) : null;
}
+ @Override
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name, int userId, boolean stable) {
enforceNotIsolatedCaller("getContentProvider");
@@ -8083,9 +8181,8 @@
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
-
- userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
- false, true, "getContentProvider", null);
+ // The incoming user check is now handled in checkContentProviderPermissionLocked() to deal
+ // with cross-user grant.
return getContentProviderImpl(caller, name, null, stable, userId);
}
@@ -9026,7 +9123,7 @@
}
@Override
- public boolean convertToTranslucent(IBinder token) {
+ public boolean convertToTranslucent(IBinder token, ActivityOptions options) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (this) {
@@ -9035,7 +9132,7 @@
return false;
}
if (r.changeWindowTranslucency(false)) {
- r.task.stack.convertToTranslucent(r);
+ r.task.stack.convertToTranslucent(r, options);
mWindowManager.setAppFullscreen(token, false);
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
return true;
@@ -9048,6 +9145,24 @@
}
@Override
+ public ActivityOptions getActivityOptions(IBinder token) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r != null) {
+ final ActivityOptions activityOptions = r.pendingOptions;
+ r.pendingOptions = null;
+ return activityOptions;
+ }
+ return null;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
public void setImmersive(IBinder token, boolean immersive) {
synchronized(this) {
final ActivityRecord r = ActivityRecord.isInStackLocked(token);
@@ -17095,4 +17210,69 @@
ActivityManagerService.this.wakingUp();
}
}
+
+ /**
+ * An implementation of IAppTask, that allows an app to manage its own tasks via
+ * {@link android.app.ActivityManager#AppTask}. We keep track of the callingUid to ensure that
+ * only the process that calls getAppTasks() can call the AppTask methods.
+ */
+ class AppTaskImpl extends IAppTask.Stub {
+ private int mTaskId;
+ private int mCallingUid;
+
+ public AppTaskImpl(int taskId, int callingUid) {
+ mTaskId = taskId;
+ mCallingUid = callingUid;
+ }
+
+ @Override
+ public void finishAndRemoveTask() {
+ // Ensure that we are called from the same process that created this AppTask
+ if (mCallingUid != Binder.getCallingUid()) {
+ Slog.w(TAG, "finishAndRemoveTask: caller " + mCallingUid
+ + " does not match caller of getAppTasks(): " + Binder.getCallingUid());
+ return;
+ }
+
+ synchronized (ActivityManagerService.this) {
+ long origId = Binder.clearCallingIdentity();
+ try {
+ TaskRecord tr = recentTaskForIdLocked(mTaskId);
+ if (tr != null) {
+ // Only kill the process if we are not a new document
+ int flags = tr.getBaseIntent().getFlags();
+ boolean isDocument = (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) ==
+ Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+ removeTaskByIdLocked(mTaskId,
+ !isDocument ? ActivityManager.REMOVE_TASK_KILL_PROCESS : 0);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
+
+ @Override
+ public ActivityManager.RecentTaskInfo getTaskInfo() {
+ // Ensure that we are called from the same process that created this AppTask
+ if (mCallingUid != Binder.getCallingUid()) {
+ Slog.w(TAG, "finishAndRemoveTask: caller " + mCallingUid
+ + " does not match caller of getAppTasks(): " + Binder.getCallingUid());
+ return null;
+ }
+
+ synchronized (ActivityManagerService.this) {
+ long origId = Binder.clearCallingIdentity();
+ try {
+ TaskRecord tr = recentTaskForIdLocked(mTaskId);
+ if (tr != null) {
+ return createRecentTaskInfoFromTaskRecord(tr);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ return null;
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index efd2b57..9582ac7 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.os.PersistableBundle;
import android.os.Trace;
import com.android.internal.app.ResolverActivity;
import com.android.server.AttributeCache;
@@ -117,6 +118,7 @@
ProcessRecord app; // if non-null, hosting application
ActivityState state; // current state we are in
Bundle icicle; // last saved activity state
+ PersistableBundle persistentState; // last persistently saved activity state
boolean frontOfTask; // is this the root activity of its task?
boolean launchFailed; // set if a launched failed, to abort on 2nd try
boolean haveState; // have we gotten the last activity state?
@@ -345,7 +347,7 @@
ActivityInfo aInfo, Configuration _configuration,
ActivityRecord _resultTo, String _resultWho, int _reqCode,
boolean _componentSpecified, ActivityStackSupervisor supervisor,
- ActivityContainer container) {
+ ActivityContainer container, Bundle options) {
service = _service;
appToken = new Token(this);
info = aInfo;
@@ -376,6 +378,9 @@
hasBeenLaunched = false;
mStackSupervisor = supervisor;
mInitialActivityContainer = container;
+ if (options != null) {
+ pendingOptions = new ActivityOptions(options);
+ }
// This starts out true, since the initial state of an activity
// is that we have everything, and we shouldn't never consider it
@@ -709,6 +714,9 @@
+ pendingOptions.getThumbnail().getHeight()));
}
break;
+ default:
+ Slog.e(TAG, "applyOptionsLocked: Unknown animationType=" + animationType);
+ break;
}
pendingOptions = null;
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 442da31..c1e5e5b 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -68,6 +68,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
@@ -204,6 +205,9 @@
ActivityRecord mTranslucentActivityWaiting = null;
ArrayList<ActivityRecord> mUndrawnActivitiesBelowTopTranslucent =
new ArrayList<ActivityRecord>();
+ // Options passed from the caller of the convertToTranslucent to the activity that will
+ // appear below it.
+ ActivityOptions mReturningActivityOptions = null;
/**
* Set when we know we are going to be calling updateConfiguration()
@@ -276,7 +280,7 @@
if (r.app != null) {
mService.logAppTooSlow(r.app, r.pauseTime, "pausing " + r);
}
- activityPausedLocked(r.appToken, true);
+ activityPausedLocked(r.appToken, true, r.persistentState);
}
} break;
case LAUNCH_TICK_MSG: {
@@ -860,13 +864,15 @@
}
}
- final void activityPausedLocked(IBinder token, boolean timeout) {
+ final void activityPausedLocked(IBinder token, boolean timeout,
+ PersistableBundle persistentState) {
if (DEBUG_PAUSE) Slog.v(
TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
final ActivityRecord r = isInStackLocked(token);
if (r != null) {
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
+ r.persistentState = persistentState;
if (mPausingActivity == r) {
if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
+ (timeout ? " (due to timeout)" : " (pause complete)"));
@@ -881,13 +887,14 @@
}
}
- final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail,
- CharSequence description) {
+ final void activityStoppedLocked(ActivityRecord r, Bundle icicle,
+ PersistableBundle persistentState, CharSequence description) {
if (r.state != ActivityState.STOPPING) {
Slog.i(TAG, "Activity reported stop, but no longer stopping: " + r);
mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
return;
}
+ r.persistentState = persistentState;
if (DEBUG_SAVED_STATE) Slog.i(TAG, "Saving icicle of " + r + ": " + icicle);
if (icicle != null) {
// If icicle is null, this is happening due to a timeout, so we
@@ -895,7 +902,7 @@
r.icicle = icicle;
r.haveState = true;
r.launchCount = 0;
- r.updateThumbnail(thumbnail, description);
+ r.updateThumbnail(null, description);
}
if (!r.stopped) {
if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r + " (stop complete)");
@@ -1214,6 +1221,7 @@
TAG, "Making visible and scheduling visibility: " + r);
try {
if (mTranslucentActivityWaiting != null) {
+ r.updateOptionsLocked(mReturningActivityOptions);
mUndrawnActivitiesBelowTopTranslucent.add(r);
}
setVisibile(r, true);
@@ -1291,9 +1299,10 @@
}
}
- void convertToTranslucent(ActivityRecord r) {
+ void convertToTranslucent(ActivityRecord r, ActivityOptions options) {
mTranslucentActivityWaiting = r;
mUndrawnActivitiesBelowTopTranslucent.clear();
+ mReturningActivityOptions = options;
mHandler.sendEmptyMessageDelayed(TRANSLUCENT_TIMEOUT_MSG, TRANSLUCENT_CONVERSION_TIMEOUT);
}
@@ -1417,7 +1426,8 @@
final TaskRecord nextTask = next.task;
final TaskRecord prevTask = prev != null ? prev.task : null;
- if (prevTask != null && prevTask.mOnTopOfHome && prev.finishing && prev.frontOfTask) {
+ if (prevTask != null && prevTask.stack == this &&
+ prevTask.mOnTopOfHome && prev.finishing && prev.frontOfTask) {
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
if (prevTask == nextTask) {
prevTask.setFrontOfTask();
@@ -1466,8 +1476,6 @@
next.sleeping = false;
mStackSupervisor.mWaitingVisibleActivities.remove(next);
- next.updateOptionsLocked(options);
-
if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
// If we are currently pausing an activity, then don't do anything
@@ -1911,7 +1919,6 @@
: AppTransition.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
mNoAnimActivities.remove(r);
}
- r.updateOptionsLocked(options);
mWindowManager.addAppToken(task.mActivities.indexOf(r),
r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
@@ -1962,13 +1969,14 @@
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
r.info.configChanges);
ActivityOptions.abort(options);
+ options = null;
}
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
if (doResume) {
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index ce3d853..5d744e6 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1022,14 +1022,12 @@
}
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);
- Bundle options = (r.pendingOptions == null) ? null : r.pendingOptions.toBundle();
- r.clearOptionsLocked();
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
- new Configuration(mService.mConfiguration), r.compat,
- r.task.voiceInteractor, app.repProcState, r.icicle, results, newIntents,
- !andResume, mService.isNextTransitionForward(), profileFile, profileFd,
- profileAutoStop, options);
+ new Configuration(mService.mConfiguration), r.compat, r.task.voiceInteractor,
+ app.repProcState, r.icicle, r.persistentState, results, newIntents, !andResume,
+ mService.isNextTransitionForward(), profileFile, profileFd, profileAutoStop
+ );
if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
// This may be a heavy-weight process! Note that the package
@@ -1325,7 +1323,7 @@
ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
- requestCode, componentSpecified, this, container);
+ requestCode, componentSpecified, this, container, options);
if (outActivity != null) {
outActivity[0] = r;
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 862932c..be884e7 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -154,6 +154,11 @@
}
}
+ /** Returns the intent for the root activity for this task */
+ Intent getBaseIntent() {
+ return intent != null ? intent : affinityIntent;
+ }
+
/** Returns the first non-finishing activity from the root. */
ActivityRecord getRootActivity() {
for (int i = 0; i < mActivities.size(); i++) {
diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
index 4970b8d..284086d 100644
--- a/services/core/java/com/android/server/am/UriPermission.java
+++ b/services/core/java/com/android/server/am/UriPermission.java
@@ -44,7 +44,7 @@
public static final int STRENGTH_GLOBAL = 2;
public static final int STRENGTH_PERSISTABLE = 3;
- final int userHandle;
+ final int targetUserId;
final String sourcePkg;
final String targetPkg;
@@ -86,7 +86,7 @@
private String stringName;
UriPermission(String sourcePkg, String targetPkg, int targetUid, GrantUri uri) {
- this.userHandle = UserHandle.getUserId(targetUid);
+ this.targetUserId = UserHandle.getUserId(targetUid);
this.sourcePkg = sourcePkg;
this.targetPkg = targetPkg;
this.targetUid = targetUid;
@@ -307,7 +307,7 @@
void dump(PrintWriter pw, String prefix) {
pw.print(prefix);
- pw.print("userHandle=" + userHandle);
+ pw.print("targetUserId=" + targetUserId);
pw.print(" sourcePkg=" + sourcePkg);
pw.println(" targetPkg=" + targetPkg);
@@ -352,7 +352,7 @@
* {@link UriPermission#persistedModeFlags} state.
*/
public static class Snapshot {
- final int userHandle;
+ final int targetUserId;
final String sourcePkg;
final String targetPkg;
final GrantUri uri;
@@ -360,7 +360,7 @@
final long persistedCreateTime;
private Snapshot(UriPermission perm) {
- this.userHandle = perm.userHandle;
+ this.targetUserId = perm.targetUserId;
this.sourcePkg = perm.sourcePkg;
this.targetPkg = perm.targetPkg;
this.uri = perm.uri;
diff --git a/services/core/java/com/android/server/am/UriPermissionOwner.java b/services/core/java/com/android/server/am/UriPermissionOwner.java
index 65d7047..ae83940 100644
--- a/services/core/java/com/android/server/am/UriPermissionOwner.java
+++ b/services/core/java/com/android/server/am/UriPermissionOwner.java
@@ -70,13 +70,13 @@
removeUriPermissionLocked(null, mode);
}
- void removeUriPermissionLocked(Uri uri, int mode) {
+ void removeUriPermissionLocked(ActivityManagerService.GrantUri grantUri, int mode) {
if ((mode & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0
&& mReadPerms != null) {
Iterator<UriPermission> it = mReadPerms.iterator();
while (it.hasNext()) {
UriPermission perm = it.next();
- if (uri == null || uri.equals(perm.uri)) {
+ if (grantUri == null || grantUri.equals(perm.uri)) {
perm.removeReadOwner(this);
service.removeUriPermissionIfNeededLocked(perm);
it.remove();
@@ -91,7 +91,7 @@
Iterator<UriPermission> it = mWritePerms.iterator();
while (it.hasNext()) {
UriPermission perm = it.next();
- if (uri == null || uri.equals(perm.uri)) {
+ if (grantUri == null || grantUri.equals(perm.uri)) {
perm.removeWriteOwner(this);
service.removeUriPermissionIfNeededLocked(perm);
it.remove();
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index f47d66d..15e3e89 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -23,6 +23,7 @@
import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ClipDescription;
+import android.content.ContentProvider;
import android.content.IClipboard;
import android.content.IOnPrimaryClipChangedListener;
import android.content.Context;
@@ -255,7 +256,8 @@
long ident = Binder.clearCallingIdentity();
try {
// This will throw SecurityException for us.
- mAm.checkGrantUriPermission(uid, null, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ mAm.checkGrantUriPermission(uid, null, ContentProvider.getUriWithoutUserId(uri),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION, resolveUserId(uri, uid));
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(ident);
@@ -282,8 +284,10 @@
private final void grantUriLocked(Uri uri, String pkg) {
long ident = Binder.clearCallingIdentity();
try {
- mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(), pkg, uri,
- Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(), pkg,
+ ContentProvider.getUriWithoutUserId(uri),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ resolveUserId(uri, Process.myUid()));
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(ident);
@@ -331,9 +335,10 @@
private final void revokeUriLocked(Uri uri) {
long ident = Binder.clearCallingIdentity();
try {
- mAm.revokeUriPermissionFromOwner(mPermissionOwner, uri,
- Intent.FLAG_GRANT_READ_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ mAm.revokeUriPermissionFromOwner(mPermissionOwner,
+ ContentProvider.getUriWithoutUserId(uri),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+ resolveUserId(uri, Process.myUid()));
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(ident);
@@ -361,4 +366,8 @@
revokeItemLocked(clipboard.primaryClip.getItemAt(i));
}
}
+
+ private final int resolveUserId(Uri uri, int uid) {
+ return ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(uid));
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index a15d678..3884ab0 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -25,11 +25,12 @@
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.LinkProperties;
-import android.net.NetworkStateTracker;
+import android.net.NetworkAgent;
import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.os.Handler;
import android.os.Message;
+import android.os.Messenger;
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.util.Slog;
@@ -45,15 +46,18 @@
private Context mContext;
private INetworkManagementService mNMService;
private IConnectivityManager mConnService;
- private NetworkStateTracker mTracker;
- private Handler mHandler;
-
// Whether we started clatd and expect it to be running.
private boolean mIsStarted;
// Whether the clatd interface exists (i.e., clatd is running).
private boolean mIsRunning;
// The LinkProperties of the clat interface.
private LinkProperties mLP;
+ // Current LinkProperties of the network. Includes mLP as a stacked link when clat is active.
+ private LinkProperties mBaseLP;
+ // ConnectivityService Handler for LinkProperties updates.
+ private Handler mHandler;
+ // Marker to connote which network we're augmenting.
+ private Messenger mNetworkMessenger;
// This must match the interface name in clatd.conf.
private static final String CLAT_INTERFACE_NAME = "clat4";
@@ -73,14 +77,13 @@
}
/**
- * Determines whether an interface requires clat.
- * @param netType the network type (one of the
- * android.net.ConnectivityManager.TYPE_* constants)
- * @param tracker the NetworkStateTracker corresponding to the network type.
- * @return true if the interface requires clat, false otherwise.
+ * Determines whether a network requires clat.
+ * @param network the NetworkAgentInfo corresponding to the network.
+ * @return true if the network requires clat, false otherwise.
*/
- public boolean requiresClat(int netType, NetworkStateTracker tracker) {
- LinkProperties lp = tracker.getLinkProperties();
+ public boolean requiresClat(NetworkAgentInfo network) {
+ int netType = network.networkInfo.getType();
+ LinkProperties lp = network.linkProperties;
// Only support clat on mobile for now.
Slog.d(TAG, "requiresClat: netType=" + netType + ", hasIPv4Address=" +
lp.hasIPv4Address());
@@ -95,13 +98,18 @@
* Starts the clat daemon.
* @param lp The link properties of the interface to start clatd on.
*/
- public void startClat(NetworkStateTracker tracker) {
+ public void startClat(NetworkAgentInfo network) {
+ if (mNetworkMessenger != null && mNetworkMessenger != network.messenger) {
+ Slog.e(TAG, "startClat: too many networks requesting clat");
+ return;
+ }
+ mNetworkMessenger = network.messenger;
+ LinkProperties lp = network.linkProperties;
+ mBaseLP = new LinkProperties(lp);
if (mIsStarted) {
Slog.e(TAG, "startClat: already started");
return;
}
- mTracker = tracker;
- LinkProperties lp = mTracker.getLinkProperties();
String iface = lp.getInterfaceName();
Slog.i(TAG, "Starting clatd on " + iface + ", lp=" + lp);
try {
@@ -125,7 +133,8 @@
}
mIsStarted = false;
mIsRunning = false;
- mTracker = null;
+ mNetworkMessenger = null;
+ mBaseLP = null;
mLP.clear();
} else {
Slog.e(TAG, "stopClat: already stopped");
@@ -140,6 +149,14 @@
return mIsRunning;
}
+ private void updateConnectivityService() {
+ Message msg = mHandler.obtainMessage(
+ NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED, mBaseLP);
+ msg.replyTo = mNetworkMessenger;
+ Slog.i(TAG, "sending message to ConnectivityService: " + msg);
+ msg.sendToTarget();
+ }
+
@Override
public void interfaceAdded(String iface) {
if (iface.equals(CLAT_INTERFACE_NAME)) {
@@ -165,19 +182,12 @@
clatAddress.getAddress(), iface);
mLP.addRoute(ipv4Default);
mLP.addLinkAddress(clatAddress);
- mTracker.addStackedLink(mLP);
- Slog.i(TAG, "Adding stacked link. tracker LP: " +
- mTracker.getLinkProperties());
+ mBaseLP.addStackedLink(mLP);
+ Slog.i(TAG, "Adding stacked link. tracker LP: " + mBaseLP);
+ updateConnectivityService();
} catch(RemoteException e) {
Slog.e(TAG, "Error getting link properties: " + e);
}
-
- // Inform ConnectivityService that things have changed.
- Message msg = mHandler.obtainMessage(
- NetworkStateTracker.EVENT_CONFIGURATION_CHANGED,
- mTracker.getNetworkInfo());
- Slog.i(TAG, "sending message to ConnectivityService: " + msg);
- msg.sendToTarget();
}
}
@@ -192,8 +202,9 @@
Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME +
" removed, mIsRunning = " + mIsRunning + " -> false");
mIsRunning = false;
- mTracker.removeStackedLink(mLP);
+ mBaseLP.removeStackedLink(mLP);
mLP.clear();
+ updateConnectivityService();
Slog.i(TAG, "mLP = " + mLP);
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
new file mode 100644
index 0000000..8102591
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import android.content.Context;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkRequest;
+import android.os.Handler;
+import android.os.Messenger;
+import android.util.SparseArray;
+
+import com.android.internal.util.AsyncChannel;
+import com.android.server.connectivity.NetworkMonitor;
+
+import java.util.ArrayList;
+
+/**
+ * A bag class used by ConnectivityService for holding a collection of most recent
+ * information published by a particular NetworkAgent as well as the
+ * AsyncChannel/messenger for reaching that NetworkAgent and lists of NetworkRequests
+ * interested in using it.
+ */
+public class NetworkAgentInfo {
+ public NetworkInfo networkInfo;
+ public final Network network;
+ public LinkProperties linkProperties;
+ public NetworkCapabilities networkCapabilities;
+ public int currentScore;
+ public final NetworkMonitor networkMonitor;
+
+
+ // The list of NetworkRequests being satisfied by this Network.
+ public final SparseArray<NetworkRequest> networkRequests = new SparseArray<NetworkRequest>();
+ public final ArrayList<NetworkRequest> networkLingered = new ArrayList<NetworkRequest>();
+
+ public final Messenger messenger;
+ public final AsyncChannel asyncChannel;
+
+ public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, int netId, NetworkInfo info,
+ LinkProperties lp, NetworkCapabilities nc, int score, Context context,
+ Handler handler) {
+ this.messenger = messenger;
+ asyncChannel = ac;
+ network = new Network(netId);
+ networkInfo = info;
+ linkProperties = lp;
+ networkCapabilities = nc;
+ currentScore = score;
+ networkMonitor = new NetworkMonitor(context, handler, this);
+ }
+
+ public String toString() {
+ return "NetworkAgentInfo{ ni{" + networkInfo + "} network{" +
+ network + "} lp{" +
+ linkProperties + "} nc{" +
+ networkCapabilities + "} Score{" + currentScore + "} }";
+ }
+
+ public String name() {
+ return "NetworkAgentInfo [" + networkInfo.getTypeName() + " (" +
+ networkInfo.getSubtypeName() + ")]";
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
new file mode 100644
index 0000000..47789b1
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import android.content.Context;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemProperties;
+import android.provider.Settings;
+
+import com.android.internal.util.Protocol;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+import com.android.server.connectivity.NetworkAgentInfo;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.URL;
+
+/**
+ * {@hide}
+ */
+public class NetworkMonitor extends StateMachine {
+ private static final boolean DBG = true;
+ private static final String TAG = "NetworkMonitor";
+ private static final String DEFAULT_SERVER = "clients3.google.com";
+ private static final int SOCKET_TIMEOUT_MS = 10000;
+
+ private static final int BASE = Protocol.BASE_NETWORK_MONITOR;
+
+ /**
+ * Inform NetworkMonitor that their network is connected.
+ * Initiates Network Validation.
+ */
+ public static final int CMD_NETWORK_CONNECTED = BASE + 1;
+
+ /**
+ * Inform ConnectivityService that the network is validated.
+ * obj = NetworkAgentInfo
+ */
+ public static final int EVENT_NETWORK_VALIDATED = BASE + 2;
+
+ /**
+ * Inform NetworkMonitor to linger a network. The Monitor should
+ * start a timer and/or start watching for zero live connections while
+ * moving towards LINGER_COMPLETE. After the Linger period expires
+ * (or other events mark the end of the linger state) the LINGER_COMPLETE
+ * event should be sent and the network will be shut down. If a
+ * CMD_NETWORK_CONNECTED happens before the LINGER completes
+ * it indicates further desire to keep the network alive and so
+ * the LINGER is aborted.
+ */
+ public static final int CMD_NETWORK_LINGER = BASE + 3;
+
+ /**
+ * Message to self indicating linger delay has expired.
+ * arg1 = Token to ignore old messages.
+ */
+ private static final int CMD_LINGER_EXPIRED = BASE + 4;
+
+ /**
+ * Inform ConnectivityService that the network LINGER period has
+ * expired.
+ * obj = NetworkAgentInfo
+ */
+ public static final int EVENT_NETWORK_LINGER_COMPLETE = BASE + 5;
+
+ /**
+ * Message to self indicating it's time to check for a captive portal again.
+ * TODO - Remove this once broadcast intents are used to communicate with
+ * apps to log into captive portals.
+ * arg1 = Token to ignore old messages.
+ */
+ private static final int CMD_CAPTIVE_PORTAL_REEVALUATE = BASE + 6;
+
+ /**
+ * Message to self indicating it's time to evaluate a network's connectivity.
+ * arg1 = Token to ignore old messages.
+ */
+ private static final int CMD_REEVALUATE = BASE + 7;
+
+ /**
+ * Message to self indicating network evaluation is complete.
+ * arg1 = Token to ignore old messages.
+ * arg2 = HTTP response code of network evaluation.
+ */
+ private static final int EVENT_REEVALUATION_COMPLETE = BASE + 8;
+
+ /**
+ * Inform NetworkMonitor that the network has disconnected.
+ */
+ public static final int CMD_NETWORK_DISCONNECTED = BASE + 9;
+
+ /**
+ * Force evaluation even if it has succeeded in the past.
+ */
+ public static final int CMD_FORCE_REEVALUATION = BASE + 10;
+
+ private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger";
+ // Default to 30s linger time-out.
+ private static final int DEFAULT_LINGER_DELAY_MS = 30000;
+ private final int mLingerDelayMs;
+ private int mLingerToken = 0;
+
+ private static final int CAPTIVE_PORTAL_REEVALUATE_DELAY_MS = 5000;
+ private int mCaptivePortalReevaluateToken = 0;
+
+ // Negative values disable reevaluation.
+ private static final String REEVALUATE_DELAY_PROPERTY = "persist.netmon.reeval_delay";
+ // Default to 5s reevaluation delay.
+ private static final int DEFAULT_REEVALUATE_DELAY_MS = 5000;
+ private final int mReevaluateDelayMs;
+ private int mReevaluateToken = 0;
+
+ private final Context mContext;
+ private final Handler mConnectivityServiceHandler;
+ private final NetworkAgentInfo mNetworkAgentInfo;
+
+ private String mServer;
+ private boolean mIsCaptivePortalCheckEnabled = false;
+
+ private State mDefaultState = new DefaultState();
+ private State mOfflineState = new OfflineState();
+ private State mValidatedState = new ValidatedState();
+ private State mEvaluatingState = new EvaluatingState();
+ private State mCaptivePortalState = new CaptivePortalState();
+ private State mLingeringState = new LingeringState();
+
+ public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo) {
+ // Add suffix indicating which NetworkMonitor we're talking about.
+ super(TAG + networkAgentInfo.name());
+
+ mContext = context;
+ mConnectivityServiceHandler = handler;
+ mNetworkAgentInfo = networkAgentInfo;
+
+ addState(mDefaultState);
+ addState(mOfflineState, mDefaultState);
+ addState(mValidatedState, mDefaultState);
+ addState(mEvaluatingState, mDefaultState);
+ addState(mCaptivePortalState, mDefaultState);
+ addState(mLingeringState, mDefaultState);
+ setInitialState(mOfflineState);
+
+ mServer = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.CAPTIVE_PORTAL_SERVER);
+ if (mServer == null) mServer = DEFAULT_SERVER;
+
+ mLingerDelayMs = SystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
+ mReevaluateDelayMs = SystemProperties.getInt(REEVALUATE_DELAY_PROPERTY,
+ DEFAULT_REEVALUATE_DELAY_MS);
+
+ // TODO: Enable this when we're ready.
+ // mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(),
+ // Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1;
+
+ start();
+ }
+
+ private class DefaultState extends State {
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) log(getName() + message.toString());
+ switch (message.what) {
+ case CMD_NETWORK_LINGER:
+ if (DBG) log("Lingering");
+ transitionTo(mLingeringState);
+ break;
+ case CMD_NETWORK_CONNECTED:
+ if (DBG) log("Connected");
+ transitionTo(mEvaluatingState);
+ break;
+ case CMD_NETWORK_DISCONNECTED:
+ if (DBG) log("Disconnected");
+ transitionTo(mOfflineState);
+ break;
+ case CMD_FORCE_REEVALUATION:
+ if (DBG) log("Forcing reevaluation");
+ transitionTo(mEvaluatingState);
+ break;
+ default:
+ break;
+ }
+ return HANDLED;
+ }
+ }
+
+ private class OfflineState extends State {
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) log(getName() + message.toString());
+ return NOT_HANDLED;
+ }
+ }
+
+ private class ValidatedState extends State {
+ @Override
+ public void enter() {
+ if (DBG) log("Validated");
+ mConnectivityServiceHandler.sendMessage(
+ obtainMessage(EVENT_NETWORK_VALIDATED, mNetworkAgentInfo));
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) log(getName() + message.toString());
+ switch (message.what) {
+ case CMD_NETWORK_CONNECTED:
+ transitionTo(mValidatedState);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
+ }
+
+ private class EvaluatingState extends State {
+ private class EvaluateInternetConnectivity extends Thread {
+ private int mToken;
+ EvaluateInternetConnectivity(int token) {
+ mToken = token;
+ }
+ public void run() {
+ sendMessage(EVENT_REEVALUATION_COMPLETE, mToken, isCaptivePortal());
+ }
+ }
+
+ @Override
+ public void enter() {
+ sendMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) log(getName() + message.toString());
+ switch (message.what) {
+ case CMD_REEVALUATE:
+ if (message.arg1 != mReevaluateToken)
+ break;
+ // If network provides no internet connectivity adjust evaluation.
+ if (mNetworkAgentInfo.networkCapabilities.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+ // TODO: Try to verify something works. Do all gateways respond to pings?
+ transitionTo(mValidatedState);
+ }
+ // Kick off a thread to perform internet connectivity evaluation.
+ Thread thread = new EvaluateInternetConnectivity(mReevaluateToken);
+ thread.run();
+ break;
+ case EVENT_REEVALUATION_COMPLETE:
+ if (message.arg1 != mReevaluateToken)
+ break;
+ int httpResponseCode = message.arg2;
+ if (httpResponseCode == 204) {
+ transitionTo(mValidatedState);
+ } else if (httpResponseCode >= 200 && httpResponseCode <= 399) {
+ transitionTo(mCaptivePortalState);
+ } else {
+ if (mReevaluateDelayMs >= 0) {
+ Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
+ sendMessageDelayed(msg, mReevaluateDelayMs);
+ }
+ }
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
+ }
+
+ // TODO: Until we add an intent from the app handling captive portal
+ // login we'll just re-evaluate after a delay.
+ private class CaptivePortalState extends State {
+ @Override
+ public void enter() {
+ Message message = obtainMessage(CMD_CAPTIVE_PORTAL_REEVALUATE,
+ ++mCaptivePortalReevaluateToken, 0);
+ sendMessageDelayed(message, CAPTIVE_PORTAL_REEVALUATE_DELAY_MS);
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) log(getName() + message.toString());
+ switch (message.what) {
+ case CMD_CAPTIVE_PORTAL_REEVALUATE:
+ if (message.arg1 != mCaptivePortalReevaluateToken)
+ break;
+ transitionTo(mEvaluatingState);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
+ }
+
+ private class LingeringState extends State {
+ @Override
+ public void enter() {
+ Message message = obtainMessage(CMD_LINGER_EXPIRED, ++mLingerToken, 0);
+ sendMessageDelayed(message, mLingerDelayMs);
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) log(getName() + message.toString());
+ switch (message.what) {
+ case CMD_NETWORK_CONNECTED:
+ // Go straight to active as we've already evaluated.
+ transitionTo(mValidatedState);
+ break;
+ case CMD_LINGER_EXPIRED:
+ if (message.arg1 != mLingerToken)
+ break;
+ mConnectivityServiceHandler.sendMessage(
+ obtainMessage(EVENT_NETWORK_LINGER_COMPLETE, mNetworkAgentInfo));
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
+ }
+
+ /**
+ * Do a URL fetch on a known server to see if we get the data we expect.
+ * Returns HTTP response code.
+ */
+ private int isCaptivePortal() {
+ if (!mIsCaptivePortalCheckEnabled) return 204;
+
+ String urlString = "http://" + mServer + "/generate_204";
+ if (DBG) log("Checking " + urlString);
+ HttpURLConnection urlConnection = null;
+ Socket socket = null;
+ int httpResponseCode = 500;
+ try {
+ URL url = new URL(urlString);
+ if (false) {
+ // TODO: Need to add URLConnection.setNetwork() before we can enable.
+ urlConnection = (HttpURLConnection) url.openConnection();
+ urlConnection.setInstanceFollowRedirects(false);
+ urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
+ urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
+ urlConnection.setUseCaches(false);
+ urlConnection.getInputStream();
+ httpResponseCode = urlConnection.getResponseCode();
+ } else {
+ socket = new Socket();
+ // TODO: setNetworkForSocket(socket, mNetworkAgentInfo.network.netId);
+ InetSocketAddress address = new InetSocketAddress(url.getHost(), 80);
+ // TODO: address = new InetSocketAddress(
+ // getByNameOnNetwork(mNetworkAgentInfo.network, url.getHost()), 80);
+ socket.connect(address);
+ BufferedReader reader = new BufferedReader(
+ new InputStreamReader(socket.getInputStream()));
+ OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream());
+ writer.write("GET " + url.getFile() + " HTTP/1.1\r\n\n");
+ writer.flush();
+ String response = reader.readLine();
+ if (response.startsWith("HTTP/1.1 ")) {
+ httpResponseCode = Integer.parseInt(response.substring(9, 12));
+ }
+ }
+ if (DBG) log("isCaptivePortal: ret=" + httpResponseCode);
+ } catch (IOException e) {
+ if (DBG) log("Probably not a portal: exception " + e);
+ } finally {
+ if (urlConnection != null) {
+ urlConnection.disconnect();
+ }
+ if (socket != null) {
+ try {
+ socket.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+ return httpResponseCode;
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 0749f24..63178eb 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -25,6 +25,7 @@
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.net.ProxyInfo;
+import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -32,7 +33,6 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Settings;
-import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -71,7 +71,7 @@
public static final String KEY_PROXY = "keyProxy";
private String mCurrentPac;
@GuardedBy("mProxyLock")
- private String mPacUrl;
+ private Uri mPacUrl;
private AlarmManager mAlarmManager;
@GuardedBy("mProxyLock")
@@ -100,7 +100,7 @@
public void run() {
String file;
synchronized (mProxyLock) {
- if (mPacUrl == null) return;
+ if (Uri.EMPTY.equals(mPacUrl)) return;
try {
file = get(mPacUrl);
} catch (IOException ioe) {
@@ -158,13 +158,13 @@
* @return Returns true when the broadcast should not be sent
*/
public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
- if (proxy.getPacFileUrl() != null) {
+ if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) {
// Allow to send broadcast, nothing to do.
return false;
}
synchronized (mProxyLock) {
- mPacUrl = proxy.getPacFileUrl().toString();
+ mPacUrl = proxy.getPacFileUrl();
}
mCurrentDelay = DELAY_1;
mHasSentBroadcast = false;
@@ -196,8 +196,8 @@
*
* @throws IOException
*/
- private static String get(String urlString) throws IOException {
- URL url = new URL(urlString);
+ private static String get(Uri pacUri) throws IOException {
+ URL url = new URL(pacUri.toString());
URLConnection urlConnection = url.openConnection(java.net.Proxy.NO_PROXY);
return new String(Streams.readFully(urlConnection.getInputStream()));
}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index abe362a..92b5f52 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -1325,7 +1325,7 @@
} else {
LinkProperties linkProperties = null;
try {
- linkProperties = mConnService.getLinkProperties(upType);
+ linkProperties = mConnService.getLinkPropertiesForType(upType);
} catch (RemoteException e) { }
if (linkProperties != null) {
// Find the interface with the default IPv4 route. It may be the
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 5fa1584..4740cae 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -48,8 +48,7 @@
private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
// If true, enables the use of the screen auto-brightness adjustment setting.
- private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT =
- PowerManager.useScreenAutoBrightnessAdjustmentFeature();
+ private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT = true;
// The maximum range of gamma adjustment possible using the screen
// auto-brightness adjustment setting.
@@ -202,7 +201,7 @@
public void updatePowerState(DisplayManagerInternal.DisplayPowerRequest request) {
if (setScreenAutoBrightnessAdjustment(request.screenAutoBrightnessAdjustment)
- || setLightSensorEnabled(request.wantLightSensorEnabled())) {
+ | setLightSensorEnabled(request.wantLightSensorEnabled())) {
updateAutoBrightness(false /*sendUpdate*/);
}
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 3ae0fd5..3d5fb57 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -518,6 +518,11 @@
// Brighten quickly.
slow = false;
}
+ // If low power mode is enabled, brightness level
+ // would be scaled down to half
+ if (mPowerRequest.lowPowerMode) {
+ target = target/2;
+ }
animateScreenBrightness(clampScreenBrightness(target),
slow ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
} else {
diff --git a/services/core/java/com/android/server/hdmi/FeatureAction.java b/services/core/java/com/android/server/hdmi/FeatureAction.java
index 296cc5b..d747cd0 100644
--- a/services/core/java/com/android/server/hdmi/FeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/FeatureAction.java
@@ -15,7 +15,6 @@
*/
package com.android.server.hdmi;
-import android.hardware.hdmi.HdmiCec;
import android.hardware.hdmi.HdmiCecMessage;
import android.os.Handler;
import android.os.Looper;
@@ -155,23 +154,10 @@
mActionTimer.sendTimerMessage(state, delayMillis);
}
- static HdmiCecMessage buildCommand(int src, int dst, int opcode, byte[] params) {
- return new HdmiCecMessage(src, dst, opcode, params);
- }
-
- // Build a CEC command that does not have parameter.
- static HdmiCecMessage buildCommand(int src, int dst, int opcode) {
- return new HdmiCecMessage(src, dst, opcode, HdmiCecMessage.EMPTY_PARAM);
- }
-
protected final void sendCommand(HdmiCecMessage cmd) {
mService.sendCecCommand(cmd);
}
- protected final void sendBroadcastCommand(int opcode, byte[] param) {
- sendCommand(buildCommand(mSourceAddress, HdmiCec.ADDR_BROADCAST, opcode, param));
- }
-
/**
* Finish up the action. Reset the state, and remove itself from the action queue.
*/
@@ -189,23 +175,4 @@
private void removeAction(FeatureAction action) {
mService.removeAction(action);
}
-
- // Utility methods for generating parameter byte arrays for CEC commands.
- protected static byte[] uiCommandParam(int uiCommand) {
- return new byte[] {(byte) uiCommand};
- }
-
- protected static byte[] physicalAddressParam(int physicalAddress) {
- return new byte[] {
- (byte) ((physicalAddress >> 8) & 0xFF),
- (byte) (physicalAddress & 0xFF)
- };
- }
-
- protected static byte[] pathPairParam(int oldPath, int newPath) {
- return new byte[] {
- (byte) ((oldPath >> 8) & 0xFF), (byte) (oldPath & 0xFF),
- (byte) ((newPath >> 8) & 0xFF), (byte) (newPath & 0xFF)
- };
- }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index b103a4d..5327ef4 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -55,15 +55,6 @@
// A message to report allocated logical address to main control looper.
private final static int MSG_REPORT_LOGICAL_ADDRESS = 2;
- // TODO: move these values to HdmiCec.java once make it internal constant class.
- // CEC's ABORT reason values.
- private static final int ABORT_UNRECOGNIZED_MODE = 0;
- private static final int ABORT_NOT_IN_CORRECT_MODE = 1;
- private static final int ABORT_CANNOT_PROVIDE_SOURCE = 2;
- private static final int ABORT_INVALID_OPERAND = 3;
- private static final int ABORT_REFUSED = 4;
- private static final int ABORT_UNABLE_TO_DETERMINE = 5;
-
private static final int NUM_LOGICAL_ADDRESS = 16;
// TODO: define other constants for errors.
@@ -80,10 +71,16 @@
// interacts with HAL.
private long mNativePtr;
+ private HdmiControlService mService;
+
// Map-like container of all cec devices. A logical address of device is
// used as key of container.
private final SparseArray<HdmiCecDeviceInfo> mDeviceInfos =
new SparseArray<HdmiCecDeviceInfo>();
+ // Set-like container for all local devices' logical address.
+ // Key and value are same.
+ private final SparseArray<Integer> mLocalLogicalAddresses =
+ new SparseArray<Integer>();
// Private constructor. Use HdmiCecController.create().
private HdmiCecController() {
@@ -325,6 +322,7 @@
*/
int addLogicalAddress(int newLogicalAddress) {
if (HdmiCec.isValidAddress(newLogicalAddress)) {
+ mLocalLogicalAddresses.append(newLogicalAddress, newLogicalAddress);
return nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
} else {
return -1;
@@ -337,6 +335,9 @@
* <p>Declared as package-private. accessed by {@link HdmiControlService} only.
*/
void clearLogicalAddress() {
+ // TODO: consider to backup logical address so that new logical address
+ // allocation can use it as preferred address.
+ mLocalLogicalAddresses.clear();
nativeClearLogicalAddress(mNativePtr);
}
@@ -371,30 +372,37 @@
}
private void init(HdmiControlService service, long nativePtr) {
+ mService = service;
mIoHandler = new IoHandler(service.getServiceLooper());
mControlHandler = new ControlHandler(service.getServiceLooper());
mNativePtr = nativePtr;
}
+ private boolean isAcceptableAddress(int address) {
+ // Can access command targeting devices available in local device or
+ // broadcast command.
+ return address == HdmiCec.ADDR_BROADCAST
+ || mLocalLogicalAddresses.get(address) != null;
+ }
+
private void onReceiveCommand(HdmiCecMessage message) {
- // TODO: Handle message according to opcode type.
+ if (isAcceptableAddress(message.getDestination()) &&
+ mService.handleCecCommand(message)) {
+ return;
+ }
// TODO: Use device's source address for broadcast message.
int sourceAddress = message.getDestination() != HdmiCec.ADDR_BROADCAST ?
message.getDestination() : 0;
// Reply <Feature Abort> to initiator (source) for all requests.
- sendFeatureAbort(sourceAddress, message.getSource(), message.getOpcode(),
- ABORT_REFUSED);
+ HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand
+ (sourceAddress, message.getSource(), message.getOpcode(),
+ HdmiCecMessageBuilder.ABORT_REFUSED);
+ sendCommand(cecMessage);
+
}
- private void sendFeatureAbort(int srcAddress, int destAddress, int originalOpcode,
- int reason) {
- byte[] params = new byte[2];
- params[0] = (byte) originalOpcode;
- params[1] = (byte) reason;
-
- HdmiCecMessage cecMessage = new HdmiCecMessage(srcAddress, destAddress,
- HdmiCec.MESSAGE_FEATURE_ABORT, params);
+ void sendCommand(HdmiCecMessage cecMessage) {
Message message = mIoHandler.obtainMessage(MSG_SEND_CEC_COMMAND, cecMessage);
mIoHandler.sendMessage(message);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
new file mode 100644
index 0000000..fc6183c
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.hdmi;
+
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecMessage;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * A helper class to build {@link HdmiCecMessage} from various cec commands.
+ */
+public class HdmiCecMessageBuilder {
+ // TODO: move these values to HdmiCec.java once make it internal constant class.
+ // CEC's ABORT reason values.
+ static final int ABORT_UNRECOGNIZED_MODE = 0;
+ static final int ABORT_NOT_IN_CORRECT_MODE = 1;
+ static final int ABORT_CANNOT_PROVIDE_SOURCE = 2;
+ static final int ABORT_INVALID_OPERAND = 3;
+ static final int ABORT_REFUSED = 4;
+ static final int ABORT_UNABLE_TO_DETERMINE = 5;
+
+ private static final int OSD_NAME_MAX_LENGTH = 13;
+
+ private HdmiCecMessageBuilder() {}
+
+ /**
+ * Build <Feature Abort> command. <Feature Abort> consists of
+ * 1 byte original opcode and 1 byte reason fields with basic fields.
+ *
+ * @param src source address of command
+ * @param dest destination address of command
+ * @param originalOpcode original opcode causing feature abort
+ * @param reason reason of feature abort
+ * @return newly created {@link HdmiCecMessage}
+ */
+ static HdmiCecMessage buildFeatureAbortCommand(int src, int dest, int originalOpcode,
+ int reason) {
+ byte[] params = new byte[] {
+ (byte) originalOpcode,
+ (byte) reason,
+ };
+ return buildCommand(src, dest, HdmiCec.MESSAGE_FEATURE_ABORT, params);
+ }
+
+ /**
+ * Build <Get Osd Name> command.
+ *
+ * @param src source address of command
+ * @param dest destination address of command
+ * @return newly created {@link HdmiCecMessage}
+ */
+ static HdmiCecMessage buildGetOsdNameCommand(int src, int dest) {
+ return buildCommand(src, dest, HdmiCec.MESSAGE_GET_OSD_NAME);
+ }
+
+ /**
+ * Build <Give Vendor Id Command> command.
+ *
+ * @param src source address of command
+ * @param dest destination address of command
+ * @return newly created {@link HdmiCecMessage}
+ */
+ static HdmiCecMessage buildGiveDeviceVendorIdCommand(int src, int dest) {
+ return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_DEVICE_VENDOR_ID);
+ }
+
+ /**
+ * Build <Set Menu Language > command.
+ *
+ * <p>This is a broadcast message sent to all devices on the bus.
+ *
+ * @param src source address of command
+ * @param language 3-letter ISO639-2 based language code
+ * @return newly created {@link HdmiCecMessage} if language is valid.
+ * Otherwise, return null
+ */
+ static HdmiCecMessage buildSetMenuLanguageCommand(int src, String language) {
+ if (language.length() != 3) {
+ return null;
+ }
+ // Hdmi CEC uses lower-cased ISO 639-2 (3 letters code).
+ String normalized = language.toLowerCase();
+ byte[] params = new byte[] {
+ (byte) normalized.charAt(0),
+ (byte) normalized.charAt(1),
+ (byte) normalized.charAt(2),
+ };
+ // <Set Menu Language> is broadcast message.
+ return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_SET_MENU_LANGUAGE,
+ params);
+ }
+
+ /**
+ * Build <Set Osd Name > command.
+ *
+ * @param src source address of command
+ * @param name display (OSD) name of device
+ * @return newly created {@link HdmiCecMessage} if valid name. Otherwise,
+ * return null
+ */
+ static HdmiCecMessage buildSetOsdNameCommand(int src, int dest, String name) {
+ int length = Math.min(name.length(), OSD_NAME_MAX_LENGTH);
+ byte[] params;
+ try {
+ params = name.substring(0, length).getBytes("US-ASCII");
+ } catch (UnsupportedEncodingException e) {
+ return null;
+ }
+ return buildCommand(src, dest, HdmiCec.MESSAGE_SET_OSD_NAME, params);
+ }
+
+ /**
+ * Build <Report Physical Address> command. It has two bytes physical
+ * address and one byte device type as parameter.
+ *
+ * <p>This is a broadcast message sent to all devices on the bus.
+ *
+ * @param src source address of command
+ * @param address physical address of device
+ * @param deviceType type of device
+ * @return newly created {@link HdmiCecMessage}
+ */
+ static HdmiCecMessage buildReportPhysicalAddressCommand(int src, int address, int deviceType) {
+ byte[] params = new byte[] {
+ // Two bytes for physical address
+ (byte) ((address >> 8) & 0xFF),
+ (byte) (address & 0xFF),
+ // One byte device type
+ (byte) deviceType
+ };
+ // <Report Physical Address> is broadcast message.
+ return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS,
+ params);
+ }
+
+ /**
+ * Build <Device Vendor Id> command. It has three bytes vendor id as
+ * parameter.
+ *
+ * <p>This is a broadcast message sent to all devices on the bus.
+ *
+ * @param src source address of command
+ * @param vendorId device's vendor id
+ * @return newly created {@link HdmiCecMessage}
+ */
+ static HdmiCecMessage buildDeviceVendorIdCommand(int src, int vendorId) {
+ byte[] params = new byte[] {
+ (byte) ((vendorId >> 16) & 0xFF),
+ (byte) ((vendorId >> 8) & 0xFF),
+ (byte) (vendorId & 0xFF)
+ };
+ // <Device Vendor Id> is broadcast message.
+ return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_DEVICE_VENDOR_ID,
+ params);
+ }
+
+ /**
+ * Build <Device Vendor Id> command. It has one byte cec version as parameter.
+ *
+ * @param src source address of command
+ * @param dest destination address of command
+ * @param version version of cec. Use 0x04 for "Version 1.3a" and 0x05 for
+ * "Version 1.4 or 1.4a or 1.4b
+ * @return newly created {@link HdmiCecMessage}
+ */
+ static HdmiCecMessage buildCecVersion(int src, int dest, int version) {
+ byte[] params = new byte[] {
+ (byte) version
+ };
+ return buildCommand(src, dest, HdmiCec.MESSAGE_CEC_VERSION, params);
+ }
+
+ /**
+ * Build a {@link HdmiCecMessage} without extra parameter.
+ *
+ * @param src source address of command
+ * @param dest destination address of command
+ * @param opcode opcode for a message
+ * @return newly created {@link HdmiCecMessage}
+ */
+ private static HdmiCecMessage buildCommand(int src, int dest, int opcode) {
+ return new HdmiCecMessage(src, dest, opcode, HdmiCecMessage.EMPTY_PARAM);
+ }
+
+ /**
+ * Build a {@link HdmiCecMessage} with given values.
+ *
+ * @param src source address of command
+ * @param dest destination address of command
+ * @param opcode opcode for a message
+ * @param params extra parameters for command
+ * @return newly created {@link HdmiCecMessage}
+ */
+ private static HdmiCecMessage buildCommand(int src, int dest, int opcode, byte[] params) {
+ return new HdmiCecMessage(src, dest, opcode, params);
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index f99c717..c122645 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -18,6 +18,7 @@
import android.annotation.Nullable;
import android.content.Context;
+import android.hardware.hdmi.HdmiCec;
import android.hardware.hdmi.HdmiCecDeviceInfo;
import android.hardware.hdmi.HdmiCecMessage;
import android.os.HandlerThread;
@@ -26,6 +27,8 @@
import com.android.server.SystemService;
+import java.util.Locale;
+
/**
* Provides a service for sending and processing HDMI control messages,
* HDMI-CEC and MHL control command, and providing the information on both standard.
@@ -105,7 +108,7 @@
* @param command CEC command to send out
*/
void sendCecCommand(HdmiCecMessage command) {
- // TODO: Implement this.
+ mCecController.sendCommand(command);
}
/**
@@ -116,4 +119,89 @@
void addDeviceInfo(HdmiCecDeviceInfo deviceInfo) {
// TODO: Implement this.
}
+
+ boolean handleCecCommand(HdmiCecMessage message) {
+ // Commands that queries system information replies directly instead
+ // of creating FeatureAction because they are state-less.
+ switch (message.getOpcode()) {
+ case HdmiCec.MESSAGE_GET_MENU_LANGUAGE:
+ handleGetMenuLanguage(message);
+ return true;
+ case HdmiCec.MESSAGE_GET_OSD_NAME:
+ handleGetOsdName(message);
+ return true;
+ case HdmiCec.MESSAGE_GIVE_PHYSICAL_ADDRESS:
+ handleGivePhysicalAddress(message);
+ return true;
+ case HdmiCec.MESSAGE_GIVE_DEVICE_VENDOR_ID:
+ handleGiveDeviceVendorId(message);
+ return true;
+ case HdmiCec.MESSAGE_GET_CEC_VERSION:
+ handleGetCecVersion(message);
+ return true;
+ // TODO: Add remaining system information query such as
+ // <Give Device Power Status> and <Request Active Source> handler.
+ default:
+ Slog.w(TAG, "Unsupported cec command:" + message.toString());
+ return false;
+ }
+ }
+
+ private void handleGetCecVersion(HdmiCecMessage message) {
+ int version = mCecController.getVersion();
+ HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildCecVersion(message.getDestination(),
+ message.getSource(),
+ version);
+ sendCecCommand(cecMessage);
+ }
+
+ private void handleGiveDeviceVendorId(HdmiCecMessage message) {
+ int vendorId = mCecController.getVendorId();
+ HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
+ message.getDestination(), vendorId);
+ sendCecCommand(cecMessage);
+ }
+
+ private void handleGivePhysicalAddress(HdmiCecMessage message) {
+ int physicalAddress = mCecController.getPhysicalAddress();
+ int deviceType = HdmiCec.getTypeFromAddress(message.getDestination());
+ HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ message.getDestination(), physicalAddress, deviceType);
+ sendCecCommand(cecMessage);
+ }
+
+ private void handleGetOsdName(HdmiCecMessage message) {
+ // TODO: read device name from settings or property.
+ String name = HdmiCec.getDefaultDeviceName(message.getDestination());
+ HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand(
+ message.getDestination(), message.getSource(), name);
+ if (cecMessage != null) {
+ sendCecCommand(cecMessage);
+ } else {
+ Slog.w(TAG, "Failed to build <Get Osd Name>:" + name);
+ }
+ }
+
+ private void handleGetMenuLanguage(HdmiCecMessage message) {
+ // Only 0 (TV), 14 (specific use) can answer.
+ if (message.getDestination() != HdmiCec.ADDR_TV
+ && message.getDestination() != HdmiCec.ADDR_SPECIFIC_USE) {
+ Slog.w(TAG, "Only TV can handle <Get Menu Language>:" + message.toString());
+ sendCecCommand(
+ HdmiCecMessageBuilder.buildFeatureAbortCommand(message.getDestination(),
+ message.getSource(), HdmiCec.MESSAGE_GET_MENU_LANGUAGE,
+ HdmiCecMessageBuilder.ABORT_UNRECOGNIZED_MODE));
+ return;
+ }
+
+ HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand(
+ message.getDestination(),
+ Locale.getDefault().getISO3Language());
+ // TODO: figure out how to handle failed to get language code.
+ if (command != null) {
+ sendCecCommand(command);
+ } else {
+ Slog.w(TAG, "Failed to respond to <Get Menu Language>: " + message.toString());
+ }
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
index c84a067..98da280 100644
--- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -71,7 +71,8 @@
@Override
public boolean start() {
sendCommand(
- buildCommand(mSourceAddress, mDeviceLogicalAddress, HdmiCec.MESSAGE_GET_OSD_NAME));
+ HdmiCecMessageBuilder.buildGetOsdNameCommand(mSourceAddress,
+ mDeviceLogicalAddress));
mState = STATE_WAITING_FOR_SET_OSD_NAME;
addTimer(mState, TIMEOUT_MS);
return true;
@@ -132,8 +133,8 @@
}
private void requestVendorId() {
- sendCommand(buildCommand(mSourceAddress, mDeviceLogicalAddress,
- HdmiCec.MESSAGE_GIVE_DEVICE_VENDOR_ID));
+ sendCommand(HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(mSourceAddress,
+ mDeviceLogicalAddress));
addTimer(mState, TIMEOUT_MS);
}
diff --git a/services/core/java/com/android/server/location/FlpHardwareProvider.java b/services/core/java/com/android/server/location/FlpHardwareProvider.java
index 09f1c56..51ee93b 100644
--- a/services/core/java/com/android/server/location/FlpHardwareProvider.java
+++ b/services/core/java/com/android/server/location/FlpHardwareProvider.java
@@ -67,9 +67,9 @@
public static FlpHardwareProvider getInstance(Context context) {
if (sSingletonInstance == null) {
sSingletonInstance = new FlpHardwareProvider(context);
+ sSingletonInstance.nativeInit();
}
- nativeInit();
return sSingletonInstance;
}
@@ -96,8 +96,7 @@
Looper.myLooper());
}
- public static boolean isSupported() {
- nativeInit();
+ public boolean isSupported() {
return nativeIsSupported();
}
@@ -218,9 +217,9 @@
// Core members
private static native void nativeClassInit();
private static native boolean nativeIsSupported();
- private static native void nativeInit();
// FlpLocationInterface members
+ private native void nativeInit();
private native int nativeGetBatchSize();
private native void nativeStartBatching(int requestId, FusedBatchOptions options);
private native void nativeUpdateBatchingOptions(int requestId, FusedBatchOptions optionsObject);
diff --git a/services/core/java/com/android/server/location/LocationRequestStatistics.java b/services/core/java/com/android/server/location/LocationRequestStatistics.java
index 85231bb..264026e 100644
--- a/services/core/java/com/android/server/location/LocationRequestStatistics.java
+++ b/services/core/java/com/android/server/location/LocationRequestStatistics.java
@@ -13,7 +13,7 @@
public class LocationRequestStatistics {
private static final String TAG = "LocationStats";
- // Maps package name nad provider to location request statistics.
+ // Maps package name and provider to location request statistics.
public final HashMap<PackageProviderKey, PackageStatistics> statistics
= new HashMap<PackageProviderKey, PackageStatistics>();
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 015032b..41ab626 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -16,6 +16,7 @@
package com.android.server.media;
+import android.app.ActivityManager;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.routeprovider.RouteRequest;
@@ -42,6 +43,7 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -80,7 +82,9 @@
private final MessageHandler mHandler;
- private final int mPid;
+ private final int mOwnerPid;
+ private final int mOwnerUid;
+ private final int mUserId;
private final SessionInfo mSessionInfo;
private final String mTag;
private final ControllerStub mController;
@@ -110,10 +114,12 @@
private boolean mIsActive = false;
- public MediaSessionRecord(int pid, String packageName, ISessionCallback cb, String tag,
- MediaSessionService service, Handler handler) {
- mPid = pid;
- mSessionInfo = new SessionInfo(UUID.randomUUID().toString(), packageName);
+ public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName,
+ ISessionCallback cb, String tag, MediaSessionService service, Handler handler) {
+ mOwnerPid = ownerPid;
+ mOwnerUid = ownerUid;
+ mUserId = userId;
+ mSessionInfo = new SessionInfo(UUID.randomUUID().toString(), ownerPackageName);
mTag = tag;
mController = new ControllerStub();
mSession = new SessionStub();
@@ -187,6 +193,15 @@
}
/**
+ * Get the user id this session was created for.
+ *
+ * @return The user id for this session.
+ */
+ public int getUserId() {
+ return mUserId;
+ }
+
+ /**
* Check if this session has system priorty and should receive media buttons
* before any other sessions.
*
@@ -305,7 +320,8 @@
pw.println(prefix + mTag + " " + this);
final String indent = prefix + " ";
- pw.println(indent + "pid=" + mPid);
+ pw.println(indent + "ownerPid=" + mOwnerPid + ", ownerUid=" + mOwnerUid
+ + ", userId=" + mUserId);
pw.println(indent + "info=" + mSessionInfo.toString());
pw.println(indent + "published=" + mIsActive);
pw.println(indent + "flags=" + mFlags);
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index fb858fc..008f9be 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -63,7 +63,6 @@
private final ArrayList<MediaRouteProviderProxy> mProviders
= new ArrayList<MediaRouteProviderProxy>();
private final Object mLock = new Object();
- // TODO do we want a separate thread for handling mediasession messages?
private final Handler mHandler = new Handler();
private MediaSessionRecord mPrioritySession;
@@ -72,8 +71,8 @@
// session so we drop late callbacks properly.
private int mShowRoutesRequestId = 0;
- // TODO refactor to have per user state. See MediaRouterService for an
- // example
+ // TODO refactor to have per user state for providers. See
+ // MediaRouterService for an example
public MediaSessionService(Context context) {
super(context);
@@ -211,25 +210,42 @@
* <ul>
* <li>the caller has android.Manifest.permission.MEDIA_CONTENT_CONTROL
* permission</li>
- * <li>the caller's listener is one of the enabled notification listeners</li>
+ * <li>the caller's listener is one of the enabled notification listeners
+ * for the caller's user</li>
* </ul>
*/
- private void enforceMediaPermissions(ComponentName compName, int pid, int uid) {
+ private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
+ int resolvedUserId) {
if (getContext()
.checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
!= PackageManager.PERMISSION_GRANTED
- && !isEnabledNotificationListener(compName)) {
+ && !isEnabledNotificationListener(compName, UserHandle.getUserId(uid),
+ resolvedUserId)) {
throw new SecurityException("Missing permission to control media.");
}
}
- private boolean isEnabledNotificationListener(ComponentName compName) {
+ /**
+ * This checks if the component is an enabled notification listener for the
+ * specified user. Enabled components may only operate on behalf of the user
+ * they're running as.
+ *
+ * @param compName The component that is enabled.
+ * @param userId The user id of the caller.
+ * @param forUserId The user id they're making the request on behalf of.
+ * @return True if the component is enabled, false otherwise
+ */
+ private boolean isEnabledNotificationListener(ComponentName compName, int userId,
+ int forUserId) {
+ if (userId != forUserId) {
+ // You may not access another user's content as an enabled listener.
+ return false;
+ }
if (compName != null) {
- final int currentUser = ActivityManager.getCurrentUser();
final String enabledNotifListeners = Settings.Secure.getStringForUser(
getContext().getContentResolver(),
Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
- currentUser);
+ userId);
if (enabledNotifListeners != null) {
final String[] components = enabledNotifListeners.split(":");
for (int i = 0; i < components.length; i++) {
@@ -248,23 +264,23 @@
}
if (DEBUG) {
Log.d(TAG, "not ok to get sessions, " + compName +
- " is not in list of ENABLED_NOTIFICATION_LISTENERS");
+ " is not in list of ENABLED_NOTIFICATION_LISTENERS for user " + userId);
}
}
return false;
}
- private MediaSessionRecord createSessionInternal(int pid, String packageName,
- ISessionCallback cb, String tag, boolean forCalls) {
+ private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
+ String callerPackageName, ISessionCallback cb, String tag) {
synchronized (mLock) {
- return createSessionLocked(pid, packageName, cb, tag);
+ return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb, tag);
}
}
- private MediaSessionRecord createSessionLocked(int pid, String packageName,
- ISessionCallback cb, String tag) {
- final MediaSessionRecord session = new MediaSessionRecord(pid, packageName, cb, tag, this,
- mHandler);
+ private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
+ String callerPackageName, ISessionCallback cb, String tag) {
+ final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId,
+ callerPackageName, cb, tag, this, mHandler);
try {
cb.asBinder().linkToDeath(session, 0);
} catch (RemoteException e) {
@@ -273,7 +289,7 @@
mRecords.add(session);
mPriorityStack.addSession(session);
if (DEBUG) {
- Log.d(TAG, "Created session for package " + packageName + " with tag " + tag);
+ Log.d(TAG, "Created session for package " + callerPackageName + " with tag " + tag);
}
return session;
}
@@ -358,41 +374,50 @@
// ActivityManagerNative.handleIncomingUser and stash result for use
// when starting services on that session's behalf.
@Override
- public ISession createSession(String packageName, ISessionCallback cb, String tag)
- throws RemoteException {
+ public ISession createSession(String packageName, ISessionCallback cb, String tag,
+ int userId) throws RemoteException {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
enforcePackageName(packageName, uid);
+ int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+ false /* allowAll */, true /* requireFull */, "createSession", packageName);
if (cb == null) {
throw new IllegalArgumentException("Controller callback cannot be null");
}
- return createSessionInternal(pid, packageName, cb, tag, false).getSessionBinder();
+ return createSessionInternal(pid, uid, resolvedUserId, packageName, cb, tag)
+ .getSessionBinder();
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
- public List<IBinder> getSessions(ComponentName componentName) {
+ public List<IBinder> getSessions(ComponentName componentName, int userId) {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
+ String packageName = null;
if (componentName != null) {
// If they gave us a component name verify they own the
// package
- enforcePackageName(componentName.getPackageName(), uid);
+ packageName = componentName.getPackageName();
+ enforcePackageName(packageName, uid);
}
- // Then check if they have the permissions or their component is
- // allowed
- enforceMediaPermissions(componentName, pid, uid);
+ // Check that they can make calls on behalf of the user and
+ // get the final user id
+ int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+ true /* allowAll */, true /* requireFull */, "getSessions", packageName);
+ // Check if they have the permissions or their component is
+ // enabled for the user they're calling from.
+ enforceMediaPermissions(componentName, pid, uid, resolvedUserId);
ArrayList<IBinder> binders = new ArrayList<IBinder>();
synchronized (mLock) {
ArrayList<MediaSessionRecord> records = mPriorityStack
- .getActiveSessions();
+ .getActiveSessions(resolvedUserId);
int size = records.size();
for (int i = 0; i < size; i++) {
binders.add(records.get(i).getControllerBinder().asBinder());
@@ -428,7 +453,7 @@
mRecords.get(i).dump(pw, "");
pw.println();
}
- mPriorityStack.dumpLocked(pw, "");
+ mPriorityStack.dump(pw, "");
pw.println("Providers:");
count = mProviders.size();
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index f9f004d..1e1818d 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -18,6 +18,7 @@
import android.media.session.PlaybackState;
import android.media.session.Session;
+import android.os.UserHandle;
import android.text.TextUtils;
import java.io.PrintWriter;
@@ -104,11 +105,12 @@
* Get the current priority sorted list of active sessions. The most
* important session is at index 0 and the least important at size - 1.
*
+ * @param userId The user to check.
* @return All the active sessions in priority order.
*/
- public ArrayList<MediaSessionRecord> getActiveSessions() {
+ public ArrayList<MediaSessionRecord> getActiveSessions(int userId) {
if (mCachedActiveList == null) {
- mCachedActiveList = getPriorityListLocked(true, 0);
+ mCachedActiveList = getPriorityListLocked(true, 0, userId);
}
return mCachedActiveList;
}
@@ -118,13 +120,14 @@
* transport controls. The most important session is at index 0 and the
* least important at size -1.
*
+ * @param userId The user to check.
* @return All the active sessions that handle transport controls in
* priority order.
*/
- public ArrayList<MediaSessionRecord> getTransportControlSessions() {
+ public ArrayList<MediaSessionRecord> getTransportControlSessions(int userId) {
if (mCachedTransportControlList == null) {
mCachedTransportControlList = getPriorityListLocked(true,
- Session.FLAG_HANDLES_TRANSPORT_CONTROLS);
+ Session.FLAG_HANDLES_TRANSPORT_CONTROLS, userId);
}
return mCachedTransportControlList;
}
@@ -132,13 +135,14 @@
/**
* Get the highest priority active session.
*
+ * @param userId The user to check.
* @return The current highest priority session or null.
*/
- public MediaSessionRecord getDefaultSession() {
+ public MediaSessionRecord getDefaultSession(int userId) {
if (mCachedDefault != null) {
return mCachedDefault;
}
- ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0);
+ ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0, userId);
if (records.size() > 0) {
return records.get(0);
}
@@ -148,22 +152,24 @@
/**
* Get the highest priority session that can handle media buttons.
*
+ * @param userId The user to check.
* @return The default media button session or null.
*/
- public MediaSessionRecord getDefaultMediaButtonSession() {
+ public MediaSessionRecord getDefaultMediaButtonSession(int userId) {
if (mCachedButtonReceiver != null) {
return mCachedButtonReceiver;
}
ArrayList<MediaSessionRecord> records = getPriorityListLocked(true,
- Session.FLAG_HANDLES_MEDIA_BUTTONS);
+ Session.FLAG_HANDLES_MEDIA_BUTTONS, userId);
if (records.size() > 0) {
mCachedButtonReceiver = records.get(0);
}
return mCachedButtonReceiver;
}
- public void dumpLocked(PrintWriter pw, String prefix) {
- ArrayList<MediaSessionRecord> sortedSessions = getPriorityListLocked(false, 0);
+ public void dump(PrintWriter pw, String prefix) {
+ ArrayList<MediaSessionRecord> sortedSessions = getPriorityListLocked(false, 0,
+ UserHandle.USER_ALL);
int count = sortedSessions.size();
pw.println(prefix + "Sessions Stack - have " + count + " sessions:");
String indent = prefix + " ";
@@ -182,9 +188,12 @@
* all sessions.
* @param withFlags Only return sessions with all the specified flags set. 0
* returns all sessions.
+ * @param userId The user to get sessions for. {@link UserHandle#USER_ALL}
+ * will return sessions for all users.
* @return The priority sorted list of sessions.
*/
- private ArrayList<MediaSessionRecord> getPriorityListLocked(boolean activeOnly, int withFlags) {
+ private ArrayList<MediaSessionRecord> getPriorityListLocked(boolean activeOnly, int withFlags,
+ int userId) {
ArrayList<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>();
int lastLocalIndex = 0;
int lastActiveIndex = 0;
@@ -194,7 +203,12 @@
for (int i = 0; i < size; i++) {
final MediaSessionRecord session = mSessions.get(i);
+ if (userId != UserHandle.USER_ALL && userId != session.getUserId()) {
+ // Filter out sessions for the wrong user
+ continue;
+ }
if ((session.getFlags() & withFlags) != withFlags) {
+ // Filter out sessions with the wrong flags
continue;
}
if (!session.isActive()) {
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index d074565..007032e 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -16,8 +16,13 @@
package com.android.server.notification;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
@@ -30,6 +35,7 @@
import android.service.notification.IConditionListener;
import android.service.notification.IConditionProvider;
import android.service.notification.ZenModeConfig;
+import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
@@ -39,6 +45,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Date;
public class ConditionProviders extends ManagedServices {
private static final Condition[] NO_CONDITIONS = new Condition[0];
@@ -47,6 +54,7 @@
private final ArrayMap<IBinder, IConditionListener> mListeners
= new ArrayMap<IBinder, IConditionListener>();
private final ArrayList<ConditionRecord> mRecords = new ArrayList<ConditionRecord>();
+ private final CountdownConditionHelper mCountdownHelper = new CountdownConditionHelper();
public ConditionProviders(Context context, Handler handler,
UserProfiles userProfiles, ZenModeHelper zenModeHelper) {
@@ -267,6 +275,7 @@
}
}
}
+ mCountdownHelper.setZenModeCondition(conditionId);
}
private void subscribeLocked(ConditionRecord r) {
@@ -434,6 +443,68 @@
mZenModeHelper.setConfig(config);
}
+ private final class CountdownConditionHelper extends BroadcastReceiver {
+ private static final String ACTION = "CountdownConditionHelper";
+ private static final int REQUEST_CODE = 100;
+ private static final String EXTRA_TIME = "time";
+
+ private long mCurrent;
+
+ public CountdownConditionHelper() {
+ mContext.registerReceiver(this, new IntentFilter(ACTION));
+ }
+
+ public void setZenModeCondition(Uri conditionId) {
+ final long time = tryParseCondition(conditionId);
+ final AlarmManager alarms = (AlarmManager)
+ mContext.getSystemService(Context.ALARM_SERVICE);
+ final Intent intent = new Intent(ACTION).putExtra(EXTRA_TIME, time)
+ .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, REQUEST_CODE,
+ intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ alarms.cancel(pendingIntent);
+ mCurrent = time;
+ if (time > 0) {
+ final long now = System.currentTimeMillis();
+ final CharSequence span =
+ DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS);
+ Slog.d(TAG, String.format("Scheduling %s for %s, %s in the future (%s), now=%s",
+ ACTION, ts(time), time - now, span, ts(now)));
+ alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
+ }
+ }
+
+ private String ts(long time) {
+ return new Date(time) + " (" + time + ")";
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION.equals(intent.getAction())) {
+ final long time = intent.getLongExtra(EXTRA_TIME, 0);
+ Slog.d(TAG, "Countdown condition fired. time=" + time + " mCurrent=" + mCurrent);
+ if (time > 0 && time == mCurrent) {
+ // countdown condition is still the manual condition, leave zen
+ mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF);
+ ConditionProviders.this.setZenModeCondition(null);
+ }
+ }
+ }
+
+ private long tryParseCondition(Uri conditionId) {
+ // condition://android/countdown/1399917958951
+ if (!Condition.isValidId(conditionId, "android")) return 0;
+ if (conditionId.getPathSegments().size() != 2
+ || !"countdown".equals(conditionId.getPathSegments().get(0))) return 0;
+ try {
+ return Long.parseLong(conditionId.getPathSegments().get(1));
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Error parsing countdown condition: " + conditionId, e);
+ return 0;
+ }
+ }
+ }
+
private class ZenModeHelperCallback extends ZenModeHelper.Callback {
@Override
void onConfigChanged() {
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index d34b09c..584145f 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -66,7 +66,7 @@
private static final String ENABLED_SERVICES_SEPARATOR = ":";
- private final Context mContext;
+ protected final Context mContext;
protected final Object mMutex;
private final UserProfiles mUserProfiles;
private final SettingsObserver mSettingsObserver;
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
new file mode 100644
index 0000000..49293d3
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.notification;
+
+import java.util.Comparator;
+
+/**
+ * Sorts notificaitons into attention-relelvant order.
+ */
+public class NotificationComparator
+ implements Comparator<NotificationManagerService.NotificationRecord> {
+
+ @Override
+ public int compare(NotificationManagerService.NotificationRecord lhs,
+ NotificationManagerService.NotificationRecord rhs) {
+ if (lhs.isRecentlyIntrusive() != rhs.isRecentlyIntrusive()) {
+ return lhs.isRecentlyIntrusive() ? -1 : 1;
+ }
+ final int leftScore = lhs.sbn.getScore();
+ final int rightScore = rhs.sbn.getScore();
+ if (leftScore != rightScore) {
+ // by priority, high to low
+ return -1 * Integer.compare(leftScore, rightScore);
+ }
+ final float leftPeple = lhs.getContactAffinity();
+ final float rightPeople = rhs.getContactAffinity();
+ if (leftPeple != rightPeople) {
+ // by contact proximity, close to far
+ return -1 * Float.compare(leftPeple, rightPeople);
+ }
+ // then break ties by time, most recent first
+ return -1 * Long.compare(lhs.sbn.getPostTime(), rhs.sbn.getPostTime());
+ }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
new file mode 100644
index 0000000..125158fd
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
@@ -0,0 +1,64 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.android.server.notification;
+
+import android.app.Notification;
+import android.content.Context;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.server.notification.NotificationManagerService.NotificationRecord;
+
+/**
+ * This {@link com.android.server.notification.NotificationSignalExtractor} noticies noisy
+ * notifications and marks them to get a temporary ranking bump.
+ */
+public class NotificationIntrusivenessExtractor implements NotificationSignalExtractor {
+ private static final String TAG = "NotificationNoiseExtractor";
+ private static final boolean DBG = false;
+
+ /** Length of time (in milliseconds) that an intrusive or noisy notification will stay at
+ the top of the ranking order, before it falls back to its natural position. */
+ private static final long HANG_TIME_MS = 10000;
+
+ public void initialize(Context ctx) {
+ if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
+ }
+
+ public RankingFuture process(NotificationRecord record) {
+ if (record == null || record.getNotification() == null) {
+ if (DBG) Slog.d(TAG, "skipping empty notification");
+ return null;
+ }
+
+ final Notification notification = record.getNotification();
+ if ((notification.defaults & Notification.DEFAULT_VIBRATE) != 0 ||
+ notification.vibrate != null ||
+ (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
+ notification.sound != null ||
+ notification.fullScreenIntent != null) {
+ record.setRecentlyIntusive(true);
+ }
+
+ return new RankingFuture(record, HANG_TIME_MS) {
+ @Override
+ public void work() {
+ mRecord.setRecentlyIntusive(false);
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index fce86e8..1734a33 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -49,8 +49,10 @@
import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.IInterface;
+import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
@@ -61,6 +63,7 @@
import android.service.notification.IConditionListener;
import android.service.notification.IConditionProvider;
import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationOrderUpdate;
import android.service.notification.StatusBarNotification;
import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
@@ -76,7 +79,6 @@
import android.widget.Toast;
import com.android.internal.R;
-import com.android.internal.notification.NotificationScorer;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.EventLogTags;
import com.android.server.SystemService;
@@ -104,9 +106,12 @@
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.NoSuchElementException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
/** {@hide} */
public class NotificationManagerService extends SystemService {
@@ -118,6 +123,8 @@
// message codes
static final int MESSAGE_TIMEOUT = 2;
static final int MESSAGE_SAVE_POLICY_FILE = 3;
+ static final int MESSAGE_RECONSIDER_RANKING = 4;
+ static final int MESSAGE_SEND_RANKING_UPDATE = 5;
static final int LONG_DELAY = 3500; // 3.5 seconds
static final int SHORT_DELAY = 2000; // 2 seconds
@@ -147,6 +154,9 @@
final IBinder mForegroundToken = new Binder();
private WorkerHandler mHandler;
+ private final HandlerThread mRankingThread = new HandlerThread("ranker",
+ Process.THREAD_PRIORITY_BACKGROUND);
+ private Handler mRankingHandler = null;
private Light mNotificationLight;
Light mAttentionLight;
@@ -171,6 +181,7 @@
// used as a mutex for access to all active notifications & listeners
final ArrayList<NotificationRecord> mNotificationList =
new ArrayList<NotificationRecord>();
+ final NotificationComparator mRankingComparator = new NotificationComparator();
final ArrayMap<String, NotificationRecord> mNotificationsByKey =
new ArrayMap<String, NotificationRecord>();
final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
@@ -193,7 +204,7 @@
private static final String TAG_PACKAGE = "package";
private static final String ATTR_NAME = "name";
- final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
+ final ArrayList<NotificationSignalExtractor> mSignalExtractors = new ArrayList<NotificationSignalExtractor>();
private final UserProfiles mUserProfiles = new UserProfiles();
private NotificationListeners mListeners;
@@ -444,9 +455,14 @@
public static final class NotificationRecord
{
final StatusBarNotification sbn;
- final SingleNotificationStats stats = new SingleNotificationStats();
+ SingleNotificationStats stats;
IBinder statusBarKey;
+ // These members are used by NotificationSignalExtractors
+ // to communicate with the ranking module.
+ private float mContactAffinity;
+ private boolean mRecentlyIntrusive;
+
NotificationRecord(StatusBarNotification sbn)
{
this.sbn = sbn;
@@ -528,6 +544,22 @@
this.sbn.getTag(), this.sbn.getScore(), this.sbn.getKey(),
this.sbn.getNotification());
}
+
+ public void setContactAffinity(float contactAffinity) {
+ mContactAffinity = contactAffinity;
+ }
+
+ public float getContactAffinity() {
+ return mContactAffinity;
+ }
+
+ public boolean isRecentlyIntrusive() {
+ return mRecentlyIntrusive;
+ }
+
+ public void setRecentlyIntusive(boolean recentlyIntrusive) {
+ mRecentlyIntrusive = recentlyIntrusive;
+ }
}
private static final class ToastRecord
@@ -695,6 +727,22 @@
EventLogTags.writeNotificationVisibilityChanged(
TextUtils.join(";", newlyVisibleKeys),
TextUtils.join(";", noLongerVisibleKeys));
+ synchronized (mNotificationList) {
+ for (String key : newlyVisibleKeys) {
+ NotificationRecord r = mNotificationsByKey.get(key);
+ if (r == null) continue;
+ r.stats.onVisibilityChanged(true);
+ }
+ // Note that we might receive this event after notifications
+ // have already left the system, e.g. after dismissing from the
+ // shade. Hence not finding notifications in
+ // mNotificationsByKey is not an exceptional condition.
+ for (String key : noLongerVisibleKeys) {
+ NotificationRecord r = mNotificationsByKey.get(key);
+ if (r == null) continue;
+ r.stats.onVisibilityChanged(false);
+ }
+ }
}
};
@@ -707,7 +755,7 @@
boolean queryRemove = false;
boolean packageChanged = false;
boolean cancelNotifications = true;
-
+
if (action.equals(Intent.ACTION_PACKAGE_ADDED)
|| (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
|| action.equals(Intent.ACTION_PACKAGE_RESTARTED)
@@ -849,6 +897,8 @@
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
mHandler = new WorkerHandler();
+ mRankingThread.start();
+ mRankingHandler = new RankingWorkerHandler(mRankingThread.getLooper());
mZenModeHelper = new ZenModeHelper(getContext(), mHandler);
mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
@Override
@@ -925,21 +975,22 @@
mSettingsObserver = new SettingsObserver(mHandler);
- // spin up NotificationScorers
- String[] notificationScorerNames = resources.getStringArray(
- R.array.config_notificationScorers);
- for (String scorerName : notificationScorerNames) {
+ // spin up NotificationSignalExtractors
+ String[] extractorNames = resources.getStringArray(
+ R.array.config_notificationSignalExtractors);
+ for (String extractorName : extractorNames) {
try {
- Class<?> scorerClass = getContext().getClassLoader().loadClass(scorerName);
- NotificationScorer scorer = (NotificationScorer) scorerClass.newInstance();
- scorer.initialize(getContext());
- mScorers.add(scorer);
+ Class<?> extractorClass = getContext().getClassLoader().loadClass(extractorName);
+ NotificationSignalExtractor extractor =
+ (NotificationSignalExtractor) extractorClass.newInstance();
+ extractor.initialize(getContext());
+ mSignalExtractors.add(extractor);
} catch (ClassNotFoundException e) {
- Slog.w(TAG, "Couldn't find scorer " + scorerName + ".", e);
+ Slog.w(TAG, "Couldn't find extractor " + extractorName + ".", e);
} catch (InstantiationException e) {
- Slog.w(TAG, "Couldn't instantiate scorer " + scorerName + ".", e);
+ Slog.w(TAG, "Couldn't instantiate extractor " + extractorName + ".", e);
} catch (IllegalAccessException e) {
- Slog.w(TAG, "Problem accessing scorer " + scorerName + ".", e);
+ Slog.w(TAG, "Problem accessing extractor " + extractorName + ".", e);
}
}
@@ -1150,6 +1201,7 @@
* System-only API for getting a list of current (i.e. not cleared) notifications.
*
* Requires ACCESS_NOTIFICATIONS which is signature|system.
+ * @returns A list of all the notifications, in natural order.
*/
@Override
public StatusBarNotification[] getActiveNotifications(String callingPkg) {
@@ -1306,6 +1358,9 @@
* should be used.
*
* @param token The binder for the listener, to check that the caller is allowed
+ * @param keys the notification keys to fetch, or null for all active notifications.
+ * @returns The return value will contain the notifications specified in keys, in that
+ * order, or if keys is null, all the notifications, in natural order.
*/
@Override
public StatusBarNotification[] getActiveNotificationsFromListener(
@@ -1337,7 +1392,7 @@
@Override
public String[] getActiveNotificationKeysFromListener(INotificationListener token) {
- return NotificationManagerService.this.getActiveNotificationKeysFromListener(token);
+ return NotificationManagerService.this.getActiveNotificationKeys(token);
}
@Override
@@ -1374,7 +1429,12 @@
@Override
public void setZenModeCondition(Uri conditionId) {
enforceSystemOrSystemUI("INotificationManager.setZenModeCondition");
- mConditionProviders.setZenModeCondition(conditionId);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mConditionProviders.setZenModeCondition(conditionId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
@@ -1409,19 +1469,21 @@
}
};
- private String[] getActiveNotificationKeysFromListener(INotificationListener token) {
- synchronized (mNotificationList) {
- final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
- final ArrayList<String> keys = new ArrayList<String>();
- final int N = mNotificationList.size();
- for (int i=0; i<N; i++) {
- final StatusBarNotification sbn = mNotificationList.get(i).sbn;
- if (info.enabledAndUserMatches(sbn.getUserId())) {
- keys.add(sbn.getKey());
+ private String[] getActiveNotificationKeys(INotificationListener token) {
+ final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+ final ArrayList<String> keys = new ArrayList<String>();
+ if (info.isEnabledForCurrentProfiles()) {
+ synchronized (mNotificationList) {
+ final int N = mNotificationList.size();
+ for (int i = 0; i < N; i++) {
+ final StatusBarNotification sbn = mNotificationList.get(i).sbn;
+ if (info.enabledAndUserMatches(sbn.getUserId())) {
+ keys.add(sbn.getKey());
+ }
}
}
- return keys.toArray(new String[keys.size()]);
}
+ return keys.toArray(new String[keys.size()]);
}
void dumpImpl(PrintWriter pw) {
@@ -1578,26 +1640,23 @@
// 1. initial score: buckets of 10, around the app
int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; //[-20..20]
- // 2. Consult external heuristics (TBD)
-
- // 3. Apply local rules
-
- int initialScore = score;
- if (!mScorers.isEmpty()) {
- if (DBG) Slog.v(TAG, "Initial score is " + score + ".");
- for (NotificationScorer scorer : mScorers) {
+ // 2. extract ranking signals from the notification data
+ final StatusBarNotification n = new StatusBarNotification(
+ pkg, opPkg, id, tag, callingUid, callingPid, score, notification,
+ user);
+ NotificationRecord r = new NotificationRecord(n);
+ if (!mSignalExtractors.isEmpty()) {
+ for (NotificationSignalExtractor extractor : mSignalExtractors) {
try {
- score = scorer.getScore(notification, score);
+ RankingFuture future = extractor.process(r);
+ scheduleRankingReconsideration(future);
} catch (Throwable t) {
- Slog.w(TAG, "Scorer threw on .getScore.", t);
+ Slog.w(TAG, "NotificationSignalExtractor failed.", t);
}
}
- if (DBG) Slog.v(TAG, "Final score is " + score + ".");
}
- // add extra to indicate score modified by NotificationScorer
- notification.extras.putBoolean(Notification.EXTRA_SCORE_MODIFIED,
- score != initialScore);
+ // 3. Apply local rules
// blocked apps
if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {
@@ -1608,10 +1667,6 @@
}
}
- if (DBG) {
- Slog.v(TAG, "Assigned score=" + score + " to " + notification);
- }
-
if (score < SCORE_DISPLAY_THRESHOLD) {
// Notification will be blocked because the score is too low.
return;
@@ -1626,12 +1681,7 @@
if (DBG || intercept) Slog.v(TAG,
"pkg=" + pkg + " canInterrupt=" + canInterrupt + " intercept=" + intercept);
synchronized (mNotificationList) {
- final StatusBarNotification n = new StatusBarNotification(
- pkg, opPkg, id, tag, callingUid, callingPid, score, notification,
- user);
- NotificationRecord r = new NotificationRecord(n);
NotificationRecord old = null;
-
int index = indexOfNotificationLocked(pkg, tag, id, userId);
if (index < 0) {
mNotificationList.add(r);
@@ -1639,7 +1689,7 @@
} else {
old = mNotificationList.get(index);
mNotificationList.set(index, r);
- mUsageStats.registerUpdatedByApp(r);
+ mUsageStats.registerUpdatedByApp(r, old);
// Make sure we don't lose the foreground service state.
if (old != null) {
notification.flags |=
@@ -1651,6 +1701,8 @@
}
mNotificationsByKey.put(n.getKey(), r);
+ Collections.sort(mNotificationList, mRankingComparator);
+
// Ensure if this is a foreground service that the proper additional
// flags are set.
if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
@@ -1948,6 +2000,57 @@
}
}
+ private void scheduleRankingReconsideration(RankingFuture future) {
+ if (future != null) {
+ Message m = Message.obtain(mRankingHandler, MESSAGE_RECONSIDER_RANKING, future);
+ long delay = future.getDelay(TimeUnit.MILLISECONDS);
+ mRankingHandler.sendMessageDelayed(m, delay);
+ }
+ }
+
+ private void handleRankingReconsideration(Message message) {
+ if (!(message.obj instanceof RankingFuture)) return;
+
+ RankingFuture future = (RankingFuture) message.obj;
+ future.run();
+ try {
+ NotificationRecord record = future.get();
+ synchronized (mNotificationList) {
+ int before = mNotificationList.indexOf(record);
+ if (before != -1) {
+ Collections.sort(mNotificationList, mRankingComparator);
+ int after = mNotificationList.indexOf(record);
+
+ if (before != after) {
+ scheduleSendRankingUpdate();
+ }
+ }
+ }
+ } catch (InterruptedException e) {
+ // we're running the future explicitly, so this should never happen
+ } catch (ExecutionException e) {
+ // we're running the future explicitly, so this should never happen
+ }
+ }
+
+ private void scheduleSendRankingUpdate() {
+ mHandler.removeMessages(MESSAGE_SEND_RANKING_UPDATE);
+ Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
+ mHandler.sendMessage(m);
+ }
+
+ private void handleSendRankingUpdate() {
+ synchronized (mNotificationList) {
+ final int N = mNotificationList.size();
+ ArrayList<StatusBarNotification> sbns =
+ new ArrayList<StatusBarNotification>(N);
+ for (int i = 0; i < N; i++ ) {
+ sbns.add(mNotificationList.get(i).sbn);
+ }
+ mListeners.notifyOrderUpdateLocked(sbns);
+ }
+ }
+
private final class WorkerHandler extends Handler
{
@Override
@@ -1961,11 +2064,30 @@
case MESSAGE_SAVE_POLICY_FILE:
handleSavePolicyFile();
break;
+ case MESSAGE_SEND_RANKING_UPDATE:
+ handleSendRankingUpdate();
+ break;
+ }
+ }
+
+ }
+
+ private final class RankingWorkerHandler extends Handler
+ {
+ public RankingWorkerHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_RECONSIDER_RANKING:
+ handleRankingReconsideration(msg);
+ break;
}
}
}
-
// Notifications
// ============================================================================
static int clamp(int x, int low, int high) {
@@ -2346,9 +2468,9 @@
@Override
public void onServiceAdded(ManagedServiceInfo info) {
final INotificationListener listener = (INotificationListener) info.service;
- final String[] keys = getActiveNotificationKeysFromListener(listener);
+ final String[] keys = getActiveNotificationKeys(listener);
try {
- listener.onListenerConnected(keys);
+ listener.onListenerConnected(new NotificationOrderUpdate(keys));
} catch (RemoteException e) {
// we tried
}
@@ -2361,12 +2483,18 @@
// make a copy in case changes are made to the underlying Notification object
final StatusBarNotification sbnClone = sbn.clone();
for (final ManagedServiceInfo info : mServices) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- notifyPostedIfUserMatch(info, sbnClone);
+ if (info.isEnabledForCurrentProfiles()) {
+ final INotificationListener listener = (INotificationListener) info.service;
+ final String[] keys = getActiveNotificationKeys(listener);
+ if (keys.length > 0) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ notifyPostedIfUserMatch(info, sbnClone, keys);
+ }
+ });
}
- });
+ }
}
}
@@ -2378,39 +2506,83 @@
// NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
// notification
final StatusBarNotification sbnLight = sbn.cloneLight();
- for (ManagedServiceInfo serviceInfo : mServices) {
- final ManagedServiceInfo info = (ManagedServiceInfo) serviceInfo;
+ for (final ManagedServiceInfo info : mServices) {
+ if (info.isEnabledForCurrentProfiles()) {
+ final INotificationListener listener = (INotificationListener) info.service;
+ final String[] keys = getActiveNotificationKeys(listener);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ notifyRemovedIfUserMatch(info, sbnLight, keys);
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * asynchronously notify all listeners about a reordering of notifications
+ * @param sbns an array of {@link StatusBarNotification}s to consider. This code
+ * must not rely on mutable members of these objects, such as the
+ * {@link Notification}.
+ */
+ public void notifyOrderUpdateLocked(final ArrayList<StatusBarNotification> sbns) {
+ for (final ManagedServiceInfo serviceInfo : mServices) {
mHandler.post(new Runnable() {
@Override
public void run() {
- notifyRemovedIfUserMatch(info, sbnLight);
+ notifyOrderUpdateIfUserMatch(serviceInfo, sbns);
}
});
}
}
- private void notifyPostedIfUserMatch(ManagedServiceInfo info, StatusBarNotification sbn) {
+ private void notifyPostedIfUserMatch(final ManagedServiceInfo info,
+ final StatusBarNotification sbn, String[] keys) {
if (!info.enabledAndUserMatches(sbn.getUserId())) {
return;
}
final INotificationListener listener = (INotificationListener)info.service;
try {
- listener.onNotificationPosted(sbn);
+ listener.onNotificationPosted(sbn, new NotificationOrderUpdate(keys));
} catch (RemoteException ex) {
Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
}
}
- private void notifyRemovedIfUserMatch(ManagedServiceInfo info, StatusBarNotification sbn) {
+ private void notifyRemovedIfUserMatch(ManagedServiceInfo info, StatusBarNotification sbn,
+ String[] keys) {
if (!info.enabledAndUserMatches(sbn.getUserId())) {
return;
}
final INotificationListener listener = (INotificationListener)info.service;
try {
- listener.onNotificationRemoved(sbn);
+ listener.onNotificationRemoved(sbn, new NotificationOrderUpdate(keys));
} catch (RemoteException ex) {
Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
}
}
+
+ /**
+ * @param sbns an array of {@link StatusBarNotification}s to consider. This code
+ * must not rely on mutable members of these objects, such as the
+ * {@link Notification}.
+ */
+ public void notifyOrderUpdateIfUserMatch(ManagedServiceInfo info,
+ ArrayList<StatusBarNotification> sbns) {
+ ArrayList<String> keys = new ArrayList<String>(sbns.size());
+ for (StatusBarNotification sbn: sbns) {
+ if (info.enabledAndUserMatches(sbn.getUserId())) {
+ keys.add(sbn.getKey());
+ }
+ }
+ final INotificationListener listener = (INotificationListener)info.service;
+ try {
+ listener.onNotificationOrderUpdate(
+ new NotificationOrderUpdate(keys.toArray(new String[keys.size()])));
+ } catch (RemoteException ex) {
+ Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationSignalExtractor.java b/services/core/java/com/android/server/notification/NotificationSignalExtractor.java
new file mode 100644
index 0000000..a41fdfe
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationSignalExtractor.java
@@ -0,0 +1,41 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.android.server.notification;
+
+import android.content.Context;
+
+/**
+ * Extracts signals that will be useful to the {@link NotificationComparator} and caches them
+ * on the {@link NotificationManagerService.NotificationRecord} object. These annotations will
+ * not be passed on to {@link android.service.notification.NotificationListenerService}s.
+ */
+public interface NotificationSignalExtractor {
+
+ /** One-time initialization. */
+ public void initialize(Context context);
+
+ /**
+ * Called once per notification that is posted or updated.
+ *
+ * @return null if the work is done, or a future if there is more to do. The
+ * {@link RankingFuture} will be run on a worker thread, and if notifications are re-ordered
+ * by that execution, the {@link NotificationManagerService} may send order update
+ * events to the {@link android.service.notification.NotificationListenerService}s.
+ */
+ public RankingFuture process(NotificationManagerService.NotificationRecord notification);
+
+}
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index 45ab3d3..d81a25e 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -58,6 +58,7 @@
* Called when a notification has been posted.
*/
public synchronized void registerPostedByApp(NotificationRecord notification) {
+ notification.stats = new SingleNotificationStats();
notification.stats.posttimeElapsedMs = SystemClock.elapsedRealtime();
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
stats.numPostedByApp++;
@@ -68,7 +69,8 @@
/**
* Called when a notification has been updated.
*/
- public void registerUpdatedByApp(NotificationRecord notification) {
+ public void registerUpdatedByApp(NotificationRecord notification, NotificationRecord old) {
+ notification.stats = old.stats;
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
stats.numUpdatedByApp++;
}
@@ -78,6 +80,7 @@
* Called when the originating app removed the notification programmatically.
*/
public synchronized void registerRemovedByApp(NotificationRecord notification) {
+ notification.stats.onRemoved();
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
stats.numRemovedByApp++;
stats.collect(notification.stats);
@@ -114,9 +117,7 @@
* <p>Called after {@link #registerClickedByUser(NotificationRecord)}.</p>
*/
public synchronized void registerCancelDueToClick(NotificationRecord notification) {
- // No explicit stats for this (the click has already been registered in
- // registerClickedByUser), just make sure the single notification stats
- // are folded up into aggregated stats.
+ notification.stats.onCancel();
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
stats.collect(notification.stats);
}
@@ -128,7 +129,7 @@
* <p>Called for notifications of apps being uninstalled, for example.</p>
*/
public synchronized void registerCancelUnknown(NotificationRecord notification) {
- // Fold up individual stats.
+ notification.stats.onCancel();
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
stats.collect(notification.stats);
}
@@ -183,6 +184,9 @@
public final Aggregate posttimeMs = new Aggregate();
public final Aggregate posttimeToDismissMs = new Aggregate();
public final Aggregate posttimeToFirstClickMs = new Aggregate();
+ public final Aggregate airtimeCount = new Aggregate();
+ public final Aggregate airtimeMs = new Aggregate();
+ public final Aggregate posttimeToFirstAirtimeMs = new Aggregate();
public AggregatedStats(String key) {
this.key = key;
@@ -197,6 +201,14 @@
if (singleNotificationStats.posttimeToFirstClickMs >= 0) {
posttimeToFirstClickMs.addSample(singleNotificationStats.posttimeToFirstClickMs);
}
+ airtimeCount.addSample(singleNotificationStats.airtimeCount);
+ if (singleNotificationStats.airtimeMs >= 0) {
+ airtimeMs.addSample(singleNotificationStats.airtimeMs);
+ }
+ if (singleNotificationStats.posttimeToFirstAirtimeMs >= 0) {
+ posttimeToFirstAirtimeMs.addSample(
+ singleNotificationStats.posttimeToFirstAirtimeMs);
+ }
}
public void dump(PrintWriter pw, String indent) {
@@ -219,6 +231,9 @@
indent + " posttimeMs=" + posttimeMs + ",\n" +
indent + " posttimeToDismissMs=" + posttimeToDismissMs + ",\n" +
indent + " posttimeToFirstClickMs=" + posttimeToFirstClickMs + ",\n" +
+ indent + " airtimeCount=" + airtimeCount + ",\n" +
+ indent + " airtimeMs=" + airtimeMs + ",\n" +
+ indent + " posttimeToFirstAirtimeMs=" + posttimeToFirstAirtimeMs + ",\n" +
indent + "}";
}
}
@@ -233,6 +248,33 @@
public long posttimeToFirstClickMs = -1;
/** Elpased time since the notification was posted until it was dismissed by the user. */
public long posttimeToDismissMs = -1;
+ /** Number of times the notification has been made visible. */
+ public long airtimeCount = 0;
+ /** Time in ms between the notification was posted and first shown; -1 if never shown. */
+ public long posttimeToFirstAirtimeMs = -1;
+ /**
+ * If currently visible, SystemClock.elapsedRealtime() when the notification was made
+ * visible; -1 otherwise.
+ */
+ public long currentAirtimeStartElapsedMs = -1;
+ /** Accumulated visible time. */
+ public long airtimeMs = 0;
+
+ public long getCurrentPosttimeMs() {
+ if (posttimeElapsedMs < 0) {
+ return 0;
+ }
+ return SystemClock.elapsedRealtime() - posttimeElapsedMs;
+ }
+
+ public long getCurrentAirtimeMs() {
+ long result = airtimeMs;
+ // Add incomplete airtime if currently shown.
+ if (currentAirtimeStartElapsedMs >= 0) {
+ result+= (SystemClock.elapsedRealtime() - currentAirtimeStartElapsedMs);
+ }
+ return result;
+ }
/**
* Called when the user clicked the notification.
@@ -250,6 +292,38 @@
if (posttimeToDismissMs < 0) {
posttimeToDismissMs = SystemClock.elapsedRealtime() - posttimeElapsedMs;
}
+ finish();
+ }
+
+ public void onCancel() {
+ finish();
+ }
+
+ public void onRemoved() {
+ finish();
+ }
+
+ public void onVisibilityChanged(boolean visible) {
+ long elapsedNowMs = SystemClock.elapsedRealtime();
+ if (visible) {
+ if (currentAirtimeStartElapsedMs < 0) {
+ airtimeCount++;
+ currentAirtimeStartElapsedMs = elapsedNowMs;
+ }
+ if (posttimeToFirstAirtimeMs < 0) {
+ posttimeToFirstAirtimeMs = elapsedNowMs - posttimeElapsedMs;
+ }
+ } else {
+ if (currentAirtimeStartElapsedMs >= 0) {
+ airtimeMs += (elapsedNowMs - currentAirtimeStartElapsedMs);
+ currentAirtimeStartElapsedMs = -1;
+ }
+ }
+ }
+
+ /** The notification is leaving the system. Finalize. */
+ public void finish() {
+ onVisibilityChanged(false);
}
@Override
@@ -258,6 +332,9 @@
"posttimeElapsedMs=" + posttimeElapsedMs +
", posttimeToFirstClickMs=" + posttimeToFirstClickMs +
", posttimeToDismissMs=" + posttimeToDismissMs +
+ ", airtimeCount=" + airtimeCount +
+ ", airtimeMs=" + airtimeMs +
+ ", currentAirtimeStartElapsedMs=" + currentAirtimeStartElapsedMs +
'}';
}
}
@@ -303,7 +380,7 @@
private static final int MSG_DISMISS = 4;
private static final String DB_NAME = "notification_log.db";
- private static final int DB_VERSION = 1;
+ private static final int DB_VERSION = 2;
/** Age in ms after which events are pruned from the DB. */
private static final long HORIZON_MS = 7 * 24 * 60 * 60 * 1000L; // 1 week
@@ -327,6 +404,8 @@
private static final String COL_PRIORITY = "priority";
private static final String COL_CATEGORY = "category";
private static final String COL_ACTION_COUNT = "action_count";
+ private static final String COL_POSTTIME_MS = "posttime_ms";
+ private static final String COL_AIRTIME_MS = "airtime_ms";
private static final int EVENT_TYPE_POST = 1;
private static final int EVENT_TYPE_CLICK = 2;
@@ -352,16 +431,16 @@
long nowMs = System.currentTimeMillis();
switch (msg.what) {
case MSG_POST:
- writeEvent(r.sbn.getPostTime(), EVENT_TYPE_POST, r, true);
+ writeEvent(r.sbn.getPostTime(), EVENT_TYPE_POST, r);
break;
case MSG_CLICK:
- writeEvent(nowMs, EVENT_TYPE_CLICK, r, false);
+ writeEvent(nowMs, EVENT_TYPE_CLICK, r);
break;
case MSG_REMOVE:
- writeEvent(nowMs, EVENT_TYPE_REMOVE, r, false);
+ writeEvent(nowMs, EVENT_TYPE_REMOVE, r);
break;
case MSG_DISMISS:
- writeEvent(nowMs, EVENT_TYPE_DISMISS, r, false);
+ writeEvent(nowMs, EVENT_TYPE_DISMISS, r);
break;
default:
Log.wtf(TAG, "Unknown message type: " + msg.what);
@@ -386,14 +465,22 @@
COL_FLAGS + " INT," +
COL_PRIORITY + " INT," +
COL_CATEGORY + " TEXT," +
- COL_ACTION_COUNT + " INT" +
+ COL_ACTION_COUNT + " INT," +
+ COL_POSTTIME_MS + " INT," +
+ COL_AIRTIME_MS + " INT" +
")");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- db.execSQL("DROP TABLE IF EXISTS " + TAB_LOG);
- onCreate(db);
+ switch (oldVersion) {
+ case 1:
+ // Add COL_POSTTIME_MS, COL_AIRTIME_MS columns,
+ db.execSQL("ALTER TABLE " + TAB_LOG + " ADD COLUMN " +
+ COL_POSTTIME_MS + " INT");
+ db.execSQL("ALTER TABLE " + TAB_LOG + " ADD COLUMN " +
+ COL_AIRTIME_MS + " INT");
+ }
}
};
}
@@ -443,15 +530,16 @@
}
}
- private void writeEvent(long eventTimeMs, int eventType, NotificationRecord r,
- boolean populateNotificationDetails) {
+ private void writeEvent(long eventTimeMs, int eventType, NotificationRecord r) {
ContentValues cv = new ContentValues();
cv.put(COL_EVENT_USER_ID, r.sbn.getUser().getIdentifier());
cv.put(COL_EVENT_TIME, eventTimeMs);
cv.put(COL_EVENT_TYPE, eventType);
putNotificationIdentifiers(r, cv);
- if (populateNotificationDetails) {
+ if (eventType == EVENT_TYPE_POST) {
putNotificationDetails(r, cv);
+ } else {
+ putPosttimeAirtime(r, cv);
}
SQLiteDatabase db = mHelper.getWritableDatabase();
if (db.insert(TAB_LOG, null, cv) < 0) {
@@ -495,6 +583,11 @@
r.getNotification().actions.length : 0);
}
+ private static void putPosttimeAirtime(NotificationRecord r, ContentValues outCv) {
+ outCv.put(COL_POSTTIME_MS, r.stats.getCurrentPosttimeMs());
+ outCv.put(COL_AIRTIME_MS, r.stats.getCurrentAirtimeMs());
+ }
+
public void dump(PrintWriter pw, String indent) {
printPostFrequencies(pw, indent);
}
diff --git a/services/core/java/com/android/server/notification/RankingFuture.java b/services/core/java/com/android/server/notification/RankingFuture.java
new file mode 100644
index 0000000..d711d02
--- /dev/null
+++ b/services/core/java/com/android/server/notification/RankingFuture.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.notification;
+
+import java.util.concurrent.Delayed;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public abstract class RankingFuture
+ implements ScheduledFuture<NotificationManagerService.NotificationRecord> {
+ private static final long IMMEDIATE = 0l;
+
+ private static final int START = 0;
+ private static final int RUNNING = 1;
+ private static final int DONE = 2;
+ private static final int CANCELLED = 3;
+
+ private int mState;
+ private long mDelay;
+ protected NotificationManagerService.NotificationRecord mRecord;
+
+ public RankingFuture(NotificationManagerService.NotificationRecord record) {
+ this(record, IMMEDIATE);
+ }
+
+ public RankingFuture(NotificationManagerService.NotificationRecord record, long delay) {
+ mDelay = delay;
+ mRecord = record;
+ mState = START;
+ }
+
+ public void run() {
+ if (mState == START) {
+ mState = RUNNING;
+
+ work();
+
+ mState = DONE;
+ synchronized (this) {
+ notifyAll();
+ }
+ }
+ }
+
+ @Override
+ public long getDelay(TimeUnit unit) {
+ return unit.convert(mDelay, TimeUnit.MILLISECONDS);
+ }
+
+ @Override
+ public int compareTo(Delayed another) {
+ return Long.compare(getDelay(TimeUnit.MILLISECONDS),
+ another.getDelay(TimeUnit.MILLISECONDS));
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ if (mState == START) { // can't cancel if running or done
+ mState = CANCELLED;
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return mState == CANCELLED;
+ }
+
+ @Override
+ public boolean isDone() {
+ return mState == DONE;
+ }
+
+ @Override
+ public NotificationManagerService.NotificationRecord get()
+ throws InterruptedException, ExecutionException {
+ while (!isDone()) {
+ synchronized (this) {
+ this.wait();
+ }
+ }
+ return mRecord;
+ }
+
+ @Override
+ public NotificationManagerService.NotificationRecord get(long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ long timeoutMillis = unit.convert(timeout, TimeUnit.MILLISECONDS);
+ long start = System.currentTimeMillis();
+ long now = System.currentTimeMillis();
+ while (!isDone() && (now - start) < timeoutMillis) {
+ try {
+ wait(timeoutMillis - (now - start));
+ } catch (InterruptedException e) {
+ now = System.currentTimeMillis();
+ }
+ }
+ return mRecord;
+ }
+
+ public abstract void work();
+}
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
new file mode 100644
index 0000000..b5c2730
--- /dev/null
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -0,0 +1,304 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.android.server.notification;
+
+import android.app.Notification;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.LruCache;
+import android.util.Slog;
+
+import com.android.server.notification.NotificationManagerService.NotificationRecord;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+/**
+ * This {@link NotificationSignalExtractor} attempts to validate
+ * people references. Also elevates the priority of real people.
+ */
+public class ValidateNotificationPeople implements NotificationSignalExtractor {
+ private static final String TAG = "ValidateNotificationPeople";
+ private static final boolean INFO = true;
+ private static final boolean DEBUG = false;
+
+ private static final boolean ENABLE_PEOPLE_VALIDATOR = true;
+ private static final String SETTING_ENABLE_PEOPLE_VALIDATOR =
+ "validate_notification_people_enabled";
+ private static final String[] LOOKUP_PROJECTION = { Contacts._ID, Contacts.STARRED };
+ private static final int MAX_PEOPLE = 10;
+ private static final int PEOPLE_CACHE_SIZE = 200;
+
+ private static final float NONE = 0f;
+ private static final float VALID_CONTACT = 0.5f;
+ private static final float STARRED_CONTACT = 1f;
+
+ protected boolean mEnabled;
+ private Context mContext;
+
+ // maps raw person handle to resolved person object
+ private LruCache<String, LookupResult> mPeopleCache;
+
+ private RankingFuture validatePeople(NotificationRecord record) {
+ float affinity = NONE;
+ Bundle extras = record.getNotification().extras;
+ if (extras == null) {
+ return null;
+ }
+
+ final String[] people = getExtraPeople(extras);
+ if (people == null || people.length == 0) {
+ return null;
+ }
+
+ if (INFO) Slog.i(TAG, "Validating: " + record.sbn.getKey());
+ final LinkedList<String> pendingLookups = new LinkedList<String>();
+ for (int personIdx = 0; personIdx < people.length && personIdx < MAX_PEOPLE; personIdx++) {
+ final String handle = people[personIdx];
+ if (TextUtils.isEmpty(handle)) continue;
+
+ synchronized (mPeopleCache) {
+ LookupResult lookupResult = mPeopleCache.get(handle);
+ if (lookupResult == null || lookupResult.isExpired()) {
+ pendingLookups.add(handle);
+ } else {
+ if (DEBUG) Slog.d(TAG, "using cached lookupResult: " + lookupResult.mId);
+ }
+ if (lookupResult != null) {
+ affinity = Math.max(affinity, lookupResult.getAffinity());
+ }
+ }
+ }
+
+ // record the best available data, so far:
+ record.setContactAffinity(affinity);
+
+ if (pendingLookups.isEmpty()) {
+ if (INFO) Slog.i(TAG, "final affinity: " + affinity);
+ return null;
+ }
+
+ if (DEBUG) Slog.d(TAG, "Pending: future work scheduled for: " + record.sbn.getKey());
+ return new RankingFuture(record) {
+ @Override
+ public void work() {
+ if (INFO) Slog.i(TAG, "Executing: validation for: " + mRecord.sbn.getKey());
+ float affinity = NONE;
+ for (final String handle: pendingLookups) {
+ LookupResult lookupResult = null;
+ final Uri uri = Uri.parse(handle);
+ if ("tel".equals(uri.getScheme())) {
+ if (DEBUG) Slog.d(TAG, "checking telephone URI: " + handle);
+ lookupResult = resolvePhoneContact(uri.getSchemeSpecificPart());
+ } else if ("mailto".equals(uri.getScheme())) {
+ if (DEBUG) Slog.d(TAG, "checking mailto URI: " + handle);
+ lookupResult = resolveEmailContact(uri.getSchemeSpecificPart());
+ } else if (handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) {
+ if (DEBUG) Slog.d(TAG, "checking lookup URI: " + handle);
+ lookupResult = searchContacts(uri);
+ } else {
+ lookupResult = new LookupResult(); // invalid person for the cache
+ Slog.w(TAG, "unsupported URI " + handle);
+ }
+ if (lookupResult != null) {
+ synchronized (mPeopleCache) {
+ mPeopleCache.put(handle, lookupResult);
+ }
+ affinity = Math.max(affinity, lookupResult.getAffinity());
+ }
+ }
+ float affinityBound = mRecord.getContactAffinity();
+ affinity = Math.max(affinity, affinityBound);
+ mRecord.setContactAffinity(affinity);
+ if (INFO) Slog.i(TAG, "final affinity: " + affinity);
+ }
+ };
+ }
+
+ private String[] getExtraPeople(Bundle extras) {
+ String[] people = extras.getStringArray(Notification.EXTRA_PEOPLE);
+ if (people != null) {
+ return people;
+ }
+
+ ArrayList<String> stringArray = extras.getStringArrayList(Notification.EXTRA_PEOPLE);
+ if (stringArray != null) {
+ return (String[]) stringArray.toArray();
+ }
+
+ String string = extras.getString(Notification.EXTRA_PEOPLE);
+ if (string != null) {
+ people = new String[1];
+ people[0] = string;
+ return people;
+ }
+ char[] charArray = extras.getCharArray(Notification.EXTRA_PEOPLE);
+ if (charArray != null) {
+ people = new String[1];
+ people[0] = new String(charArray);
+ return people;
+ }
+
+ CharSequence charSeq = extras.getCharSequence(Notification.EXTRA_PEOPLE);
+ if (charSeq != null) {
+ people = new String[1];
+ people[0] = charSeq.toString();
+ return people;
+ }
+
+ CharSequence[] charSeqArray = extras.getCharSequenceArray(Notification.EXTRA_PEOPLE);
+ if (charSeqArray != null) {
+ final int N = charSeqArray.length;
+ people = new String[N];
+ for (int i = 0; i < N; i++) {
+ people[i] = charSeqArray[i].toString();
+ }
+ return people;
+ }
+
+ ArrayList<CharSequence> charSeqList =
+ extras.getCharSequenceArrayList(Notification.EXTRA_PEOPLE);
+ if (charSeqList != null) {
+ final int N = charSeqList.size();
+ people = new String[N];
+ for (int i = 0; i < N; i++) {
+ people[i] = charSeqList.get(i).toString();
+ }
+ return people;
+ }
+ return null;
+ }
+
+ private LookupResult resolvePhoneContact(final String number) {
+ Uri phoneUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
+ Uri.encode(number));
+ return searchContacts(phoneUri);
+ }
+
+ private LookupResult resolveEmailContact(final String email) {
+ Uri numberUri = Uri.withAppendedPath(
+ ContactsContract.CommonDataKinds.Email.CONTENT_LOOKUP_URI,
+ Uri.encode(email));
+ return searchContacts(numberUri);
+ }
+
+ private LookupResult searchContacts(Uri lookupUri) {
+ LookupResult lookupResult = new LookupResult();
+ Cursor c = null;
+ try {
+ c = mContext.getContentResolver().query(lookupUri, LOOKUP_PROJECTION, null, null, null);
+ if (c != null && c.getCount() > 0) {
+ c.moveToFirst();
+ lookupResult.readContact(c);
+ }
+ } catch(Throwable t) {
+ Slog.w(TAG, "Problem getting content resolver or performing contacts query.", t);
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ return lookupResult;
+ }
+
+ public void initialize(Context context) {
+ if (DEBUG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
+ mContext = context;
+ mPeopleCache = new LruCache<String, LookupResult>(PEOPLE_CACHE_SIZE);
+ mEnabled = ENABLE_PEOPLE_VALIDATOR && 1 == Settings.Global.getInt(
+ mContext.getContentResolver(), SETTING_ENABLE_PEOPLE_VALIDATOR, 1);
+ }
+
+ public RankingFuture process(NotificationManagerService.NotificationRecord record) {
+ if (!mEnabled) {
+ if (INFO) Slog.i(TAG, "disabled");
+ return null;
+ }
+ if (record == null || record.getNotification() == null) {
+ if (INFO) Slog.i(TAG, "skipping empty notification");
+ return null;
+ }
+ return validatePeople(record);
+ }
+
+ private static class LookupResult {
+ private static final long CONTACT_REFRESH_MILLIS = 60 * 60 * 1000; // 1hr
+ public static final int INVALID_ID = -1;
+
+ private final long mExpireMillis;
+ private int mId;
+ private boolean mStarred;
+
+ public LookupResult() {
+ mId = INVALID_ID;
+ mStarred = false;
+ mExpireMillis = System.currentTimeMillis() + CONTACT_REFRESH_MILLIS;
+ }
+
+ public void readContact(Cursor cursor) {
+ final int idIdx = cursor.getColumnIndex(Contacts._ID);
+ if (idIdx >= 0) {
+ mId = cursor.getInt(idIdx);
+ if (DEBUG) Slog.d(TAG, "contact _ID is: " + mId);
+ } else {
+ if (DEBUG) Slog.d(TAG, "invalid cursor: no _ID");
+ }
+ final int starIdx = cursor.getColumnIndex(Contacts.STARRED);
+ if (starIdx >= 0) {
+ mStarred = cursor.getInt(starIdx) != 0;
+ if (DEBUG) Slog.d(TAG, "contact STARRED is: " + mStarred);
+ } else {
+ if (DEBUG) Slog.d(TAG, "invalid cursor: no STARRED");
+ }
+ }
+
+ public boolean isExpired() {
+ return mExpireMillis < System.currentTimeMillis();
+ }
+
+ public boolean isInvalid() {
+ return mId == INVALID_ID || isExpired();
+ }
+
+ public float getAffinity() {
+ if (isInvalid()) {
+ return NONE;
+ } else if (mStarred) {
+ return STARRED_CONTACT;
+ } else {
+ return VALID_CONTACT;
+ }
+ }
+
+ public LookupResult setStarred(boolean starred) {
+ mStarred = starred;
+ return this;
+ }
+
+ public LookupResult setId(int id) {
+ mId = id;
+ return this;
+ }
+ }
+}
+
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index bd28e04..5e3325c 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -17,11 +17,9 @@
package com.android.server.pm;
import android.app.AppGlobals;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ILauncherApps;
import android.content.pm.IOnAppsChangedListener;
@@ -157,10 +155,26 @@
}
}
+ /**
+ * Checks if the user is enabled.
+ */
+ private boolean isUserEnabled(UserHandle user) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ UserInfo targetUserInfo = mUm.getUserInfo(user.getIdentifier());
+ return targetUserInfo != null && targetUserInfo.isEnabled();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
@Override
public List<ResolveInfo> getLauncherActivities(String packageName, UserHandle user)
throws RemoteException {
ensureInUserProfiles(user, "Cannot retrieve activities for unrelated profile " + user);
+ if (!isUserEnabled(user)) {
+ return new ArrayList<ResolveInfo>();
+ }
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
@@ -179,6 +193,9 @@
public ResolveInfo resolveActivity(Intent intent, UserHandle user)
throws RemoteException {
ensureInUserProfiles(user, "Cannot resolve activity for unrelated profile " + user);
+ if (!isUserEnabled(user)) {
+ return null;
+ }
long ident = Binder.clearCallingIdentity();
try {
@@ -193,6 +210,10 @@
public boolean isPackageEnabled(String packageName, UserHandle user)
throws RemoteException {
ensureInUserProfiles(user, "Cannot check package for unrelated profile " + user);
+ if (!isUserEnabled(user)) {
+ return false;
+ }
+
long ident = Binder.clearCallingIdentity();
try {
IPackageManager pm = AppGlobals.getPackageManager();
@@ -207,6 +228,10 @@
public boolean isActivityEnabled(ComponentName component, UserHandle user)
throws RemoteException {
ensureInUserProfiles(user, "Cannot check component for unrelated profile " + user);
+ if (!isUserEnabled(user)) {
+ return false;
+ }
+
long ident = Binder.clearCallingIdentity();
try {
IPackageManager pm = AppGlobals.getPackageManager();
@@ -221,6 +246,9 @@
public void startActivityAsUser(ComponentName component, Rect sourceBounds,
Bundle opts, UserHandle user) throws RemoteException {
ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user);
+ if (!isUserEnabled(user)) {
+ throw new IllegalStateException("Cannot start activity for disabled profile " + user);
+ }
Intent launchIntent = new Intent(Intent.ACTION_MAIN);
launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
@@ -228,7 +256,6 @@
launchIntent.setSourceBounds(sourceBounds);
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- final int callingUserId = UserHandle.getCallingUserId();
long ident = Binder.clearCallingIdentity();
try {
mContext.startActivityAsUser(launchIntent, opts, user);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
new file mode 100644
index 0000000..5fdfce4
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.content.pm.PackageManager.INSTALL_ALL_USERS;
+import static android.content.pm.PackageManager.INSTALL_FROM_ADB;
+import static android.content.pm.PackageManager.INSTALL_REPLACE_EXISTING;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageInstaller;
+import android.content.pm.IPackageInstallerSession;
+import android.content.pm.PackageInstallerParams;
+import android.os.Binder;
+import android.os.FileUtils;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.IoThread;
+import com.google.android.collect.Sets;
+
+import java.io.File;
+
+public class PackageInstallerService extends IPackageInstaller.Stub {
+ private static final String TAG = "PackageInstaller";
+
+ // TODO: destroy sessions with old timestamps
+ // TODO: remove outstanding sessions when installer package goes away
+
+ private final Context mContext;
+ private final PackageManagerService mPm;
+ private final AppOpsManager mAppOps;
+
+ private final File mStagingDir;
+
+ private final HandlerThread mInstallThread = new HandlerThread(TAG);
+ private final Callback mCallback = new Callback();
+
+ @GuardedBy("mSessions")
+ private int mNextSessionId;
+ @GuardedBy("mSessions")
+ private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>();
+
+ public PackageInstallerService(Context context, PackageManagerService pm, File stagingDir) {
+ mContext = context;
+ mPm = pm;
+ mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+
+ mStagingDir = stagingDir;
+ mStagingDir.mkdirs();
+
+ synchronized (mSessions) {
+ readSessionsLocked();
+
+ // Clean up orphaned staging directories
+ final ArraySet<String> dirs = Sets.newArraySet(mStagingDir.list());
+ for (int i = 0; i < mSessions.size(); i++) {
+ dirs.remove(Integer.toString(mSessions.keyAt(i)));
+ }
+ for (String dirName : dirs) {
+ Slog.w(TAG, "Deleting orphan session " + dirName);
+ final File dir = new File(mStagingDir, dirName);
+ FileUtils.deleteContents(dir);
+ dir.delete();
+ }
+ }
+ }
+
+ private void readSessionsLocked() {
+ // TODO: implement persisting
+ mSessions.clear();
+ mNextSessionId = 1;
+ }
+
+ private void writeSessionsLocked() {
+ // TODO: implement persisting
+ }
+
+ private void writeSessionsAsync() {
+ IoThread.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mSessions) {
+ writeSessionsLocked();
+ }
+ }
+ });
+ }
+
+ @Override
+ public int createSession(int userId, String installerPackageName,
+ PackageInstallerParams params) {
+ final int callingUid = Binder.getCallingUid();
+ mPm.enforceCrossUserPermission(callingUid, userId, false, TAG);
+ mAppOps.checkPackage(callingUid, installerPackageName);
+
+ if (mPm.isUserRestricted(UserHandle.getUserId(callingUid),
+ UserManager.DISALLOW_INSTALL_APPS)) {
+ throw new SecurityException("User restriction prevents installing");
+ }
+
+ if ((callingUid == Process.SHELL_UID) || (callingUid == 0)) {
+ params.installFlags |= INSTALL_FROM_ADB;
+ } else {
+ params.installFlags &= ~INSTALL_FROM_ADB;
+ params.installFlags &= ~INSTALL_ALL_USERS;
+ params.installFlags |= INSTALL_REPLACE_EXISTING;
+ }
+
+ synchronized (mSessions) {
+ final int sessionId = allocateSessionIdLocked();
+ final long createdMillis = System.currentTimeMillis();
+ final File sessionDir = new File(mStagingDir, Integer.toString(sessionId));
+ sessionDir.mkdirs();
+
+ final PackageInstallerSession session = new PackageInstallerSession(mCallback, mPm,
+ sessionId, userId, installerPackageName, callingUid, params, createdMillis,
+ sessionDir, mInstallThread.getLooper());
+ mSessions.put(sessionId, session);
+
+ writeSessionsAsync();
+ return sessionId;
+ }
+ }
+
+ @Override
+ public IPackageInstallerSession openSession(int sessionId) {
+ synchronized (mSessions) {
+ final PackageInstallerSession session = mSessions.get(sessionId);
+ if (session == null) {
+ throw new IllegalStateException("Missing session " + sessionId);
+ }
+ if (Binder.getCallingUid() != session.installerUid) {
+ throw new SecurityException("Caller has no access to session " + sessionId);
+ }
+ return session;
+ }
+ }
+
+ private int allocateSessionIdLocked() {
+ if (mSessions.get(mNextSessionId) != null) {
+ throw new IllegalStateException("Next session already allocated");
+ }
+ return mNextSessionId++;
+ }
+
+ @Override
+ public int[] getSessions(int userId, String installerPackageName) {
+ final int callingUid = Binder.getCallingUid();
+ mPm.enforceCrossUserPermission(callingUid, userId, false, TAG);
+ mAppOps.checkPackage(callingUid, installerPackageName);
+
+ int[] matching = new int[0];
+ synchronized (mSessions) {
+ for (int i = 0; i < mSessions.size(); i++) {
+ final int key = mSessions.keyAt(i);
+ final PackageInstallerSession session = mSessions.valueAt(i);
+ if (session.userId == userId
+ && session.installerPackageName.equals(installerPackageName)) {
+ matching = ArrayUtils.appendInt(matching, key);
+ }
+ }
+ }
+ return matching;
+ }
+
+ @Override
+ public void uninstall(int userId, String basePackageName, IPackageDeleteObserver observer) {
+ mPm.deletePackageAsUser(basePackageName, observer, userId, 0);
+ }
+
+ @Override
+ public void uninstallSplit(int userId, String basePackageName, String overlayName,
+ IPackageDeleteObserver observer) {
+ // TODO: flesh out once PM has split support
+ throw new UnsupportedOperationException();
+ }
+
+ class Callback {
+ public void onProgressChanged(PackageInstallerSession session) {
+ // TODO: notify listeners
+ }
+
+ public void onSessionInvalid(PackageInstallerSession session) {
+ writeSessionsAsync();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
new file mode 100644
index 0000000..f90d7ab
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -0,0 +1,539 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
+import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
+import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
+import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.IPackageInstallerSession;
+import android.content.pm.PackageInstallerParams;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageLite;
+import android.content.pm.Signature;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.SELinux;
+import android.system.ErrnoException;
+import android.system.OsConstants;
+import android.system.StructStat;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
+
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+import libcore.io.Streams;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+public class PackageInstallerSession extends IPackageInstallerSession.Stub {
+ private static final String TAG = "PackageInstaller";
+
+ private final PackageInstallerService.Callback mCallback;
+ private final PackageManagerService mPm;
+ private final Handler mHandler;
+
+ public final int sessionId;
+ public final int userId;
+ public final String installerPackageName;
+ /** UID not persisted */
+ public final int installerUid;
+ public final PackageInstallerParams params;
+ public final long createdMillis;
+ public final File sessionDir;
+
+ private static final int MSG_INSTALL = 0;
+
+ private Handler.Callback mHandlerCallback = new Handler.Callback() {
+ @Override
+ public boolean handleMessage(Message msg) {
+ synchronized (mLock) {
+ if (msg.obj != null) {
+ mRemoteObserver = (IPackageInstallObserver2) msg.obj;
+ }
+
+ try {
+ installLocked();
+ } catch (InstallFailedException e) {
+ Slog.e(TAG, "Install failed: " + e);
+ try {
+ mRemoteObserver.packageInstalled(mPackageName, null, e.error);
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ return true;
+ }
+ }
+ };
+
+ private final Object mLock = new Object();
+
+ private int mProgress;
+
+ private String mPackageName;
+ private int mVersionCode;
+ private Signature[] mSignatures;
+
+ private boolean mMutationsAllowed;
+ private boolean mVerifierConfirmed;
+ private boolean mPermissionsConfirmed;
+ private boolean mInvalid;
+
+ private ArrayList<WritePipe> mPipes = new ArrayList<>();
+
+ private IPackageInstallObserver2 mRemoteObserver;
+
+ public PackageInstallerSession(PackageInstallerService.Callback callback,
+ PackageManagerService pm, int sessionId, int userId, String installerPackageName,
+ int installerUid, PackageInstallerParams params, long createdMillis, File sessionDir,
+ Looper looper) {
+ mCallback = callback;
+ mPm = pm;
+ mHandler = new Handler(looper, mHandlerCallback);
+
+ this.sessionId = sessionId;
+ this.userId = userId;
+ this.installerPackageName = installerPackageName;
+ this.installerUid = installerUid;
+ this.params = params;
+ this.createdMillis = createdMillis;
+ this.sessionDir = sessionDir;
+
+ // Check against any explicitly provided signatures
+ mSignatures = params.signatures;
+
+ // TODO: splice in flag when restoring persisted session
+ mMutationsAllowed = true;
+
+ if (pm.checkPermission(android.Manifest.permission.INSTALL_PACKAGES, installerPackageName)
+ == PackageManager.PERMISSION_GRANTED) {
+ mPermissionsConfirmed = true;
+ }
+ }
+
+ @Override
+ public void updateProgress(int progress) {
+ mProgress = progress;
+ mCallback.onProgressChanged(this);
+ }
+
+ @Override
+ public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
+ // TODO: relay over to DCS when installing to ASEC
+
+ // Quick sanity check of state, and allocate a pipe for ourselves. We
+ // then do heavy disk allocation outside the lock, but this open pipe
+ // will block any attempted install transitions.
+ final WritePipe pipe;
+ synchronized (mLock) {
+ if (!mMutationsAllowed) {
+ throw new IllegalStateException("Mutations not allowed");
+ }
+
+ pipe = new WritePipe();
+ mPipes.add(pipe);
+ }
+
+ try {
+ // Use installer provided name for now; we always rename later
+ if (!FileUtils.isValidExtFilename(name)) {
+ throw new IllegalArgumentException("Invalid name: " + name);
+ }
+ final File target = new File(sessionDir, name);
+
+ final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(),
+ OsConstants.O_CREAT | OsConstants.O_WRONLY, 00700);
+
+ // If caller specified a total length, allocate it for them. Free up
+ // cache space to grow, if needed.
+ if (lengthBytes > 0) {
+ final StructStat stat = Libcore.os.fstat(targetFd);
+ final long deltaBytes = lengthBytes - stat.st_size;
+ if (deltaBytes > 0) {
+ mPm.freeStorage(deltaBytes);
+ }
+ Libcore.os.posix_fallocate(targetFd, 0, lengthBytes);
+ }
+
+ if (offsetBytes > 0) {
+ Libcore.os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
+ }
+
+ pipe.setTargetFd(targetFd);
+ pipe.start();
+ return pipe.getWriteFd();
+
+ } catch (ErrnoException e) {
+ throw new IllegalStateException("Failed to write", e);
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to write", e);
+ }
+ }
+
+ @Override
+ public void install(IPackageInstallObserver2 observer) {
+ Preconditions.checkNotNull(observer);
+ mHandler.obtainMessage(MSG_INSTALL, observer).sendToTarget();
+ }
+
+ private void installLocked() throws InstallFailedException {
+ if (mInvalid) {
+ throw new InstallFailedException(INSTALL_FAILED_ALREADY_EXISTS, "Invalid session");
+ }
+
+ // Verify that all writers are hands-off
+ if (mMutationsAllowed) {
+ for (WritePipe pipe : mPipes) {
+ if (!pipe.isClosed()) {
+ throw new InstallFailedException(INSTALL_FAILED_PACKAGE_CHANGED,
+ "Files still open");
+ }
+ }
+ mMutationsAllowed = false;
+
+ // TODO: persist disabled mutations before going forward, since
+ // beyond this point we may have hardlinks to the valid install
+ }
+
+ // Verify that stage looks sane with respect to existing application.
+ // This currently only ensures packageName, versionCode, and certificate
+ // consistency.
+ validateInstallLocked();
+
+ Preconditions.checkNotNull(mPackageName);
+ Preconditions.checkNotNull(mSignatures);
+
+ if (!mVerifierConfirmed) {
+ // TODO: async communication with verifier
+ // when they confirm, we'll kick off another install() pass
+ mVerifierConfirmed = true;
+ }
+
+ if (!mPermissionsConfirmed) {
+ // TODO: async confirm permissions with user
+ // when they confirm, we'll kick off another install() pass
+ mPermissionsConfirmed = true;
+ }
+
+ // Unpack any native libraries contained in this session
+ unpackNativeLibraries();
+
+ // Inherit any packages and native libraries from existing install that
+ // haven't been overridden.
+ if (!params.fullInstall) {
+ spliceExistingFilesIntoStage();
+ }
+
+ // TODO: for ASEC based applications, grow and stream in packages
+
+ // We've reached point of no return; call into PMS to install the stage.
+ // Regardless of success or failure we always destroy session.
+ final IPackageInstallObserver2 remoteObserver = mRemoteObserver;
+ final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
+ @Override
+ public void packageInstalled(String basePackageName, Bundle extras, int returnCode)
+ throws RemoteException {
+ destroy();
+ remoteObserver.packageInstalled(basePackageName, extras, returnCode);
+ }
+ };
+
+ mPm.installStage(mPackageName, this.sessionDir, localObserver, params.installFlags);
+ }
+
+ /**
+ * Validate install by confirming that all application packages are have
+ * consistent package name, version code, and signing certificates.
+ * <p>
+ * Renames package files in stage to match split names defined inside.
+ */
+ private void validateInstallLocked() throws InstallFailedException {
+ mPackageName = null;
+ mVersionCode = -1;
+ mSignatures = null;
+
+ final File[] files = sessionDir.listFiles();
+ if (ArrayUtils.isEmpty(files)) {
+ throw new InstallFailedException(INSTALL_FAILED_INVALID_APK, "No packages staged");
+ }
+
+ final ArraySet<String> seenSplits = new ArraySet<>();
+
+ // Verify that all staged packages are internally consistent
+ for (File file : files) {
+ final PackageLite info = PackageParser.parsePackageLite(file.getAbsolutePath(),
+ PackageParser.PARSE_GET_SIGNATURES);
+ if (info == null) {
+ throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
+ "Failed to parse " + file);
+ }
+
+ if (!seenSplits.add(info.splitName)) {
+ throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
+ "Split " + info.splitName + " was defined multiple times");
+ }
+
+ // Use first package to define unknown values
+ if (mPackageName != null) {
+ mPackageName = info.packageName;
+ mVersionCode = info.versionCode;
+ }
+ if (mSignatures != null) {
+ mSignatures = info.signatures;
+ }
+
+ assertPackageConsistent(String.valueOf(file), info.packageName, info.versionCode,
+ info.signatures);
+
+ // Take this opportunity to enforce uniform naming
+ final String name;
+ if (info.splitName == null) {
+ name = info.packageName + ".apk";
+ } else {
+ name = info.packageName + "-" + info.splitName + ".apk";
+ }
+ if (!FileUtils.isValidExtFilename(name)) {
+ throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
+ "Invalid filename: " + name);
+ }
+ if (!file.getName().equals(name)) {
+ file.renameTo(new File(file.getParentFile(), name));
+ }
+ }
+
+ // TODO: shift package signature verification to installer; we're
+ // currently relying on PMS to do this.
+ // TODO: teach about compatible upgrade keysets.
+
+ if (params.fullInstall) {
+ // Full installs must include a base package
+ if (!seenSplits.contains(null)) {
+ throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
+ "Full install must include a base package");
+ }
+
+ } else {
+ // Partial installs must be consistent with existing install.
+ final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
+ if (app == null) {
+ throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
+ "Missing existing base package for " + mPackageName);
+ }
+
+ final PackageLite info = PackageParser.parsePackageLite(app.sourceDir,
+ PackageParser.PARSE_GET_SIGNATURES);
+ if (info == null) {
+ throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
+ "Failed to parse existing base " + app.sourceDir);
+ }
+
+ assertPackageConsistent("Existing base", info.packageName, info.versionCode,
+ info.signatures);
+ }
+ }
+
+ private void assertPackageConsistent(String tag, String packageName, int versionCode,
+ Signature[] signatures) throws InstallFailedException {
+ if (!mPackageName.equals(packageName)) {
+ throw new InstallFailedException(INSTALL_FAILED_INVALID_APK, tag + " package "
+ + packageName + " inconsistent with " + mPackageName);
+ }
+ if (mVersionCode != versionCode) {
+ throw new InstallFailedException(INSTALL_FAILED_INVALID_APK, tag
+ + " version code " + versionCode + " inconsistent with "
+ + mVersionCode);
+ }
+ if (!Signature.areExactMatch(mSignatures, signatures)) {
+ throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
+ tag + " signatures are inconsistent");
+ }
+ }
+
+ /**
+ * Application is already installed; splice existing files that haven't been
+ * overridden into our stage.
+ */
+ private void spliceExistingFilesIntoStage() throws InstallFailedException {
+ final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
+ final File existingDir = new File(app.sourceDir).getParentFile();
+
+ try {
+ linkTreeIgnoringExisting(existingDir, sessionDir);
+ } catch (ErrnoException e) {
+ throw new InstallFailedException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Failed to splice into stage");
+ }
+ }
+
+ /**
+ * Recursively hard link all files from source directory tree to target.
+ * When a file already exists in the target tree, it leaves that file
+ * intact.
+ */
+ private void linkTreeIgnoringExisting(File sourceDir, File targetDir) throws ErrnoException {
+ final File[] sourceContents = sourceDir.listFiles();
+ if (ArrayUtils.isEmpty(sourceContents)) return;
+
+ for (File sourceFile : sourceContents) {
+ final File targetFile = new File(targetDir, sourceFile.getName());
+
+ if (sourceFile.isDirectory()) {
+ targetFile.mkdir();
+ linkTreeIgnoringExisting(sourceFile, targetFile);
+ } else {
+ Libcore.os.link(sourceFile.getAbsolutePath(), targetFile.getAbsolutePath());
+ }
+ }
+ }
+
+ private void unpackNativeLibraries() throws InstallFailedException {
+ final File libDir = new File(sessionDir, "lib");
+
+ if (!libDir.mkdir()) {
+ throw new InstallFailedException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Failed to create " + libDir);
+ }
+
+ try {
+ Libcore.os.chmod(libDir.getAbsolutePath(), 0755);
+ } catch (ErrnoException e) {
+ throw new InstallFailedException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Failed to prepare " + libDir + ": " + e);
+ }
+
+ if (!SELinux.restorecon(libDir)) {
+ throw new InstallFailedException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Failed to set context on " + libDir);
+ }
+
+ // Unpack all native libraries under stage
+ final File[] files = sessionDir.listFiles();
+ if (ArrayUtils.isEmpty(files)) {
+ throw new InstallFailedException(INSTALL_FAILED_INVALID_APK, "No packages staged");
+ }
+
+ for (File file : files) {
+ final NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(file);
+ try {
+ final int abiIndex = NativeLibraryHelper.findSupportedAbi(handle,
+ Build.SUPPORTED_ABIS);
+ if (abiIndex >= 0) {
+ int copyRet = NativeLibraryHelper.copyNativeBinariesIfNeededLI(handle, libDir,
+ Build.SUPPORTED_ABIS[abiIndex]);
+ if (copyRet != INSTALL_SUCCEEDED) {
+ throw new InstallFailedException(copyRet,
+ "Failed to copy native libraries for " + file);
+ }
+ } else if (abiIndex != PackageManager.NO_NATIVE_LIBRARIES) {
+ throw new InstallFailedException(abiIndex,
+ "Failed to copy native libraries for " + file);
+ }
+ } finally {
+ handle.close();
+ }
+ }
+ }
+
+ @Override
+ public void destroy() {
+ try {
+ synchronized (mLock) {
+ mInvalid = true;
+ }
+ FileUtils.deleteContents(sessionDir);
+ sessionDir.delete();
+ } finally {
+ mCallback.onSessionInvalid(this);
+ }
+ }
+
+ private static class WritePipe extends Thread {
+ private final ParcelFileDescriptor[] mPipe;
+
+ private FileDescriptor mTargetFd;
+
+ private volatile boolean mClosed;
+
+ public WritePipe() {
+ try {
+ mPipe = ParcelFileDescriptor.createPipe();
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to create pipe");
+ }
+ }
+
+ public boolean isClosed() {
+ return mClosed;
+ }
+
+ public void setTargetFd(FileDescriptor targetFd) {
+ mTargetFd = targetFd;
+ }
+
+ public ParcelFileDescriptor getWriteFd() {
+ return mPipe[1];
+ }
+
+ @Override
+ public void run() {
+ FileInputStream in = null;
+ FileOutputStream out = null;
+ try {
+ // TODO: look at switching to sendfile(2) to speed up
+ in = new FileInputStream(mPipe[0].getFileDescriptor());
+ out = new FileOutputStream(mTargetFd);
+ Streams.copy(in, out);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to stream data: " + e);
+ } finally {
+ IoUtils.closeQuietly(mPipe[0]);
+ IoUtils.closeQuietly(mTargetFd);
+ mClosed = true;
+ }
+ }
+ }
+
+ private class InstallFailedException extends Exception {
+ private final int error;
+
+ public InstallFailedException(int error, String detailMessage) {
+ super(detailMessage);
+ this.error = error;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c8b61f1..f9eabcd 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.GRANT_REVOKE_PERMISSIONS;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.INSTALL_PACKAGES;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
@@ -59,6 +60,7 @@
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
+import android.app.PackageInstallObserver;
import android.app.admin.IDevicePolicyManager;
import android.app.backup.IBackupManager;
import android.content.BroadcastReceiver;
@@ -78,6 +80,7 @@
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageInstallObserver;
import android.content.pm.IPackageInstallObserver2;
+import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageManager;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
@@ -86,6 +89,7 @@
import android.content.pm.PackageCleanItem;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
+import android.content.pm.PackageInstallerParams;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser.ActivityIntentInfo;
import android.content.pm.PackageParser;
@@ -157,7 +161,6 @@
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
-import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.text.SimpleDateFormat;
@@ -179,6 +182,7 @@
import dalvik.system.DexFile;
import dalvik.system.StaleDexCacheError;
import dalvik.system.VMRuntime;
+
import libcore.io.IoUtils;
/**
@@ -351,6 +355,8 @@
// apps.
final File mDrmAppPrivateInstallDir;
+ final File mAppStagingDir;
+
// ----------------------------------------------------------------
// Lock for state used when installing and doing other long running
@@ -457,6 +463,8 @@
final SparseArray<PackageVerificationState> mPendingVerification
= new SparseArray<PackageVerificationState>();
+ final PackageInstallerService mInstallerService;
+
HashSet<PackageParser.Package> mDeferredDexOpt = null;
/** Token for keys in mPendingVerification. */
@@ -613,9 +621,15 @@
private final AtomicLong mLastWritten = new AtomicLong(0);
private final AtomicBoolean mBackgroundWriteRunning = new AtomicBoolean(false);
+ private boolean mIsFirstBoot = false;
+
+ boolean isFirstBoot() {
+ return mIsFirstBoot;
+ }
+
void write(boolean force) {
if (force) {
- write();
+ writeInternal();
return;
}
if (SystemClock.elapsedRealtime() - mLastWritten.get() < WRITE_INTERVAL
@@ -627,7 +641,7 @@
@Override
public void run() {
try {
- write(true);
+ writeInternal();
} finally {
mBackgroundWriteRunning.set(false);
}
@@ -636,7 +650,7 @@
}
}
- private void write() {
+ private void writeInternal() {
synchronized (mPackages) {
synchronized (mFileLock) {
AtomicFile file = getFile();
@@ -701,6 +715,7 @@
pkg.mLastPackageUsageTimeInMills = timeInMillis;
}
} catch (FileNotFoundException expected) {
+ mIsFirstBoot = true;
} catch (IOException e) {
Log.w(TAG, "Failed to read package usage times", e);
} finally {
@@ -1332,6 +1347,7 @@
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mUserAppDataDir = new File(dataDir, "user");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
+ mAppStagingDir = new File(dataDir, "app-staging");
sUserManager = new UserManagerService(context, this,
mInstallLock, mPackages);
@@ -1694,14 +1710,17 @@
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
- // Now after opening every single application zip, make sure they
- // are all flushed. Not really needed, but keeps things nice and
- // tidy.
- Runtime.getRuntime().gc();
mRequiredVerifierPackage = getRequiredVerifierLPr();
} // synchronized (mPackages)
} // synchronized (mInstallLock)
+
+ mInstallerService = new PackageInstallerService(context, this, mAppStagingDir);
+
+ // Now after opening every single application zip, make sure they
+ // are all flushed. Not really needed, but keeps things nice and
+ // tidy.
+ Runtime.getRuntime().gc();
}
private static void pruneDexFiles(File cacheDir) {
@@ -1745,7 +1764,7 @@
@Override
public boolean isFirstBoot() {
- return !mRestoredSettings;
+ return !mRestoredSettings || mPackageUsage.isFirstBoot();
}
@Override
@@ -2245,7 +2264,8 @@
if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) {
return null;
}
- pkg = new PackageParser.Package(packageName);
+ // TODO: teach about reading split name
+ pkg = new PackageParser.Package(packageName, null);
pkg.applicationInfo.packageName = packageName;
pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
@@ -2253,7 +2273,7 @@
pkg.applicationInfo.dataDir =
getDataPathForPackage(packageName, 0).getPath();
pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;
- pkg.applicationInfo.requiredCpuAbi = ps.requiredCpuAbiString;
+ pkg.applicationInfo.cpuAbi = ps.cpuAbiString;
}
return generatePackageInfo(pkg, flags, userId);
}
@@ -2343,6 +2363,14 @@
});
}
+ void freeStorage(long freeStorageSize) throws IOException {
+ synchronized (mInstallLock) {
+ if (mInstaller.freeCache(freeStorageSize) < 0) {
+ throw new IOException("Failed to free enough space");
+ }
+ }
+ }
+
@Override
public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
@@ -2526,10 +2554,9 @@
* Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS
* or INTERACT_ACROSS_USERS_FULL permissions, if the userid is not for the caller.
* @param message the message to log on security exception
- * @return
*/
- private void enforceCrossUserPermission(int callingUid, int userId,
- boolean requireFullPermission, String message) {
+ void enforceCrossUserPermission(int callingUid, int userId, boolean requireFullPermission,
+ String message) {
if (userId < 0) {
throw new IllegalArgumentException("Invalid userId " + userId);
}
@@ -4547,7 +4574,7 @@
if (updateUsage) {
p.mLastPackageUsageTimeInMills = System.currentTimeMillis();
}
- mPackageUsage.write();
+ mPackageUsage.write(false);
if (!p.mDexOptNeeded) {
return false;
}
@@ -4676,8 +4703,8 @@
private String getAppInstructionSet(ApplicationInfo info) {
String instructionSet = getPreferredInstructionSet();
- if (info.requiredCpuAbi != null) {
- instructionSet = VMRuntime.getInstructionSet(info.requiredCpuAbi);
+ if (info.cpuAbi != null) {
+ instructionSet = VMRuntime.getInstructionSet(info.cpuAbi);
}
return instructionSet;
@@ -4686,8 +4713,8 @@
private String getAppInstructionSetFromSettings(PackageSetting ps) {
String instructionSet = getPreferredInstructionSet();
- if (ps.requiredCpuAbiString != null) {
- instructionSet = VMRuntime.getInstructionSet(ps.requiredCpuAbiString);
+ if (ps.cpuAbiString != null) {
+ instructionSet = VMRuntime.getInstructionSet(ps.cpuAbiString);
}
return instructionSet;
@@ -5075,7 +5102,7 @@
// the PkgSetting exists already and doesn't have to be created.
pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
destResourceFile, pkg.applicationInfo.nativeLibraryDir,
- pkg.applicationInfo.requiredCpuAbi,
+ pkg.applicationInfo.cpuAbi,
pkg.applicationInfo.flags, user, false);
if (pkgSetting == null) {
Slog.w(TAG, "Creating application package " + pkg.packageName + " failed");
@@ -5403,9 +5430,9 @@
// We've successfully copied native libraries across, so we make a
// note of what ABI we're using
if (copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
- pkg.applicationInfo.requiredCpuAbi = Build.SUPPORTED_ABIS[copyRet];
+ pkg.applicationInfo.cpuAbi = Build.SUPPORTED_ABIS[copyRet];
} else {
- pkg.applicationInfo.requiredCpuAbi = null;
+ pkg.applicationInfo.cpuAbi = null;
}
} catch (IOException e) {
Slog.e(TAG, "Unable to copy native libraries", e);
@@ -5423,12 +5450,12 @@
final NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(scanFile);
final int abi = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_ABIS);
if (abi >= 0) {
- pkg.applicationInfo.requiredCpuAbi = Build.SUPPORTED_ABIS[abi];
+ pkg.applicationInfo.cpuAbi = Build.SUPPORTED_ABIS[abi];
} else if (abi == PackageManager.NO_NATIVE_LIBRARIES) {
// Note that (non upgraded) system apps will not have any native
// libraries bundled in their APK, but we're guaranteed not to be
// such an app at this point.
- pkg.applicationInfo.requiredCpuAbi = null;
+ pkg.applicationInfo.cpuAbi = null;
} else {
mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
return null;
@@ -5938,8 +5965,8 @@
String requiredInstructionSet = null;
PackageSetting requirer = null;
for (PackageSetting ps : packagesForUser) {
- if (ps.requiredCpuAbiString != null) {
- final String instructionSet = VMRuntime.getInstructionSet(ps.requiredCpuAbiString);
+ if (ps.cpuAbiString != null) {
+ final String instructionSet = VMRuntime.getInstructionSet(ps.cpuAbiString);
if (requiredInstructionSet != null) {
if (!instructionSet.equals(requiredInstructionSet)) {
// We have a mismatch between instruction sets (say arm vs arm64).
@@ -5967,11 +5994,11 @@
if (requiredInstructionSet != null) {
for (PackageSetting ps : packagesForUser) {
- if (ps.requiredCpuAbiString == null) {
- ps.requiredCpuAbiString = requirer.requiredCpuAbiString;
+ if (ps.cpuAbiString == null) {
+ ps.cpuAbiString = requirer.cpuAbiString;
if (ps.pkg != null) {
- ps.pkg.applicationInfo.requiredCpuAbi = requirer.requiredCpuAbiString;
- Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + ps.requiredCpuAbiString);
+ ps.pkg.applicationInfo.cpuAbi = requirer.cpuAbiString;
+ Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + ps.cpuAbiString);
if (doDexOpt) {
performDexOptLI(ps.pkg, forceDexOpt, deferDexOpt, true);
mInstaller.rmdex(ps.codePathString, getPreferredInstructionSet());
@@ -6074,15 +6101,15 @@
// Assume that the bundled native libraries always correspond to the
// most preferred 32 or 64 bit ABI.
if (lib64.exists()) {
- pkg.applicationInfo.requiredCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
- pkgSetting.requiredCpuAbiString = Build.SUPPORTED_64_BIT_ABIS[0];
+ pkg.applicationInfo.cpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
+ pkgSetting.cpuAbiString = Build.SUPPORTED_64_BIT_ABIS[0];
} else if (lib.exists()) {
- pkg.applicationInfo.requiredCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
- pkgSetting.requiredCpuAbiString = Build.SUPPORTED_32_BIT_ABIS[0];
+ pkg.applicationInfo.cpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
+ pkgSetting.cpuAbiString = Build.SUPPORTED_32_BIT_ABIS[0];
} else {
// This is the case where the app has no native code.
- pkg.applicationInfo.requiredCpuAbi = null;
- pkgSetting.requiredCpuAbiString = null;
+ pkg.applicationInfo.cpuAbi = null;
+ pkgSetting.cpuAbiString = null;
}
}
@@ -7727,6 +7754,16 @@
}
}
+ void installStage(String basePackageName, File stageDir, IPackageInstallObserver2 observer,
+ int flags) {
+ // TODO: install stage!
+ try {
+ observer.packageInstalled(basePackageName, null,
+ PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
+ } catch (RemoteException ignored) {
+ }
+ }
+
/**
* @hide
*/
@@ -7770,7 +7807,7 @@
return PackageManager.INSTALL_SUCCEEDED;
}
- private boolean isUserRestricted(int userId, String restrictionKey) {
+ boolean isUserRestricted(int userId, String restrictionKey) {
Bundle restrictions = sUserManager.getUserRestrictions(userId);
if (restrictions.getBoolean(restrictionKey, false)) {
Log.w(TAG, "User is restricted: " + restrictionKey);
@@ -12893,4 +12930,9 @@
Binder.restoreCallingIdentity(token);
}
}
+
+ @Override
+ public IPackageInstaller getPackageInstaller() {
+ return mInstallerService;
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 15df3d2..284da99 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -30,8 +30,8 @@
SharedUserSetting sharedUser;
PackageSetting(String name, String realName, File codePath, File resourcePath,
- String nativeLibraryPathString, String requiredCpuAbiString, int pVersionCode, int pkgFlags) {
- super(name, realName, codePath, resourcePath, nativeLibraryPathString, requiredCpuAbiString, pVersionCode,
+ String nativeLibraryPathString, String cpuAbiString, int pVersionCode, int pkgFlags) {
+ super(name, realName, codePath, resourcePath, nativeLibraryPathString, cpuAbiString, pVersionCode,
pkgFlags);
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index c8af9d1..7fee372 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -50,7 +50,7 @@
File resourcePath;
String resourcePathString;
String nativeLibraryPathString;
- String requiredCpuAbiString;
+ String cpuAbiString;
long timeStamp;
long firstInstallTime;
long lastUpdateTime;
@@ -78,11 +78,11 @@
/* package name of the app that installed this package */
String installerPackageName;
PackageSettingBase(String name, String realName, File codePath, File resourcePath,
- String nativeLibraryPathString, String requiredCpuAbiString, int pVersionCode, int pkgFlags) {
+ String nativeLibraryPathString, String cpuAbiString, int pVersionCode, int pkgFlags) {
super(pkgFlags);
this.name = name;
this.realName = realName;
- init(codePath, resourcePath, nativeLibraryPathString, requiredCpuAbiString, pVersionCode);
+ init(codePath, resourcePath, nativeLibraryPathString, cpuAbiString, pVersionCode);
}
/**
@@ -99,7 +99,7 @@
resourcePath = base.resourcePath;
resourcePathString = base.resourcePathString;
nativeLibraryPathString = base.nativeLibraryPathString;
- requiredCpuAbiString = base.requiredCpuAbiString;
+ cpuAbiString = base.cpuAbiString;
timeStamp = base.timeStamp;
firstInstallTime = base.firstInstallTime;
lastUpdateTime = base.lastUpdateTime;
@@ -133,7 +133,7 @@
this.resourcePath = resourcePath;
this.resourcePathString = resourcePath.toString();
this.nativeLibraryPathString = nativeLibraryPathString;
- this.requiredCpuAbiString = requiredCpuAbiString;
+ this.cpuAbiString = requiredCpuAbiString;
this.versionCode = pVersionCode;
}
@@ -164,7 +164,7 @@
grantedPermissions = base.grantedPermissions;
gids = base.gids;
- requiredCpuAbiString = base.requiredCpuAbiString;
+ cpuAbiString = base.cpuAbiString;
timeStamp = base.timeStamp;
firstInstallTime = base.firstInstallTime;
lastUpdateTime = base.lastUpdateTime;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 599d2a7..d37b240 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -260,10 +260,10 @@
PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
- String nativeLibraryPathString, String requiredCpuAbiString, int pkgFlags, UserHandle user, boolean add) {
+ String nativeLibraryPathString, String cpuAbiString, int pkgFlags, UserHandle user, boolean add) {
final String name = pkg.packageName;
PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,
- resourcePath, nativeLibraryPathString, requiredCpuAbiString, pkg.mVersionCode, pkgFlags,
+ resourcePath, nativeLibraryPathString, cpuAbiString, pkg.mVersionCode, pkgFlags,
user, add, true /* allowInstall */);
return p;
}
@@ -350,7 +350,7 @@
p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
}
PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
- p.nativeLibraryPathString, p.requiredCpuAbiString, p.appId, p.versionCode, p.pkgFlags);
+ p.nativeLibraryPathString, p.cpuAbiString, p.appId, p.versionCode, p.pkgFlags);
mDisabledSysPackages.remove(name);
return ret;
}
@@ -364,7 +364,7 @@
}
PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
- String nativeLibraryPathString, String requiredCpuAbiString, int uid, int vc, int pkgFlags) {
+ String nativeLibraryPathString, String cpuAbiString, int uid, int vc, int pkgFlags) {
PackageSetting p = mPackages.get(name);
if (p != null) {
if (p.appId == uid) {
@@ -374,7 +374,7 @@
"Adding duplicate package, keeping first: " + name);
return null;
}
- p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString, requiredCpuAbiString,
+ p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString, cpuAbiString,
vc, pkgFlags);
p.appId = uid;
if (addUserIdLPw(uid, p, name)) {
@@ -443,11 +443,11 @@
private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
- String nativeLibraryPathString, String requiredCpuAbiString, int vc, int pkgFlags,
+ String nativeLibraryPathString, String cpuAbiString, int vc, int pkgFlags,
UserHandle installUser, boolean add, boolean allowInstall) {
PackageSetting p = mPackages.get(name);
if (p != null) {
- p.requiredCpuAbiString = requiredCpuAbiString;
+ p.cpuAbiString = cpuAbiString;
if (!p.codePath.equals(codePath)) {
// Check to see if its a disabled system app
if ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
@@ -491,7 +491,7 @@
if (origPackage != null) {
// We are consuming the data from an existing package.
p = new PackageSetting(origPackage.name, name, codePath, resourcePath,
- nativeLibraryPathString, requiredCpuAbiString, vc, pkgFlags);
+ nativeLibraryPathString, cpuAbiString, vc, pkgFlags);
if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
+ name + " is adopting original package " + origPackage.name);
// Note that we will retain the new package's signature so
@@ -508,7 +508,7 @@
p.setTimeStamp(codePath.lastModified());
} else {
p = new PackageSetting(name, realName, codePath, resourcePath,
- nativeLibraryPathString, requiredCpuAbiString, vc, pkgFlags);
+ nativeLibraryPathString, cpuAbiString, vc, pkgFlags);
p.setTimeStamp(codePath.lastModified());
p.sharedUser = sharedUser;
// If this is not a system app, it starts out stopped.
@@ -635,7 +635,7 @@
p.nativeLibraryPathString = nativeLibraryPath;
}
// Update the required Cpu Abi
- p.requiredCpuAbiString = pkg.applicationInfo.requiredCpuAbi;
+ p.cpuAbiString = pkg.applicationInfo.cpuAbi;
// Update version code if needed
if (pkg.mVersionCode != p.versionCode) {
p.versionCode = pkg.mVersionCode;
@@ -1690,8 +1690,8 @@
if (pkg.nativeLibraryPathString != null) {
serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
}
- if (pkg.requiredCpuAbiString != null) {
- serializer.attribute(null, "requiredCpuAbi", pkg.requiredCpuAbiString);
+ if (pkg.cpuAbiString != null) {
+ serializer.attribute(null, "requiredCpuAbi", pkg.cpuAbiString);
}
if (pkg.sharedUser == null) {
serializer.attribute(null, "userId", Integer.toString(pkg.appId));
@@ -1735,8 +1735,8 @@
if (pkg.nativeLibraryPathString != null) {
serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
}
- if (pkg.requiredCpuAbiString != null) {
- serializer.attribute(null, "requiredCpuAbi", pkg.requiredCpuAbiString);
+ if (pkg.cpuAbiString != null) {
+ serializer.attribute(null, "requiredCpuAbi", pkg.cpuAbiString);
}
serializer.attribute(null, "flags", Integer.toString(pkg.pkgFlags));
serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
@@ -2023,7 +2023,7 @@
if (idObj != null && idObj instanceof SharedUserSetting) {
PackageSetting p = getPackageLPw(pp.name, null, pp.realName,
(SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
- pp.nativeLibraryPathString, pp.requiredCpuAbiString, pp.versionCode, pp.pkgFlags,
+ pp.nativeLibraryPathString, pp.cpuAbiString, pp.versionCode, pp.pkgFlags,
null, true /* add */, false /* allowInstall */);
if (p == null) {
PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -2443,7 +2443,7 @@
String codePathStr = parser.getAttributeValue(null, "codePath");
String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
String nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
- String requiredCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi");
+ String cpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi");
if (resourcePathStr == null) {
resourcePathStr = codePathStr;
@@ -2464,7 +2464,7 @@
pkgFlags |= ApplicationInfo.FLAG_PRIVILEGED;
}
PackageSetting ps = new PackageSetting(name, realName, codePathFile,
- new File(resourcePathStr), nativeLibraryPathStr, requiredCpuAbiString, versionCode, pkgFlags);
+ new File(resourcePathStr), nativeLibraryPathStr, cpuAbiString, versionCode, pkgFlags);
String timeStampStr = parser.getAttributeValue(null, "ft");
if (timeStampStr != null) {
try {
@@ -2531,7 +2531,7 @@
String codePathStr = null;
String resourcePathStr = null;
String nativeLibraryPathStr = null;
- String requiredCpuAbiString = null;
+ String cpuAbiString = null;
String systemStr = null;
String installerPackageName = null;
String uidError = null;
@@ -2551,7 +2551,7 @@
codePathStr = parser.getAttributeValue(null, "codePath");
resourcePathStr = parser.getAttributeValue(null, "resourcePath");
nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
- requiredCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi");
+ cpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi");
version = parser.getAttributeValue(null, "version");
if (version != null) {
@@ -2629,7 +2629,7 @@
+ parser.getPositionDescription());
} else if (userId > 0) {
packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
- new File(resourcePathStr), nativeLibraryPathStr, requiredCpuAbiString, userId, versionCode,
+ new File(resourcePathStr), nativeLibraryPathStr, cpuAbiString, userId, versionCode,
pkgFlags);
if (PackageManagerService.DEBUG_SETTINGS)
Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
@@ -2647,7 +2647,7 @@
userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
if (userId > 0) {
packageSetting = new PendingPackage(name.intern(), realName, new File(
- codePathStr), new File(resourcePathStr), nativeLibraryPathStr, requiredCpuAbiString, userId,
+ codePathStr), new File(resourcePathStr), nativeLibraryPathStr, cpuAbiString, userId,
versionCode, pkgFlags);
packageSetting.setTimeStamp(timeStamp);
packageSetting.firstInstallTime = firstInstallTime;
@@ -2676,7 +2676,7 @@
packageSetting.uidError = "true".equals(uidError);
packageSetting.installerPackageName = installerPackageName;
packageSetting.nativeLibraryPathString = nativeLibraryPathStr;
- packageSetting.requiredCpuAbiString = requiredCpuAbiString;
+ packageSetting.cpuAbiString = cpuAbiString;
// Handle legacy string here for single-user mode
final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
if (enabledStr != null) {
@@ -3176,7 +3176,7 @@
pw.print(prefix); pw.print(" codePath="); pw.println(ps.codePathString);
pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.resourcePathString);
pw.print(prefix); pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString);
- pw.print(prefix); pw.print(" requiredCpuAbi="); pw.println(ps.requiredCpuAbiString);
+ pw.print(prefix); pw.print(" requiredCpuAbi="); pw.println(ps.cpuAbiString);
pw.print(prefix); pw.print(" versionCode="); pw.print(ps.versionCode);
if (ps.pkg != null) {
pw.print(" targetSdk="); pw.print(ps.pkg.applicationInfo.targetSdkVersion);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 6d2e8592..03941c6 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -168,9 +168,9 @@
// Poll interval in milliseconds for watching boot animation finished.
private static final int BOOT_ANIMATION_POLL_INTERVAL = 200;
- //powerHint
+ // Used to send the hint to the PowerHAL indicating transitions
+ // from and to the low power mode.
private static final int POWER_HINT_LOW_POWER_MODE = 5;
- private static boolean mLowPowerModeEnabled;
private final Context mContext;
private LightsManager mLightsManager;
@@ -399,6 +399,9 @@
// Time when we last logged a warning about calling userActivity() without permission.
private long mLastWarningAboutUserActivityPermission = Long.MIN_VALUE;
+ // If true, the device is in low power mode.
+ private static boolean mLowPowerModeEnabled;
+
private native void nativeInit();
private static native void nativeAcquireSuspendBlocker(String name);
@@ -535,6 +538,9 @@
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_BRIGHTNESS_MODE),
false, mSettingsObserver, UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ),
+ false, mSettingsObserver, UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.LOW_POWER_MODE),
false, mSettingsObserver, UserHandle.USER_ALL);
@@ -617,12 +623,11 @@
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT);
- boolean mIsEnabled = Settings.Global.getInt(resolver,
- Settings.Global.LOW_POWER_MODE, 0) != 0;
- if (mIsEnabled != mLowPowerModeEnabled) {
- BinderService bs = new BinderService();
- bs.powerHint(POWER_HINT_LOW_POWER_MODE, mIsEnabled ? 1 : 0);
- mLowPowerModeEnabled = mIsEnabled;
+ boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
+ Settings.Global.LOW_POWER_MODE, 0) != 0;
+ if (lowPowerModeEnabled != mLowPowerModeEnabled) {
+ powerHintInternal(POWER_HINT_LOW_POWER_MODE, lowPowerModeEnabled ? 1 : 0);
+ mLowPowerModeEnabled = lowPowerModeEnabled;
}
mDirty |= DIRTY_SETTINGS;
@@ -1634,6 +1639,8 @@
mDisplayPowerRequest.blockScreenOn = mScreenOnBlocker.isHeld();
+ mDisplayPowerRequest.lowPowerMode = mLowPowerModeEnabled;
+
mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity);
mRequestWaitForNegativeProximity = false;
@@ -2018,6 +2025,10 @@
}
}
+ private void powerHintInternal(int hintId, int data) {
+ nativeSendPowerHint(hintId, data);
+ }
+
/**
* Low-level function turn the device off immediately, without trying
* to be clean. Most people should use {@link ShutdownThread} for a clean shutdown.
@@ -2527,7 +2538,7 @@
@Override // Binder call
public void powerHint(int hintId, int data) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
- nativeSendPowerHint(hintId, data);
+ powerHintInternal(hintId, data);
}
@Override // Binder call
diff --git a/services/core/java/com/android/server/task/StateChangedListener.java b/services/core/java/com/android/server/task/StateChangedListener.java
new file mode 100644
index 0000000..a87bf95
--- /dev/null
+++ b/services/core/java/com/android/server/task/StateChangedListener.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task;
+
+import com.android.server.task.controllers.TaskStatus;
+
+/**
+ * Interface through which a {@link StateController} informs the
+ * {@link com.android.server.task.TaskManagerService} that there are some tasks potentially ready
+ * to be run.
+ */
+public interface StateChangedListener {
+ /**
+ * Called by the controller to notify the TaskManager that it should check on the state of a
+ * task.
+ * @param taskStatus The state of the task which has changed.
+ */
+ public void onTaskStateChanged(TaskStatus taskStatus);
+
+ /**
+ * Called by the controller to notify the TaskManager that regardless of the state of the task,
+ * it must be run immediately.
+ * @param taskStatus The state of the task which is to be run immediately.
+ */
+ public void onTaskDeadlineExpired(TaskStatus taskStatus);
+}
diff --git a/services/core/java/com/android/server/task/TaskList.java b/services/core/java/com/android/server/task/TaskList.java
new file mode 100644
index 0000000..d2b8440
--- /dev/null
+++ b/services/core/java/com/android/server/task/TaskList.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task;
+
+import android.content.ComponentName;
+import android.content.Task;
+
+import com.android.server.task.controllers.TaskStatus;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Maintain a list of classes, and accessor methods/logic for these tasks.
+ * This class offers the following functionality:
+ * - When a task is added, it will determine if the task requirements have changed (update) and
+ * whether the controllers need to be updated.
+ * - Persists Tasks, figures out when to to rewrite the Task to disk.
+ * - Is threadsafe.
+ * - Handles rescheduling of tasks.
+ * - When a periodic task is executed and must be re-added.
+ * - When a task fails and the client requests that it be retried with backoff.
+ */
+public class TaskList {
+
+ final List<TaskStatus> mTasks;
+
+ TaskList() {
+ mTasks = intialiseTaskMapFromDisk();
+ }
+
+ /**
+ * Add a task to the master list, persisting it if necessary.
+ * @param task Task to add.
+ * @param persistable true if the TaskQueue should persist this task to the disk.
+ * @return true if this operation was successful. If false, this task was neither added nor
+ * persisted.
+ */
+ // TODO: implement this when i decide whether i want to key by TaskStatus
+ public boolean add(Task task, boolean persistable) {
+ return true;
+ }
+
+ /**
+ * Remove the provided task. Will also delete the task if it was persisted. Note that this
+ * function does not return the validity of the operation, as we assume a delete will always
+ * succeed.
+ * @param task Task to remove.
+ */
+ public void remove(Task task) {
+
+ }
+
+ /**
+ *
+ * @return
+ */
+ // TODO: Implement this.
+ private List<TaskStatus> intialiseTaskMapFromDisk() {
+ return new ArrayList<TaskStatus>();
+ }
+}
diff --git a/services/core/java/com/android/server/task/TaskManagerService.java b/services/core/java/com/android/server/task/TaskManagerService.java
new file mode 100644
index 0000000..5df4b2a
--- /dev/null
+++ b/services/core/java/com/android/server/task/TaskManagerService.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.SparseArray;
+
+import com.android.server.task.controllers.TaskStatus;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Responsible for taking tasks representing work to be performed by a client app, and determining
+ * based on the criteria specified when that task should be run against the client application's
+ * endpoint.
+ * @hide
+ */
+public class TaskManagerService extends com.android.server.SystemService
+ implements StateChangedListener {
+
+ /** Master list of tasks. */
+ private final TaskList mTaskList;
+
+ /**
+ * Track Services that have currently active or pending tasks. The index is provided by
+ * {@link TaskStatus#getServiceToken()}
+ */
+ private final SparseArray<TaskServiceContext> mPendingTaskServices =
+ new SparseArray<TaskServiceContext>();
+
+ private final TaskHandler mHandler;
+
+ private class TaskHandler extends Handler {
+ /** Check the pending queue and start any tasks. */
+ static final int MSG_RUN_PENDING = 0;
+ /** Initiate the stop task flow. */
+ static final int MSG_STOP_TASK = 1;
+
+ public TaskHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_RUN_PENDING:
+
+ break;
+ case MSG_STOP_TASK:
+
+ break;
+ }
+ }
+
+ /**
+ * Helper to post a message to this handler that will run through the pending queue and
+ * start any tasks it can.
+ */
+ void sendRunPendingTasksMessage() {
+ Message m = Message.obtain(this, MSG_RUN_PENDING);
+ m.sendToTarget();
+ }
+
+ void sendOnStopMessage(TaskStatus taskStatus) {
+
+ }
+ }
+
+ /**
+ * Initializes the system service.
+ * <p>
+ * Subclasses must define a single argument constructor that accepts the context
+ * and passes it to super.
+ * </p>
+ *
+ * @param context The system server context.
+ */
+ public TaskManagerService(Context context) {
+ super(context);
+ mTaskList = new TaskList();
+ mHandler = new TaskHandler(context.getMainLooper());
+ }
+
+ @Override
+ public void onStart() {
+
+ }
+
+ /**
+ * Offboard work to our handler thread as quickly as possible, b/c this call is probably being
+ * made on the main thread.
+ * @param taskStatus The state of the task which has changed.
+ */
+ @Override
+ public void onTaskStateChanged(TaskStatus taskStatus) {
+ if (taskStatus.isReady()) {
+
+ } else {
+ if (mPendingTaskServices.get(taskStatus.getServiceToken()) != null) {
+ // The task is either pending or being executed, which we have to cancel.
+ }
+ }
+
+ }
+
+ @Override
+ public void onTaskDeadlineExpired(TaskStatus taskStatus) {
+
+ }
+}
diff --git a/services/core/java/com/android/server/task/TaskServiceContext.java b/services/core/java/com/android/server/task/TaskServiceContext.java
new file mode 100644
index 0000000..65c6fa5
--- /dev/null
+++ b/services/core/java/com/android/server/task/TaskServiceContext.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task;
+
+import android.app.task.ITaskCallback;
+import android.app.task.ITaskService;
+import android.content.ComponentName;
+import android.content.ServiceConnection;
+import android.content.Task;
+import android.os.IBinder;
+
+import com.android.server.task.controllers.TaskStatus;
+
+/**
+ * Maintains information required to bind to a {@link android.app.task.TaskService}. This binding
+ * can then be reused to start concurrent tasks on the TaskService. Information here is unique
+ * within this service.
+ * Functionality provided by this class:
+ * - Managages wakelock for the service.
+ * - Sends onStartTask() and onStopTask() messages to client app, and handles callbacks.
+ * -
+ */
+public class TaskServiceContext extends ITaskCallback.Stub implements ServiceConnection {
+
+ final ComponentName component;
+ int uid;
+ ITaskService service;
+
+ /** Whether this service is actively bound. */
+ boolean mBound;
+
+ TaskServiceContext(Task task) {
+ this.component = task.getService();
+ }
+
+ public void stopTask() {
+
+ }
+
+ public void startTask(Task task) {
+
+ }
+
+ @Override
+ public void taskFinished(int taskId, boolean reschedule) {
+
+ }
+
+ @Override
+ public void acknowledgeStopMessage(int taskId) {
+
+ }
+
+ @Override
+ public void acknowledgeStartMessage(int taskId) {
+
+ }
+
+ /**
+ * @return true if this task is pending or active within this context.
+ */
+ public boolean hasTaskPending(TaskStatus taskStatus) {
+ return true;
+ }
+
+ public boolean isBound() {
+ return mBound;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+
+ mBound = true;
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mBound = false;
+ }
+}
diff --git a/services/core/java/com/android/server/task/controllers/ConnectivityController.java b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
new file mode 100644
index 0000000..5cca77c
--- /dev/null
+++ b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task.controllers;
+
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.server.task.TaskManagerService;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ *
+ */
+public class ConnectivityController extends StateController {
+ private static final String TAG = "TaskManager.Connectivity";
+
+ private final List<TaskStatus> mTrackedTasks = new LinkedList<TaskStatus>();
+ private final BroadcastReceiver mConnectivityChangedReceiver =
+ new ConnectivityChangedReceiver();
+
+ public ConnectivityController(TaskManagerService service) {
+ super(service);
+ // Register connectivity changed BR.
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ mContext.registerReceiverAsUser(
+ mConnectivityChangedReceiver, UserHandle.ALL, intentFilter, null, null);
+ }
+
+ @Override
+ public void maybeTrackTaskState(TaskStatus taskStatus) {
+ if (taskStatus.hasConnectivityConstraint() || taskStatus.hasMeteredConstraint()) {
+ mTrackedTasks.add(taskStatus);
+ }
+ }
+
+ @Override
+ public void removeTaskStateIfTracked(TaskStatus taskStatus) {
+ mTrackedTasks.remove(taskStatus);
+ }
+
+ /**
+ * @param isConnected Whether the active network is connected for the given uid
+ * @param isMetered Whether the active network is metered for the given uid. This is
+ * necessarily false if <code>isConnected</code> is false.
+ * @param userId Id of the user for whom we are updating the connectivity state.
+ */
+ private void updateTrackedTasks(boolean isConnected, boolean isMetered, int userId) {
+ for (TaskStatus ts : mTrackedTasks) {
+ if (ts.userId != userId) {
+ continue;
+ }
+ boolean prevIsConnected = ts.connectivityConstraintSatisfied.getAndSet(isConnected);
+ boolean prevIsMetered = ts.meteredConstraintSatisfied.getAndSet(isMetered);
+ if (prevIsConnected != isConnected || prevIsMetered != isMetered) {
+ mStateChangedListener.onTaskStateChanged(ts);
+ }
+ }
+ }
+
+ class ConnectivityChangedReceiver extends BroadcastReceiver {
+ /**
+ * We'll receive connectivity changes for each user here, which we'll process independently.
+ * We are only interested in the active network here. We're only interested in the active
+ * network, b/c the end result of this will be for apps to try to hit the network.
+ * @param context The Context in which the receiver is running.
+ * @param intent The Intent being received.
+ */
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+ final int networkType =
+ intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,
+ ConnectivityManager.TYPE_NONE);
+ // Connectivity manager for THIS context - important!
+ final ConnectivityManager connManager = (ConnectivityManager)
+ context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ final NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
+ // This broadcast gets sent a lot, only update if the active network has changed.
+ if (activeNetwork.getType() == networkType) {
+ final int userid = context.getUserId();
+ boolean isMetered = false;
+ boolean isConnected =
+ !intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
+ if (isConnected) { // No point making the call if we know there's no conn.
+ isMetered = connManager.isActiveNetworkMetered();
+ }
+ updateTrackedTasks(isConnected, isMetered, userid);
+ }
+ } else {
+ Log.w(TAG, "Unrecognised action in intent: " + action);
+ }
+ }
+ };
+}
diff --git a/services/core/java/com/android/server/task/controllers/StateController.java b/services/core/java/com/android/server/task/controllers/StateController.java
new file mode 100644
index 0000000..e1cd662
--- /dev/null
+++ b/services/core/java/com/android/server/task/controllers/StateController.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task.controllers;
+
+import android.content.Context;
+
+import com.android.server.task.StateChangedListener;
+import com.android.server.task.TaskManagerService;
+
+/**
+ * Incorporates shared controller logic between the various controllers of the TaskManager.
+ * These are solely responsible for tracking a list of tasks, and notifying the TM when these
+ * are ready to run, or whether they must be stopped.
+ */
+public abstract class StateController {
+
+ protected Context mContext;
+ protected StateChangedListener mStateChangedListener;
+
+ public StateController(TaskManagerService service) {
+ mStateChangedListener = service;
+ mContext = service.getContext();
+ }
+
+ /**
+ * Implement the logic here to decide whether a task should be tracked by this controller.
+ * This logic is put here so the TaskManger can be completely agnostic of Controller logic.
+ * Also called when updating a task, so implementing controllers have to be aware of
+ * preexisting tasks.
+ */
+ public abstract void maybeTrackTaskState(TaskStatus taskStatus);
+ /**
+ * Remove task - this will happen if the task is cancelled, completed, etc.
+ */
+ public abstract void removeTaskStateIfTracked(TaskStatus taskStatus);
+
+}
diff --git a/services/core/java/com/android/server/task/controllers/TaskStatus.java b/services/core/java/com/android/server/task/controllers/TaskStatus.java
new file mode 100644
index 0000000..230b049
--- /dev/null
+++ b/services/core/java/com/android/server/task/controllers/TaskStatus.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task.controllers;
+
+import android.content.ComponentName;
+import android.content.Task;
+import android.os.SystemClock;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Uniquely identifies a task internally.
+ * Created from the public {@link android.content.Task} object when it lands on the scheduler.
+ * Contains current state of the requirements of the task, as well as a function to evaluate
+ * whether it's ready to run.
+ * This object is shared among the various controllers - hence why the different fields are atomic.
+ * This isn't strictly necessary because each controller is only interested in a specific field,
+ * and the receivers that are listening for global state change will all run on the main looper,
+ * but we don't enforce that so this is safer.
+ * @hide
+ */
+public class TaskStatus {
+ final int taskId;
+ final int userId;
+ ComponentName component;
+
+ final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
+ final AtomicBoolean timeConstraintSatisfied = new AtomicBoolean();
+ final AtomicBoolean idleConstraintSatisfied = new AtomicBoolean();
+ final AtomicBoolean meteredConstraintSatisfied = new AtomicBoolean();
+ final AtomicBoolean connectivityConstraintSatisfied = new AtomicBoolean();
+
+ private final boolean hasChargingConstraint;
+ private final boolean hasTimingConstraint;
+ private final boolean hasIdleConstraint;
+ private final boolean hasMeteredConstraint;
+ private final boolean hasConnectivityConstraint;
+
+ private long earliestRunTimeElapsedMillis;
+ private long latestRunTimeElapsedMillis;
+
+ /** Provide a unique handle to the service that this task will be run on. */
+ public int getServiceToken() {
+ return component.hashCode() + userId;
+ }
+
+ /** Generate a TaskStatus object for a given task and uid. */
+ // TODO: reimplement this to reuse these objects instead of creating a new one each time?
+ static TaskStatus getForTaskAndUid(Task task, int uId) {
+ return new TaskStatus(task, uId);
+ }
+
+ /** Set up the state of a newly scheduled task. */
+ TaskStatus(Task task, int userId) {
+ this.taskId = task.getTaskId();
+ this.userId = userId;
+ this.component = task.getService();
+
+ hasChargingConstraint = task.isRequireCharging();
+ hasIdleConstraint = task.isRequireDeviceIdle();
+
+ // Timing constraints
+ if (task.isPeriodic()) {
+ long elapsedNow = SystemClock.elapsedRealtime();
+ earliestRunTimeElapsedMillis = elapsedNow;
+ latestRunTimeElapsedMillis = elapsedNow + task.getIntervalMillis();
+ hasTimingConstraint = true;
+ } else if (task.getMinLatencyMillis() != 0L || task.getMaxExecutionDelayMillis() != 0L) {
+ earliestRunTimeElapsedMillis = task.getMinLatencyMillis() > 0L ?
+ task.getMinLatencyMillis() : Long.MAX_VALUE;
+ latestRunTimeElapsedMillis = task.getMaxExecutionDelayMillis() > 0L ?
+ task.getMaxExecutionDelayMillis() : Long.MAX_VALUE;
+ hasTimingConstraint = true;
+ } else {
+ hasTimingConstraint = false;
+ }
+
+ // Networking constraints
+ hasMeteredConstraint = task.getNetworkCapabilities() == Task.NetworkType.UNMETERED;
+ hasConnectivityConstraint = task.getNetworkCapabilities() == Task.NetworkType.ANY;
+ }
+
+ boolean hasConnectivityConstraint() {
+ return hasConnectivityConstraint;
+ }
+
+ boolean hasMeteredConstraint() {
+ return hasMeteredConstraint;
+ }
+
+ boolean hasChargingConstraint() {
+ return hasChargingConstraint;
+ }
+
+ boolean hasTimingConstraint() {
+ return hasTimingConstraint;
+ }
+
+ boolean hasIdleConstraint() {
+ return hasIdleConstraint;
+ }
+
+ long getEarliestRunTime() {
+ return earliestRunTimeElapsedMillis;
+ }
+
+ long getLatestRunTime() {
+ return latestRunTimeElapsedMillis;
+ }
+
+ /**
+ * @return whether this task is ready to run, based on its requirements.
+ */
+ public synchronized boolean isReady() {
+ return (!hasChargingConstraint || chargingConstraintSatisfied.get())
+ && (!hasTimingConstraint || timeConstraintSatisfied.get())
+ && (!hasConnectivityConstraint || connectivityConstraintSatisfied.get())
+ && (!hasMeteredConstraint || meteredConstraintSatisfied.get())
+ && (!hasIdleConstraint || idleConstraintSatisfied.get());
+ }
+
+ @Override
+ public int hashCode() {
+ int result = component.hashCode();
+ result = 31 * result + taskId;
+ result = 31 * result + userId;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof TaskStatus)) return false;
+
+ TaskStatus that = (TaskStatus) o;
+ return ((taskId == that.taskId)
+ && (userId == that.userId)
+ && (component.equals(that.component)));
+ }
+}
diff --git a/services/core/java/com/android/server/task/controllers/TimeController.java b/services/core/java/com/android/server/task/controllers/TimeController.java
new file mode 100644
index 0000000..6d97a53
--- /dev/null
+++ b/services/core/java/com/android/server/task/controllers/TimeController.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.task.controllers;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.server.task.TaskManagerService;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * This class sets an alarm for the next expiring task, and determines whether a task's minimum
+ * delay has been satisfied.
+ */
+public class TimeController extends StateController {
+ private static final String TAG = "TaskManager.Time";
+ private static final String ACTION_TASK_EXPIRED =
+ "android.content.taskmanager.TASK_EXPIRED";
+ private static final String ACTION_TASK_DELAY_EXPIRED =
+ "android.content.taskmanager.TASK_DELAY_EXPIRED";
+
+ /** Set an alarm for the next task expiry. */
+ private final PendingIntent mTaskExpiredAlarmIntent;
+ /** Set an alarm for the next task delay expiry. This*/
+ private final PendingIntent mNextDelayExpiredAlarmIntent;
+
+ private long mNextTaskExpiredElapsedMillis;
+ private long mNextDelayExpiredElapsedMillis;
+
+ private AlarmManager mAlarmService = null;
+ /** List of tracked tasks, sorted asc. by deadline */
+ private final List<TaskStatus> mTrackedTasks = new LinkedList<TaskStatus>();
+
+ public TimeController(TaskManagerService service) {
+ super(service);
+ mTaskExpiredAlarmIntent =
+ PendingIntent.getBroadcast(mContext, 0 /* ignored */,
+ new Intent(ACTION_TASK_EXPIRED), 0);
+ mNextDelayExpiredAlarmIntent =
+ PendingIntent.getBroadcast(mContext, 0 /* ignored */,
+ new Intent(ACTION_TASK_DELAY_EXPIRED), 0);
+
+ // Register BR for these intents.
+ IntentFilter intentFilter = new IntentFilter(ACTION_TASK_EXPIRED);
+ intentFilter.addAction(ACTION_TASK_DELAY_EXPIRED);
+ mContext.registerReceiver(mAlarmExpiredReceiver, intentFilter);
+ }
+
+ /**
+ * Check if the task has a timing constraint, and if so determine where to insert it in our
+ * list.
+ */
+ @Override
+ public synchronized void maybeTrackTaskState(TaskStatus task) {
+ if (task.hasTimingConstraint()) {
+ ListIterator<TaskStatus> it = mTrackedTasks.listIterator(mTrackedTasks.size());
+ while (it.hasPrevious()) {
+ TaskStatus ts = it.previous();
+ if (ts.equals(task)) {
+ // Update
+ it.remove();
+ it.add(task);
+ break;
+ } else if (ts.getLatestRunTime() < task.getLatestRunTime()) {
+ // Insert
+ it.add(task);
+ break;
+ }
+ }
+ maybeUpdateAlarms(task.getEarliestRunTime(), task.getLatestRunTime());
+ }
+ }
+
+ /**
+ * If the task passed in is being tracked, figure out if we need to update our alarms, and if
+ * so, update them.
+ */
+ @Override
+ public synchronized void removeTaskStateIfTracked(TaskStatus taskStatus) {
+ if (mTrackedTasks.remove(taskStatus)) {
+ if (mNextDelayExpiredElapsedMillis <= taskStatus.getEarliestRunTime()) {
+ handleTaskDelayExpired();
+ }
+ if (mNextTaskExpiredElapsedMillis <= taskStatus.getLatestRunTime()) {
+ handleTaskDeadlineExpired();
+ }
+ }
+ }
+
+ /**
+ * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a task's
+ * delay will expire.
+ * This alarm <b>will not</b> wake up the phone.
+ */
+ private void setDelayExpiredAlarm(long alarmTimeElapsedMillis) {
+ ensureAlarmService();
+ mAlarmService.set(AlarmManager.ELAPSED_REALTIME, alarmTimeElapsedMillis,
+ mNextDelayExpiredAlarmIntent);
+ }
+
+ /**
+ * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a task's
+ * deadline will expire.
+ * This alarm <b>will</b> wake up the phone.
+ */
+ private void setDeadlineExpiredAlarm(long alarmTimeElapsedMillis) {
+ ensureAlarmService();
+ mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTimeElapsedMillis,
+ mTaskExpiredAlarmIntent);
+ }
+
+ /**
+ * Determines whether this controller can stop tracking the given task.
+ * The controller is no longer interested in a task once its time constraint is satisfied, and
+ * the task's deadline is fulfilled - unlike other controllers a time constraint can't toggle
+ * back and forth.
+ */
+ private boolean canStopTrackingTask(TaskStatus taskStatus) {
+ final long elapsedNowMillis = SystemClock.elapsedRealtime();
+ return taskStatus.timeConstraintSatisfied.get() &&
+ (taskStatus.getLatestRunTime() == Long.MAX_VALUE ||
+ taskStatus.getLatestRunTime() < elapsedNowMillis);
+ }
+
+ private void maybeUpdateAlarms(long delayExpiredElapsed, long deadlineExpiredElapsed) {
+ if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) {
+ mNextDelayExpiredElapsedMillis = delayExpiredElapsed;
+ setDelayExpiredAlarm(mNextDelayExpiredElapsedMillis);
+ }
+ if (deadlineExpiredElapsed < mNextTaskExpiredElapsedMillis) {
+ mNextTaskExpiredElapsedMillis = deadlineExpiredElapsed;
+ setDeadlineExpiredAlarm(mNextTaskExpiredElapsedMillis);
+ }
+ }
+
+ private void ensureAlarmService() {
+ if (mAlarmService == null) {
+ mAlarmService = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ }
+ }
+
+ /**
+ * Handles alarm that notifies that a task has expired. When this function is called at least
+ * one task must be run.
+ */
+ private synchronized void handleTaskDeadlineExpired() {
+ long nextExpiryTime = Long.MAX_VALUE;
+ final long nowElapsedMillis = SystemClock.elapsedRealtime();
+
+ Iterator<TaskStatus> it = mTrackedTasks.iterator();
+ while (it.hasNext()) {
+ TaskStatus ts = it.next();
+ final long taskDeadline = ts.getLatestRunTime();
+
+ if (taskDeadline <= nowElapsedMillis) {
+ ts.timeConstraintSatisfied.set(true);
+ mStateChangedListener.onTaskDeadlineExpired(ts);
+ it.remove();
+ } else { // Sorted by expiry time, so take the next one and stop.
+ nextExpiryTime = taskDeadline;
+ break;
+ }
+ }
+ maybeUpdateAlarms(Long.MAX_VALUE, nextExpiryTime);
+ }
+
+ /**
+ * Handles alarm that notifies us that a task's delay has expired. Iterates through the list of
+ * tracked tasks and marks them as ready as appropriate.
+ */
+ private synchronized void handleTaskDelayExpired() {
+ final long nowElapsedMillis = SystemClock.elapsedRealtime();
+ long nextDelayTime = Long.MAX_VALUE;
+
+ Iterator<TaskStatus> it = mTrackedTasks.iterator();
+ while (it.hasNext()) {
+ final TaskStatus ts = it.next();
+ final long taskDelayTime = ts.getEarliestRunTime();
+ if (taskDelayTime < nowElapsedMillis) {
+ ts.timeConstraintSatisfied.set(true);
+ mStateChangedListener.onTaskStateChanged(ts);
+ if (canStopTrackingTask(ts)) {
+ it.remove();
+ }
+ } else { // Keep going through list to get next delay time.
+ if (nextDelayTime > taskDelayTime) {
+ nextDelayTime = taskDelayTime;
+ }
+ }
+ }
+ maybeUpdateAlarms(nextDelayTime, Long.MAX_VALUE);
+ }
+
+ private final BroadcastReceiver mAlarmExpiredReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // An task has just expired, so we run through the list of tasks that we have and
+ // notify our StateChangedListener.
+ if (ACTION_TASK_EXPIRED.equals(intent.getAction())) {
+ handleTaskDeadlineExpired();
+ } else if (ACTION_TASK_DELAY_EXPIRED.equals(intent.getAction())) {
+ handleTaskDelayExpired();
+ }
+ }
+ };
+}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 50dd27d..8ad7fff 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -134,7 +134,7 @@
private void buildTvInputListLocked(int userId) {
UserState userState = getUserStateLocked(userId);
- userState.inputList.clear();
+ userState.inputMap.clear();
if (DEBUG) Slog.d(TAG, "buildTvInputList");
PackageManager pm = mContext.getPackageManager();
@@ -149,7 +149,7 @@
}
TvInputInfo info = new TvInputInfo(ri);
if (DEBUG) Slog.d(TAG, "add " + info.getId());
- userState.inputList.add(info);
+ userState.inputMap.put(info.getId(), info);
}
}
@@ -179,9 +179,9 @@
}
// Release created sessions.
for (SessionState state : userState.sessionStateMap.values()) {
- if (state.session != null) {
+ if (state.mSession != null) {
try {
- state.session.release();
+ state.mSession.release();
} catch (RemoteException e) {
Slog.e(TAG, "error in release", e);
}
@@ -191,15 +191,15 @@
// Unregister all callbacks and unbind all services.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
- if (serviceState.callback != null) {
+ if (serviceState.mCallback != null) {
try {
- serviceState.service.unregisterCallback(serviceState.callback);
+ serviceState.mService.unregisterCallback(serviceState.mCallback);
} catch (RemoteException e) {
Slog.e(TAG, "error in unregisterCallback", e);
}
}
- serviceState.clients.clear();
- mContext.unbindService(serviceState.connection);
+ serviceState.mClients.clear();
+ mContext.unbindService(serviceState.mConnection);
}
userState.serviceStateMap.clear();
@@ -215,28 +215,33 @@
return userState;
}
- private ServiceState getServiceStateLocked(ComponentName name, int userId) {
+ private ServiceState getServiceStateLocked(String inputId, int userId) {
UserState userState = getUserStateLocked(userId);
- ServiceState serviceState = userState.serviceStateMap.get(name);
+ ServiceState serviceState = userState.serviceStateMap.get(inputId);
if (serviceState == null) {
- throw new IllegalStateException("Service state not found for " + name + " (userId="
+ throw new IllegalStateException("Service state not found for " + inputId + " (userId="
+ userId + ")");
}
return serviceState;
}
- private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) {
+ private SessionState getSessionStateLocked(IBinder sessionToken, int callingUid, int userId) {
UserState userState = getUserStateLocked(userId);
SessionState sessionState = userState.sessionStateMap.get(sessionToken);
if (sessionState == null) {
throw new IllegalArgumentException("Session state not found for token " + sessionToken);
}
// Only the application that requested this session or the system can access it.
- if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.callingUid) {
+ if (callingUid != Process.SYSTEM_UID && callingUid != sessionState.mCallingUid) {
throw new SecurityException("Illegal access to the session with token " + sessionToken
+ " from uid " + callingUid);
}
- ITvInputSession session = sessionState.session;
+ return sessionState;
+ }
+
+ private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) {
+ SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
+ ITvInputSession session = sessionState.mSession;
if (session == null) {
throw new IllegalStateException("Session not yet created for token " + sessionToken);
}
@@ -249,38 +254,47 @@
false, methodName, null);
}
- private void updateServiceConnectionLocked(ComponentName name, int userId) {
+ private void updateServiceConnectionLocked(String inputId, int userId) {
UserState userState = getUserStateLocked(userId);
- ServiceState serviceState = userState.serviceStateMap.get(name);
+ ServiceState serviceState = userState.serviceStateMap.get(inputId);
if (serviceState == null) {
return;
}
- boolean isStateEmpty = serviceState.clients.isEmpty()
- && serviceState.sessionTokens.isEmpty();
- if (serviceState.service == null && !isStateEmpty && userId == mCurrentUserId) {
+ if (serviceState.mReconnecting) {
+ if (!serviceState.mSessionTokens.isEmpty()) {
+ // wait until all the sessions are removed.
+ return;
+ }
+ serviceState.mReconnecting = false;
+ }
+ boolean isStateEmpty = serviceState.mClients.isEmpty()
+ && serviceState.mSessionTokens.isEmpty();
+ if (serviceState.mService == null && !isStateEmpty && userId == mCurrentUserId) {
// This means that the service is not yet connected but its state indicates that we
// have pending requests. Then, connect the service.
- if (serviceState.bound) {
+ if (serviceState.mBound) {
// We have already bound to the service so we don't try to bind again until after we
// unbind later on.
return;
}
if (DEBUG) {
- Slog.d(TAG, "bindServiceAsUser(name=" + name.getClassName() + ", userId=" + userId
+ Slog.d(TAG, "bindServiceAsUser(inputId=" + inputId + ", userId=" + userId
+ ")");
}
- Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(name);
- mContext.bindServiceAsUser(i, serviceState.connection, Context.BIND_AUTO_CREATE,
+
+ Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(
+ userState.inputMap.get(inputId).getComponent());
+ mContext.bindServiceAsUser(i, serviceState.mConnection, Context.BIND_AUTO_CREATE,
new UserHandle(userId));
- serviceState.bound = true;
- } else if (serviceState.service != null && isStateEmpty) {
+ serviceState.mBound = true;
+ } else if (serviceState.mService != null && isStateEmpty) {
// This means that the service is already connected but its state indicates that we have
// nothing to do with it. Then, disconnect the service.
if (DEBUG) {
- Slog.d(TAG, "unbindService(name=" + name.getClassName() + ")");
+ Slog.d(TAG, "unbindService(inputId=" + inputId + ")");
}
- mContext.unbindService(serviceState.connection);
- userState.serviceStateMap.remove(name);
+ mContext.unbindService(serviceState.mConnection);
+ userState.serviceStateMap.remove(inputId);
}
}
@@ -289,8 +303,7 @@
final SessionState sessionState =
getUserStateLocked(userId).sessionStateMap.get(sessionToken);
if (DEBUG) {
- Slog.d(TAG, "createSessionInternalLocked(name=" + sessionState.name.getClassName()
- + ")");
+ Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.mInputId + ")");
}
final InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString());
@@ -300,17 +313,22 @@
@Override
public void onSessionCreated(ITvInputSession session) {
if (DEBUG) {
- Slog.d(TAG, "onSessionCreated(name=" + sessionState.name.getClassName() + ")");
+ Slog.d(TAG, "onSessionCreated(inputId=" + sessionState.mInputId + ")");
}
synchronized (mLock) {
- sessionState.session = session;
+ sessionState.mSession = session;
if (session == null) {
removeSessionStateLocked(sessionToken, userId);
- sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null,
- null, sessionState.seq, userId);
+ sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId,
+ null, null, sessionState.mSeq, userId);
} else {
- sendSessionTokenToClientLocked(sessionState.client, sessionState.name,
- sessionToken, channels[0], sessionState.seq, userId);
+ try {
+ session.asBinder().linkToDeath(sessionState, 0);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Session is already died.");
+ }
+ sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId,
+ sessionToken, channels[0], sessionState.mSeq, userId);
}
channels[0].dispose();
}
@@ -323,24 +341,32 @@
} catch (RemoteException e) {
Slog.e(TAG, "error in createSession", e);
removeSessionStateLocked(sessionToken, userId);
- sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null, null,
- sessionState.seq, userId);
+ sendSessionTokenToClientLocked(sessionState.mClient, sessionState.mInputId, null, null,
+ sessionState.mSeq, userId);
}
channels[1].dispose();
}
- private void sendSessionTokenToClientLocked(ITvInputClient client, ComponentName name,
+ private void sendSessionTokenToClientLocked(ITvInputClient client, String inputId,
IBinder sessionToken, InputChannel channel, int seq, int userId) {
try {
- client.onSessionCreated(name, sessionToken, channel, seq);
+ client.onSessionCreated(inputId, sessionToken, channel, seq);
} catch (RemoteException exception) {
Slog.e(TAG, "error in onSessionCreated", exception);
}
+ }
- if (sessionToken == null) {
- // This means that the session creation failed. We might want to disconnect the service.
- updateServiceConnectionLocked(name, userId);
+ private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) {
+ SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
+ if (sessionState.mSession != null) {
+ try {
+ sessionState.mSession.release();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "session is already disapeared", e);
+ }
+ sessionState.mSession = null;
}
+ removeSessionStateLocked(sessionToken, userId);
}
private void removeSessionStateLocked(IBinder sessionToken, int userId) {
@@ -349,19 +375,31 @@
SessionState sessionState = userState.sessionStateMap.remove(sessionToken);
// Close the open log entry, if any.
- if (sessionState.logUri != null) {
+ if (sessionState.mLogUri != null) {
SomeArgs args = SomeArgs.obtain();
- args.arg1 = sessionState.logUri;
+ args.arg1 = sessionState.mLogUri;
args.arg2 = System.currentTimeMillis();
mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args).sendToTarget();
}
// Also remove the session token from the session token list of the current service.
- ServiceState serviceState = userState.serviceStateMap.get(sessionState.name);
+ ServiceState serviceState = userState.serviceStateMap.get(sessionState.mInputId);
if (serviceState != null) {
- serviceState.sessionTokens.remove(sessionToken);
+ serviceState.mSessionTokens.remove(sessionToken);
}
- updateServiceConnectionLocked(sessionState.name, userId);
+ updateServiceConnectionLocked(sessionState.mInputId, userId);
+ }
+
+ private void broadcastServiceAvailabilityChangedLocked(ServiceState serviceState) {
+ for (IBinder iBinder : serviceState.mClients) {
+ ITvInputClient client = ITvInputClient.Stub.asInterface(iBinder);
+ try {
+ client.onAvailabilityChanged(
+ serviceState.mTvInputInfo.getId(), serviceState.mAvailable);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in onAvailabilityChanged", e);
+ }
+ }
}
private final class BinderService extends ITvInputManager.Stub {
@@ -373,7 +411,7 @@
try {
synchronized (mLock) {
UserState userState = getUserStateLocked(resolvedUserId);
- return new ArrayList<TvInputInfo>(userState.inputList);
+ return new ArrayList<TvInputInfo>(userState.inputMap.values());
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -381,7 +419,7 @@
}
@Override
- public boolean getAvailability(final ITvInputClient client, final ComponentName name,
+ public boolean getAvailability(final ITvInputClient client, final String inputId,
int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
Binder.getCallingUid(), userId, "getAvailability");
@@ -389,11 +427,11 @@
try {
synchronized (mLock) {
UserState userState = getUserStateLocked(resolvedUserId);
- ServiceState serviceState = userState.serviceStateMap.get(name);
+ ServiceState serviceState = userState.serviceStateMap.get(inputId);
if (serviceState != null) {
// We already know the status of this input service. Return the cached
// status.
- return serviceState.available;
+ return serviceState.mAvailable;
}
}
} finally {
@@ -403,7 +441,7 @@
}
@Override
- public void registerCallback(final ITvInputClient client, final ComponentName name,
+ public void registerCallback(final ITvInputClient client, final String inputId,
int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
Binder.getCallingUid(), userId, "registerCallback");
@@ -413,28 +451,29 @@
// Create a new service callback and add it to the callback map of the current
// service.
UserState userState = getUserStateLocked(resolvedUserId);
- ServiceState serviceState = userState.serviceStateMap.get(name);
+ ServiceState serviceState = userState.serviceStateMap.get(inputId);
if (serviceState == null) {
- serviceState = new ServiceState(resolvedUserId);
- userState.serviceStateMap.put(name, serviceState);
+ serviceState = new ServiceState(
+ userState.inputMap.get(inputId), resolvedUserId);
+ userState.serviceStateMap.put(inputId, serviceState);
}
IBinder iBinder = client.asBinder();
- if (!serviceState.clients.contains(iBinder)) {
- serviceState.clients.add(iBinder);
+ if (!serviceState.mClients.contains(iBinder)) {
+ serviceState.mClients.add(iBinder);
}
- if (serviceState.service != null) {
- if (serviceState.callback != null) {
+ if (serviceState.mService != null) {
+ if (serviceState.mCallback != null) {
// We already handled.
return;
}
- serviceState.callback = new ServiceCallback(resolvedUserId);
+ serviceState.mCallback = new ServiceCallback(resolvedUserId);
try {
- serviceState.service.registerCallback(serviceState.callback);
+ serviceState.mService.registerCallback(serviceState.mCallback);
} catch (RemoteException e) {
Slog.e(TAG, "error in registerCallback", e);
}
} else {
- updateServiceConnectionLocked(name, resolvedUserId);
+ updateServiceConnectionLocked(inputId, resolvedUserId);
}
}
} finally {
@@ -443,34 +482,34 @@
}
@Override
- public void unregisterCallback(ITvInputClient client, ComponentName name, int userId) {
+ public void unregisterCallback(ITvInputClient client, String inputId, int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
Binder.getCallingUid(), userId, "unregisterCallback");
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
UserState userState = getUserStateLocked(resolvedUserId);
- ServiceState serviceState = userState.serviceStateMap.get(name);
+ ServiceState serviceState = userState.serviceStateMap.get(inputId);
if (serviceState == null) {
return;
}
// Remove this client from the client list and unregister the callback.
- serviceState.clients.remove(client.asBinder());
- if (!serviceState.clients.isEmpty()) {
+ serviceState.mClients.remove(client.asBinder());
+ if (!serviceState.mClients.isEmpty()) {
// We have other clients who want to keep the callback. Do this later.
return;
}
- if (serviceState.service == null || serviceState.callback == null) {
+ if (serviceState.mService == null || serviceState.mCallback == null) {
return;
}
try {
- serviceState.service.unregisterCallback(serviceState.callback);
+ serviceState.mService.unregisterCallback(serviceState.mCallback);
} catch (RemoteException e) {
Slog.e(TAG, "error in unregisterCallback", e);
} finally {
- serviceState.callback = null;
- updateServiceConnectionLocked(name, resolvedUserId);
+ serviceState.mCallback = null;
+ updateServiceConnectionLocked(inputId, resolvedUserId);
}
}
} finally {
@@ -479,7 +518,7 @@
}
@Override
- public void createSession(final ITvInputClient client, final ComponentName name,
+ public void createSession(final ITvInputClient client, final String inputId,
int seq, int userId) {
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
@@ -487,28 +526,35 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
+ UserState userState = getUserStateLocked(resolvedUserId);
+ ServiceState serviceState = userState.serviceStateMap.get(inputId);
+ if (serviceState == null) {
+ serviceState = new ServiceState(
+ userState.inputMap.get(inputId), resolvedUserId);
+ userState.serviceStateMap.put(inputId, serviceState);
+ }
+ // Send a null token immediately while reconnecting.
+ if (serviceState.mReconnecting == true) {
+ sendSessionTokenToClientLocked(client, inputId, null, null, seq, userId);
+ return;
+ }
+
// Create a new session token and a session state.
IBinder sessionToken = new Binder();
- SessionState sessionState = new SessionState(name, client, seq, callingUid);
- sessionState.session = null;
+ SessionState sessionState = new SessionState(
+ sessionToken, inputId, client, seq, callingUid, resolvedUserId);
// Add them to the global session state map of the current user.
- UserState userState = getUserStateLocked(resolvedUserId);
userState.sessionStateMap.put(sessionToken, sessionState);
// Also, add them to the session state map of the current service.
- ServiceState serviceState = userState.serviceStateMap.get(name);
- if (serviceState == null) {
- serviceState = new ServiceState(resolvedUserId);
- userState.serviceStateMap.put(name, serviceState);
- }
- serviceState.sessionTokens.add(sessionToken);
+ serviceState.mSessionTokens.add(sessionToken);
- if (serviceState.service != null) {
- createSessionInternalLocked(serviceState.service, sessionToken,
+ if (serviceState.mService != null) {
+ createSessionInternalLocked(serviceState.mService, sessionToken,
resolvedUserId);
} else {
- updateServiceConnectionLocked(name, resolvedUserId);
+ updateServiceConnectionLocked(inputId, resolvedUserId);
}
}
} finally {
@@ -524,14 +570,7 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- // Release the session.
- try {
- getSessionLocked(sessionToken, callingUid, resolvedUserId).release();
- } catch (RemoteException e) {
- Slog.e(TAG, "error in release", e);
- }
-
- removeSessionStateLocked(sessionToken, resolvedUserId);
+ releaseSessionLocked(sessionToken, callingUid, resolvedUserId);
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -599,9 +638,9 @@
// Close the open log entry first, if any.
UserState userState = getUserStateLocked(resolvedUserId);
SessionState sessionState = userState.sessionStateMap.get(sessionToken);
- if (sessionState.logUri != null) {
+ if (sessionState.mLogUri != null) {
SomeArgs args = SomeArgs.obtain();
- args.arg1 = sessionState.logUri;
+ args.arg1 = sessionState.mLogUri;
args.arg2 = currentTime;
mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args)
.sendToTarget();
@@ -609,15 +648,15 @@
// Create a log entry and fill it later.
ContentValues values = new ContentValues();
- values.put(TvContract.WatchedPrograms.WATCH_START_TIME_UTC_MILLIS,
+ values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
currentTime);
- values.put(TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, 0);
- values.put(TvContract.WatchedPrograms.CHANNEL_ID, channelId);
+ values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, 0);
+ values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId);
- sessionState.logUri = mContentResolver.insert(
+ sessionState.mLogUri = mContentResolver.insert(
TvContract.WatchedPrograms.CONTENT_URI, values);
SomeArgs args = SomeArgs.obtain();
- args.arg1 = sessionState.logUri;
+ args.arg1 = sessionState.mLogUri;
args.arg2 = ContentUris.parseId(channelUri);
args.arg3 = currentTime;
mLogHandler.obtainMessage(LogHandler.MSG_OPEN_ENTRY, args).sendToTarget();
@@ -694,12 +733,12 @@
}
private static final class UserState {
- // A list of all known TV inputs on the system.
- private final List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
+ // A mapping from the TV input id to its TvInputInfo.
+ private final Map<String, TvInputInfo> inputMap = new HashMap<String,TvInputInfo>();
// A mapping from the name of a TV input service to its state.
- private final Map<ComponentName, ServiceState> serviceStateMap =
- new HashMap<ComponentName, ServiceState>();
+ private final Map<String, ServiceState> serviceStateMap =
+ new HashMap<String, ServiceState>();
// A mapping from the token of a TV input session to its state.
private final Map<IBinder, SessionState> sessionStateMap =
@@ -707,66 +746,91 @@
}
private final class ServiceState {
- private final List<IBinder> clients = new ArrayList<IBinder>();
- private final List<IBinder> sessionTokens = new ArrayList<IBinder>();
- private final ServiceConnection connection;
+ // TODO: need to implement DeathRecipient for clients.
+ private final List<IBinder> mClients = new ArrayList<IBinder>();
+ private final List<IBinder> mSessionTokens = new ArrayList<IBinder>();
+ private final ServiceConnection mConnection;
+ private final TvInputInfo mTvInputInfo;
- private ITvInputService service;
- private ServiceCallback callback;
- private boolean bound;
- private boolean available;
+ private ITvInputService mService;
+ private ServiceCallback mCallback;
+ private boolean mBound;
+ private boolean mAvailable;
+ private boolean mReconnecting;
- private ServiceState(int userId) {
- this.connection = new InputServiceConnection(userId);
+ private ServiceState(TvInputInfo inputInfo, int userId) {
+ mTvInputInfo = inputInfo;
+ mConnection = new InputServiceConnection(inputInfo, userId);
}
}
- private static final class SessionState {
- private final ComponentName name;
- private final ITvInputClient client;
- private final int seq;
- private final int callingUid;
+ private final class SessionState implements IBinder.DeathRecipient {
+ private final String mInputId;
+ private final ITvInputClient mClient;
+ private final int mSeq;
+ private final int mCallingUid;
+ private final int mUserId;
+ private final IBinder mToken;
+ private ITvInputSession mSession;
+ private Uri mLogUri;
- private ITvInputSession session;
- private Uri logUri;
+ private SessionState(IBinder token, String inputId, ITvInputClient client, int seq,
+ int callingUid, int userId) {
+ mToken = token;
+ mInputId = inputId;
+ mClient = client;
+ mSeq = seq;
+ mCallingUid = callingUid;
+ mUserId = userId;
+ }
- private SessionState(ComponentName name, ITvInputClient client, int seq, int callingUid) {
- this.name = name;
- this.client = client;
- this.seq = seq;
- this.callingUid = callingUid;
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ mSession = null;
+ if (mClient != null) {
+ try {
+ mClient.onSessionReleased(mSeq);
+ } catch(RemoteException e) {
+ Slog.e(TAG, "error in onSessionReleased", e);
+ }
+ }
+ removeSessionStateLocked(mToken, mUserId);
+ }
}
}
private final class InputServiceConnection implements ServiceConnection {
+ private final TvInputInfo mTvInputInfo;
private final int mUserId;
- private InputServiceConnection(int userId) {
+ private InputServiceConnection(TvInputInfo inputInfo, int userId) {
mUserId = userId;
+ mTvInputInfo = inputInfo;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG) {
- Slog.d(TAG, "onServiceConnected(name=" + name.getClassName() + ")");
+ Slog.d(TAG, "onServiceConnected(inputId=" + mTvInputInfo.getId() + ")");
}
synchronized (mLock) {
- ServiceState serviceState = getServiceStateLocked(name, mUserId);
- serviceState.service = ITvInputService.Stub.asInterface(service);
+ ServiceState serviceState = getServiceStateLocked(mTvInputInfo.getId(), mUserId);
+ serviceState.mService = ITvInputService.Stub.asInterface(service);
// Register a callback, if we need to.
- if (!serviceState.clients.isEmpty() && serviceState.callback == null) {
- serviceState.callback = new ServiceCallback(mUserId);
+ if (!serviceState.mClients.isEmpty() && serviceState.mCallback == null) {
+ serviceState.mCallback = new ServiceCallback(mUserId);
try {
- serviceState.service.registerCallback(serviceState.callback);
+ serviceState.mService.registerCallback(serviceState.mCallback);
} catch (RemoteException e) {
Slog.e(TAG, "error in registerCallback", e);
}
}
// And create sessions, if any.
- for (IBinder sessionToken : serviceState.sessionTokens) {
- createSessionInternalLocked(serviceState.service, sessionToken, mUserId);
+ for (IBinder sessionToken : serviceState.mSessionTokens) {
+ createSessionInternalLocked(serviceState.mService, sessionToken, mUserId);
}
}
}
@@ -774,7 +838,38 @@
@Override
public void onServiceDisconnected(ComponentName name) {
if (DEBUG) {
- Slog.d(TAG, "onServiceDisconnected(name=" + name.getClassName() + ")");
+ Slog.d(TAG, "onServiceDisconnected(inputId=" + mTvInputInfo.getId() + ")");
+ }
+ if (!mTvInputInfo.getComponent().equals(name)) {
+ throw new IllegalArgumentException("Mismatched ComponentName: "
+ + mTvInputInfo.getComponent() + " (expected), " + name + " (actual).");
+ }
+ synchronized (mLock) {
+ UserState userState = getUserStateLocked(mUserId);
+ ServiceState serviceState = userState.serviceStateMap.get(mTvInputInfo.getId());
+ if (serviceState != null) {
+ serviceState.mReconnecting = true;
+ serviceState.mBound = false;
+ serviceState.mService = null;
+ serviceState.mCallback = null;
+
+ // Send null tokens for not finishing create session events.
+ for (IBinder sessionToken : serviceState.mSessionTokens) {
+ SessionState sessionState = userState.sessionStateMap.get(sessionToken);
+ if (sessionState.mSession == null) {
+ removeSessionStateLocked(sessionToken, sessionState.mUserId);
+ sendSessionTokenToClientLocked(sessionState.mClient,
+ sessionState.mInputId, null, null, sessionState.mSeq,
+ sessionState.mUserId);
+ }
+ }
+
+ if (serviceState.mAvailable) {
+ serviceState.mAvailable = false;
+ broadcastServiceAvailabilityChangedLocked(serviceState);
+ }
+ updateServiceConnectionLocked(mTvInputInfo.getId(), mUserId);
+ }
}
}
}
@@ -787,18 +882,16 @@
}
@Override
- public void onAvailabilityChanged(ComponentName name, boolean isAvailable)
- throws RemoteException {
+ public void onAvailabilityChanged(String inputId, boolean isAvailable) {
if (DEBUG) {
- Slog.d(TAG, "onAvailabilityChanged(name=" + name.getClassName() + ", isAvailable="
+ Slog.d(TAG, "onAvailabilityChanged(inputId=" + inputId + ", isAvailable="
+ isAvailable + ")");
}
synchronized (mLock) {
- ServiceState serviceState = getServiceStateLocked(name, mUserId);
- serviceState.available = isAvailable;
- for (IBinder iBinder : serviceState.clients) {
- ITvInputClient client = ITvInputClient.Stub.asInterface(iBinder);
- client.onAvailabilityChanged(name, isAvailable);
+ ServiceState serviceState = getServiceStateLocked(inputId, mUserId);
+ if (serviceState.mAvailable != isAvailable) {
+ serviceState.mAvailable = isAvailable;
+ broadcastServiceAvailabilityChangedLocked(serviceState);
}
}
}
@@ -851,31 +944,32 @@
private void onOpenEntry(Uri uri, long channelId, long watchStarttime) {
String[] projection = {
- TvContract.Programs.TITLE,
- TvContract.Programs.START_TIME_UTC_MILLIS,
- TvContract.Programs.END_TIME_UTC_MILLIS,
- TvContract.Programs.DESCRIPTION
+ TvContract.Programs.COLUMN_TITLE,
+ TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS,
+ TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS,
+ TvContract.Programs.COLUMN_DESCRIPTION
};
- String selection = TvContract.Programs.CHANNEL_ID + "=? AND "
- + TvContract.Programs.START_TIME_UTC_MILLIS + "<=? AND "
- + TvContract.Programs.END_TIME_UTC_MILLIS + ">?";
+ String selection = TvContract.Programs.COLUMN_CHANNEL_ID + "=? AND "
+ + TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS + "<=? AND "
+ + TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS + ">?";
String[] selectionArgs = {
String.valueOf(channelId),
String.valueOf(watchStarttime),
String.valueOf(watchStarttime)
};
- String sortOrder = TvContract.Programs.START_TIME_UTC_MILLIS + " ASC";
+ String sortOrder = TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS + " ASC";
Cursor cursor = null;
try {
cursor = mContentResolver.query(TvContract.Programs.CONTENT_URI, projection,
selection, selectionArgs, sortOrder);
if (cursor != null && cursor.moveToNext()) {
ContentValues values = new ContentValues();
- values.put(TvContract.WatchedPrograms.TITLE, cursor.getString(0));
- values.put(TvContract.WatchedPrograms.START_TIME_UTC_MILLIS, cursor.getLong(1));
+ values.put(TvContract.WatchedPrograms.COLUMN_TITLE, cursor.getString(0));
+ values.put(TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS,
+ cursor.getLong(1));
long endTime = cursor.getLong(2);
- values.put(TvContract.WatchedPrograms.END_TIME_UTC_MILLIS, endTime);
- values.put(TvContract.WatchedPrograms.DESCRIPTION, cursor.getString(3));
+ values.put(TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
+ values.put(TvContract.WatchedPrograms.COLUMN_DESCRIPTION, cursor.getString(3));
mContentResolver.update(uri, values, null, null);
// Schedule an update when the current program ends.
@@ -895,12 +989,12 @@
private void onUpdateEntry(Uri uri, long channelId, long time) {
String[] projection = {
- TvContract.WatchedPrograms.WATCH_START_TIME_UTC_MILLIS,
- TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS,
- TvContract.WatchedPrograms.TITLE,
- TvContract.WatchedPrograms.START_TIME_UTC_MILLIS,
- TvContract.WatchedPrograms.END_TIME_UTC_MILLIS,
- TvContract.WatchedPrograms.DESCRIPTION
+ TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
+ TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS,
+ TvContract.WatchedPrograms.COLUMN_TITLE,
+ TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS,
+ TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS,
+ TvContract.WatchedPrograms.COLUMN_DESCRIPTION
};
Cursor cursor = null;
try {
@@ -921,14 +1015,14 @@
// The current program has just ended. Create a (complete) log entry off the
// current entry.
ContentValues values = new ContentValues();
- values.put(TvContract.WatchedPrograms.WATCH_START_TIME_UTC_MILLIS,
+ values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
watchStartTime);
- values.put(TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, time);
- values.put(TvContract.WatchedPrograms.CHANNEL_ID, channelId);
- values.put(TvContract.WatchedPrograms.TITLE, title);
- values.put(TvContract.WatchedPrograms.START_TIME_UTC_MILLIS, startTime);
- values.put(TvContract.WatchedPrograms.END_TIME_UTC_MILLIS, endTime);
- values.put(TvContract.WatchedPrograms.DESCRIPTION, description);
+ values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, time);
+ values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId);
+ values.put(TvContract.WatchedPrograms.COLUMN_TITLE, title);
+ values.put(TvContract.WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS, startTime);
+ values.put(TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
+ values.put(TvContract.WatchedPrograms.COLUMN_DESCRIPTION, description);
mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
}
} finally {
@@ -942,7 +1036,7 @@
private void onCloseEntry(Uri uri, long watchEndTime) {
ContentValues values = new ContentValues();
- values.put(TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, watchEndTime);
+ values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, watchEndTime);
mContentResolver.update(uri, values, null, null);
}
}
diff --git a/services/core/java/com/android/server/wm/ViewServer.java b/services/core/java/com/android/server/wm/ViewServer.java
index a763e2c..741cee3 100644
--- a/services/core/java/com/android/server/wm/ViewServer.java
+++ b/services/core/java/com/android/server/wm/ViewServer.java
@@ -314,7 +314,7 @@
out.flush();
}
if (needFocusedWindowUpdate) {
- out.write("FOCUS UPDATE\n");
+ out.write("ACTION_FOCUS UPDATE\n");
out.flush();
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 637beec..836a19c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5038,6 +5038,10 @@
throw new SecurityException("Requires DISABLE_KEYGUARD permission");
}
+ if (token == null) {
+ throw new IllegalArgumentException("token == null");
+ }
+
mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(
KeyguardDisableHandler.KEYGUARD_DISABLE, new Pair<IBinder, String>(token, tag)));
}
@@ -5049,6 +5053,10 @@
throw new SecurityException("Requires DISABLE_KEYGUARD permission");
}
+ if (token == null) {
+ throw new IllegalArgumentException("token == null");
+ }
+
mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(
KeyguardDisableHandler.KEYGUARD_REENABLE, token));
}
@@ -5062,6 +5070,11 @@
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires DISABLE_KEYGUARD permission");
}
+
+ if (callback == null) {
+ throw new IllegalArgumentException("callback == null");
+ }
+
mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() {
@Override
public void onKeyguardExitResult(boolean success) {
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index f7bec6e..39f228f 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -28,6 +28,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
@@ -35,6 +36,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintJobStateChangeListener;
import android.print.IPrintManager;
@@ -91,18 +93,23 @@
private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
"EXTRA_PRINT_SERVICE_COMPONENT_NAME";
+ private static final int BACKGROUND_USER_ID = -10;
+
private final Object mLock = new Object();
private final Context mContext;
+ private final UserManager mUserManager;
+
private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
private int mCurrentUserId = UserHandle.USER_OWNER;
PrintManagerImpl(Context context) {
mContext = context;
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
registerContentObservers();
- registerBoradcastReceivers();
+ registerBroadcastReceivers();
}
public void systemRunning() {
@@ -125,11 +132,17 @@
@Override
public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
PrintAttributes attributes, String packageName, int appId, int userId) {
- final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
- String resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName);
+ final int resolvedAppId;
final UserState userState;
+ final String resolvedPackageName;
synchronized (mLock) {
+ // Only the current group members can start new print jobs.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+ return null;
+ }
+ resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+ resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName);
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
@@ -143,10 +156,15 @@
@Override
public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) {
- final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final int resolvedAppId;
final UserState userState;
synchronized (mLock) {
+ // Only the current group members can query for state of print jobs.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+ return null;
+ }
+ resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
@@ -159,10 +177,15 @@
@Override
public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
- final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final int resolvedAppId;
final UserState userState;
synchronized (mLock) {
+ // Only the current group members can query for state of a print job.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+ return null;
+ }
+ resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
@@ -175,10 +198,15 @@
@Override
public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
- final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final int resolvedAppId;
final UserState userState;
synchronized (mLock) {
+ // Only the current group members can cancel a print job.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+ return;
+ }
+ resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
@@ -191,10 +219,15 @@
@Override
public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
- final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final int resolvedAppId;
final UserState userState;
synchronized (mLock) {
+ // Only the current group members can restart a print job.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+ return;
+ }
+ resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
@@ -210,6 +243,10 @@
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
+ // Only the current group members can get enabled services.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+ return null;
+ }
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
@@ -225,6 +262,10 @@
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
+ // Only the current group members can get installed services.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+ return null;
+ }
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
@@ -241,6 +282,10 @@
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
+ // Only the current group members can create a discovery session.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+ return;
+ }
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
@@ -257,6 +302,10 @@
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
+ // Only the current group members can destroy a discovery session.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+ return;
+ }
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
@@ -273,6 +322,10 @@
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
+ // Only the current group members can start discovery.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+ return;
+ }
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
@@ -288,6 +341,10 @@
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
+ // Only the current group members can stop discovery.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+ return;
+ }
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
@@ -303,6 +360,10 @@
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
+ // Only the current group members can validate printers.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+ return;
+ }
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
@@ -318,6 +379,10 @@
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
+ // Only the current group members can start printer tracking.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+ return;
+ }
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
@@ -333,6 +398,10 @@
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
+ // Only the current group members can stop printer tracking.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+ return;
+ }
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
@@ -347,9 +416,14 @@
public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
int appId, int userId) throws RemoteException {
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
- final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+ final int resolvedAppId;
final UserState userState;
synchronized (mLock) {
+ // Only the current group members can add a print job listener.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+ return;
+ }
+ resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
@@ -366,6 +440,10 @@
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
+ // Only the current group members can remove a print job listener.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != mCurrentUserId) {
+ return;
+ }
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
@@ -421,11 +499,14 @@
false, observer, UserHandle.USER_ALL);
}
- private void registerBoradcastReceivers() {
+ private void registerBroadcastReceivers() {
PackageMonitor monitor = new PackageMonitor() {
@Override
public void onPackageModified(String packageName) {
synchronized (mLock) {
+ // A background user/profile's print jobs are running but there is
+ // no UI shown. Hence, if the packages of such a user change we need
+ // to handle it as the change may affect ongoing print jobs.
boolean servicesChanged = false;
UserState userState = getOrCreateUserStateLocked(getChangingUserId());
Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
@@ -444,6 +525,9 @@
@Override
public void onPackageRemoved(String packageName, int uid) {
synchronized (mLock) {
+ // A background user/profile's print jobs are running but there is
+ // no UI shown. Hence, if the packages of such a user change we need
+ // to handle it as the change may affect ongoing print jobs.
boolean servicesRemoved = false;
UserState userState = getOrCreateUserStateLocked(getChangingUserId());
Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
@@ -467,6 +551,9 @@
public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
int uid, boolean doit) {
synchronized (mLock) {
+ // A background user/profile's print jobs are running but there is
+ // no UI shown. Hence, if the packages of such a user change we need
+ // to handle it as the change may affect ongoing print jobs.
UserState userState = getOrCreateUserStateLocked(getChangingUserId());
boolean stoppedSomePackages = false;
Iterator<ComponentName> iterator = userState.getEnabledServices()
@@ -493,6 +580,9 @@
@Override
public void onPackageAdded(String packageName, int uid) {
+ // A background user/profile's print jobs are running but there is
+ // no UI shown. Hence, if the packages of such a user change we need
+ // to handle it as the change may affect ongoing print jobs.
Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
intent.setPackage(packageName);
@@ -596,6 +686,23 @@
}
}
+ private int resolveCallingProfileParentLocked(int userId) {
+ if (userId != mCurrentUserId) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ UserInfo parent = mUserManager.getProfileParent(userId);
+ if (parent != null) {
+ return parent.getUserHandle().getIdentifier();
+ } else {
+ return BACKGROUND_USER_ID;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ return userId;
+ }
+
private int resolveCallingAppEnforcingPermissions(int appId) {
final int callingUid = Binder.getCallingUid();
if (callingUid == 0 || callingUid == Process.SYSTEM_UID
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index f955f4f..88aaafc 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -163,9 +163,10 @@
nextConnBroadcast.get();
// verify that both routes were added and DNS was flushed
- verify(mNetManager).addRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V4));
- verify(mNetManager).addRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V6));
- verify(mNetManager).flushInterfaceDnsCache(MOBILE_IFACE);
+ int mobileNetId = mMobile.tracker.getNetwork().netId;
+ verify(mNetManager).addRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V4));
+ verify(mNetManager).addRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V6));
+ verify(mNetManager).flushNetworkDnsCache(mobileNetId);
}
@@ -200,11 +201,14 @@
nextConnBroadcast.get();
// verify that wifi routes added, and teardown requested
- verify(mNetManager).addRoute(eq(WIFI_IFACE), eq(WIFI_ROUTE_V4));
- verify(mNetManager).addRoute(eq(WIFI_IFACE), eq(WIFI_ROUTE_V6));
- verify(mNetManager).flushInterfaceDnsCache(WIFI_IFACE);
+ int wifiNetId = mWifi.tracker.getNetwork().netId;
+ verify(mNetManager).addRoute(eq(wifiNetId), eq(WIFI_ROUTE_V4));
+ verify(mNetManager).addRoute(eq(wifiNetId), eq(WIFI_ROUTE_V6));
+ verify(mNetManager).flushNetworkDnsCache(wifiNetId);
verify(mMobile.tracker).teardown();
+ int mobileNetId = mMobile.tracker.getNetwork().netId;
+
reset(mNetManager, mMobile.tracker);
// tear down mobile network, as requested
@@ -216,8 +220,8 @@
mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
nextConnBroadcast.get();
- verify(mNetManager).removeRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V4));
- verify(mNetManager).removeRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V6));
+ verify(mNetManager).removeRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V4));
+ verify(mNetManager).removeRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V6));
}
diff --git a/telecomm/java/android/telecomm/CallAudioState.aidl b/telecomm/java/android/telecomm/CallAudioState.aidl
new file mode 100644
index 0000000..ae64567
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallAudioState.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+parcelable CallAudioState;
diff --git a/telecomm/java/android/telecomm/CallAudioState.java b/telecomm/java/android/telecomm/CallAudioState.java
new file mode 100644
index 0000000..d9a0090
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallAudioState.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Locale;
+
+/**
+ * Encapsulates all audio states during a call.
+ */
+public final class CallAudioState implements Parcelable {
+ /** Direct the audio stream through the device's earpiece. */
+ public static int ROUTE_EARPIECE = 0x00000001;
+
+ /** Direct the audio stream through Bluetooth. */
+ public static int ROUTE_BLUETOOTH = 0x00000002;
+
+ /** Direct the audio stream through a wired headset. */
+ public static int ROUTE_WIRED_HEADSET = 0x00000004;
+
+ /** Direct the audio stream through the device's spakerphone. */
+ public static int ROUTE_SPEAKER = 0x00000008;
+
+ /**
+ * Direct the audio stream through the device's earpiece or wired headset if one is
+ * connected.
+ */
+ public static int ROUTE_WIRED_OR_EARPIECE = ROUTE_EARPIECE | ROUTE_WIRED_HEADSET;
+
+ /** Bit mask of all possible audio routes. */
+ public static int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET |
+ ROUTE_SPEAKER;
+
+ /** True if the call is muted, false otherwise. */
+ public final boolean isMuted;
+
+ /** The route to use for the audio stream. */
+ public final int route;
+
+ /** Bit vector of all routes supported by this call. */
+ public final int supportedRouteMask;
+
+ /** @hide */
+ public CallAudioState(boolean isMuted, int route, int supportedRouteMask) {
+ this.isMuted = isMuted;
+ this.route = route;
+ this.supportedRouteMask = supportedRouteMask;
+ }
+
+ /** @hide */
+ public CallAudioState(CallAudioState state) {
+ isMuted = state.isMuted;
+ route = state.route;
+ supportedRouteMask = state.supportedRouteMask;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof CallAudioState)) {
+ return false;
+ }
+ CallAudioState state = (CallAudioState) obj;
+ return isMuted == state.isMuted && route == state.route &&
+ supportedRouteMask == state.supportedRouteMask;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(Locale.US,
+ "[CallAudioState isMuted: %b, route; %s, supportedRouteMask: %s]",
+ isMuted, audioRouteToString(route), audioRouteToString(supportedRouteMask));
+ }
+
+ /** @hide */
+ public static String audioRouteToString(int route) {
+ if (route == 0 || (route & ~ROUTE_ALL) != 0x0) {
+ return "UNKNOWN";
+ }
+
+ StringBuffer buffer = new StringBuffer();
+ if ((route & ROUTE_EARPIECE) == ROUTE_EARPIECE) {
+ listAppend(buffer, "EARPIECE");
+ }
+ if ((route & ROUTE_BLUETOOTH) == ROUTE_BLUETOOTH) {
+ listAppend(buffer, "BLUETOOTH");
+ }
+ if ((route & ROUTE_WIRED_HEADSET) == ROUTE_WIRED_HEADSET) {
+ listAppend(buffer, "WIRED_HEADSET");
+ }
+ if ((route & ROUTE_SPEAKER) == ROUTE_SPEAKER) {
+ listAppend(buffer, "SPEAKER");
+ }
+
+ return buffer.toString();
+ }
+
+ private static void listAppend(StringBuffer buffer, String str) {
+ if (buffer.length() > 0) {
+ buffer.append(", ");
+ }
+ buffer.append(str);
+ }
+
+ /**
+ * Responsible for creating CallAudioState objects for deserialized Parcels.
+ */
+ public static final Parcelable.Creator<CallAudioState> CREATOR =
+ new Parcelable.Creator<CallAudioState> () {
+
+ @Override
+ public CallAudioState createFromParcel(Parcel source) {
+ boolean isMuted = source.readByte() == 0 ? false : true;
+ int route = source.readInt();
+ int supportedRouteMask = source.readInt();
+ return new CallAudioState(isMuted, route, supportedRouteMask);
+ }
+
+ @Override
+ public CallAudioState[] newArray(int size) {
+ return new CallAudioState[size];
+ }
+ };
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Writes CallAudioState object into a serializeable Parcel.
+ */
+ @Override
+ public void writeToParcel(Parcel destination, int flags) {
+ destination.writeByte((byte) (isMuted ? 1 : 0));
+ destination.writeInt(route);
+ destination.writeInt(supportedRouteMask);
+ }
+}
diff --git a/telecomm/java/android/telecomm/CallCapabilities.java b/telecomm/java/android/telecomm/CallCapabilities.java
new file mode 100644
index 0000000..b2b33a3
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallCapabilities.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+/** Defines actions a call currently supports. */
+public class CallCapabilities {
+ /** Call can currently be put on hold or unheld. */
+ public static final int HOLD = 0x00000001;
+
+ /** Call supports the hold feature. */
+ public static final int SUPPORT_HOLD = 0x00000002;
+
+ /** Call can currently be merged. */
+ public static final int MERGE_CALLS = 0x00000004;
+
+ /* Call can currently be swapped with another call. */
+ public static final int SWAP_CALLS = 0x00000008;
+
+ /* Call currently supports adding another call to this one. */
+ public static final int ADD_CALL = 0x00000010;
+
+ /* Call supports responding via text option. */
+ public static final int RESPOND_VIA_TEXT = 0x00000020;
+
+ /* Call can be muted. */
+ public static final int MUTE = 0x00000040;
+
+ /* Call supports generic conference mode. */
+ public static final int GENERIC_CONFERENCE = 0x00000080;
+
+ /* Call currently supports switch between connections. */
+ public static final int CONNECTION_HANDOFF = 0x00000100;
+
+ public static final int ALL = HOLD | SUPPORT_HOLD | MERGE_CALLS | SWAP_CALLS | ADD_CALL
+ | RESPOND_VIA_TEXT | MUTE | GENERIC_CONFERENCE | CONNECTION_HANDOFF;
+}
diff --git a/telecomm/java/android/telecomm/CallInfo.aidl b/telecomm/java/android/telecomm/CallInfo.aidl
new file mode 100644
index 0000000..bc5ef96
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 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 android.telecomm;
+
+parcelable CallInfo;
diff --git a/telecomm/java/android/telecomm/CallInfo.java b/telecomm/java/android/telecomm/CallInfo.java
new file mode 100644
index 0000000..cb7f2dc
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallInfo.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 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 android.telecomm;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Date;
+
+/**
+ * A parcelable holder class of Call information data. This class is intended for transfering call
+ * information from Telecomm to call services and thus is read-only.
+ * TODO(santoscordon): Need final public-facing comments in this file.
+ */
+public final class CallInfo implements Parcelable {
+
+ /**
+ * Unique identifier for the call.
+ */
+ private final String mId;
+
+ /**
+ * The state of the call.
+ */
+ private final CallState mState;
+
+ /**
+ * Endpoint to which the call is connected.
+ * This could be the dialed value for outgoing calls or the caller id of incoming calls.
+ */
+ private final Uri mHandle;
+
+ /**
+ * Gateway information for the call.
+ */
+ private final GatewayInfo mGatewayInfo;
+
+ /**
+ * Additional information that can be persisted. For example, extra handoff information can
+ * attached to a call using {@link CallServiceSelectorAdapter#setHandoffInfo(String,Uri,Bundle).
+ */
+ private final Bundle mExtras;
+
+ /** The descriptor for the call service currently routing this call. */
+ private final CallServiceDescriptor mCurrentCallServiceDescriptor;
+
+ public CallInfo(String id, CallState state, Uri handle) {
+ this(id, state, handle, null, Bundle.EMPTY, null);
+ }
+
+ /**
+ * Persists handle of the other party of this call.
+ *
+ * @param id The unique ID of the call.
+ * @param state The state of the call.
+ * @param handle The handle to the other party in this call.
+ * @param gatewayInfo Gateway information pertaining to this call.
+ * @param extras Additional information that can be persisted.
+ * @param currentCallServiceDescriptor The descriptor for the call service currently routing
+ * this call.
+ *
+ * @hide
+ */
+ public CallInfo(
+ String id,
+ CallState state,
+ Uri handle,
+ GatewayInfo gatewayInfo,
+ Bundle extras,
+ CallServiceDescriptor currentCallServiceDescriptor) {
+ mId = id;
+ mState = state;
+ mHandle = handle;
+ mGatewayInfo = gatewayInfo;
+ mExtras = extras;
+ mCurrentCallServiceDescriptor = currentCallServiceDescriptor;
+ }
+
+ public String getId() {
+ return mId;
+ }
+
+ public CallState getState() {
+ return mState;
+ }
+
+ public Uri getHandle() {
+ return mHandle;
+ }
+
+ /**
+ * @return The actual handle this call is associated with. This is used by call services to
+ * correctly indicate in their UI what handle the user is actually calling, and by other
+ * telecomm components that require the user-dialed handle to function.
+ */
+ public Uri getOriginalHandle() {
+ if (mGatewayInfo != null) {
+ return mGatewayInfo.getOriginalHandle();
+ }
+ return getHandle();
+ }
+
+ public GatewayInfo getGatewayInfo() {
+ return mGatewayInfo;
+ }
+
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ public CallServiceDescriptor getCurrentCallServiceDescriptor() {
+ return mCurrentCallServiceDescriptor;
+ }
+
+ /**
+ * Responsible for creating CallInfo objects for deserialized Parcels.
+ */
+ public static final Parcelable.Creator<CallInfo> CREATOR = new Parcelable.Creator<CallInfo> () {
+ @Override
+ public CallInfo createFromParcel(Parcel source) {
+ String id = source.readString();
+ CallState state = CallState.valueOf(source.readString());
+ Uri handle = Uri.CREATOR.createFromParcel(source);
+
+ boolean gatewayInfoPresent = source.readByte() != 0;
+ GatewayInfo gatewayInfo = null;
+ if (gatewayInfoPresent) {
+ gatewayInfo = GatewayInfo.CREATOR.createFromParcel(source);
+ }
+
+ ClassLoader classLoader = CallInfo.class.getClassLoader();
+ Bundle extras = source.readParcelable(classLoader);
+ CallServiceDescriptor descriptor = source.readParcelable(classLoader);
+ return new CallInfo(id, state, handle, gatewayInfo, extras, descriptor);
+ }
+
+ @Override
+ public CallInfo[] newArray(int size) {
+ return new CallInfo[size];
+ }
+ };
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Writes CallInfo object into a serializeable Parcel.
+ */
+ @Override
+ public void writeToParcel(Parcel destination, int flags) {
+ destination.writeString(mId);
+ destination.writeString(mState.name());
+ mHandle.writeToParcel(destination, 0);
+
+ if (mGatewayInfo != null) {
+ destination.writeByte((byte) 1);
+ mGatewayInfo.writeToParcel(destination, 0);
+ } else {
+ destination.writeByte((byte) 0);
+ }
+
+ destination.writeParcelable(mExtras, 0);
+ destination.writeParcelable(mCurrentCallServiceDescriptor, 0);
+ }
+}
diff --git a/telecomm/java/android/telecomm/CallNumberPresentation.java b/telecomm/java/android/telecomm/CallNumberPresentation.java
new file mode 100644
index 0000000..6cd22f8
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallNumberPresentation.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+/** Defines how numbers are displayed in caller id. */
+public enum CallNumberPresentation {
+ /** Number is displayed normally. */
+ ALLOWED,
+
+ /** Number was blocked. */
+ RESTRICTED,
+
+ /** Presentation was not specified or is unknown. */
+ UNKNOWN,
+
+ /** Number should be displayed as a pay phone. */
+ PAYPHONE
+}
diff --git a/telecomm/java/android/telecomm/CallService.java b/telecomm/java/android/telecomm/CallService.java
new file mode 100644
index 0000000..51f10c1
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallService.java
@@ -0,0 +1,362 @@
+/*
+ * 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 android.telecomm;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+
+import com.android.internal.os.SomeArgs;
+import com.android.internal.telecomm.ICallService;
+import com.android.internal.telecomm.ICallServiceAdapter;
+
+/**
+ * Base implementation of CallService which can be used to provide calls for the system
+ * in-call UI. CallService is a one-way service from the framework's CallsManager to any app
+ * that would like to provide calls managed by the default system in-call user interface.
+ * When the service is bound by the framework, CallsManager will call setCallServiceAdapter
+ * which will provide CallService with an instance of {@link CallServiceAdapter} to be used
+ * for communicating back to CallsManager. Subsequently, more specific methods of the service
+ * will be called to perform various call actions including making an outgoing call and
+ * disconnected existing calls.
+ * TODO(santoscordon): Needs more about AndroidManifest.xml service registrations before
+ * we can unhide this API.
+ *
+ * Most public methods of this function are backed by a one-way AIDL interface which precludes
+ * synchronous responses. As a result, most responses are handled by (or have TODOs to handle)
+ * response objects instead of return values.
+ * TODO(santoscordon): Improve paragraph above once the final design is in place.
+ */
+public abstract class CallService extends Service {
+
+ private static final int MSG_SET_CALL_SERVICE_ADAPTER = 1;
+ private static final int MSG_IS_COMPATIBLE_WITH = 2;
+ private static final int MSG_CALL = 3;
+ private static final int MSG_ABORT = 4;
+ private static final int MSG_SET_INCOMING_CALL_ID = 5;
+ private static final int MSG_ANSWER = 6;
+ private static final int MSG_REJECT = 7;
+ private static final int MSG_DISCONNECT = 8;
+ private static final int MSG_HOLD = 9;
+ private static final int MSG_UNHOLD = 10;
+ private static final int MSG_ON_AUDIO_STATE_CHANGED = 11;
+ private static final int MSG_PLAY_DTMF_TONE = 12;
+ private static final int MSG_STOP_DTMF_TONE = 13;
+
+ /**
+ * Default Handler used to consolidate binder method calls onto a single thread.
+ */
+ private final class CallServiceMessageHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SET_CALL_SERVICE_ADAPTER:
+ mAdapter = new CallServiceAdapter((ICallServiceAdapter) msg.obj);
+ onAdapterAttached(mAdapter);
+ break;
+ case MSG_IS_COMPATIBLE_WITH:
+ isCompatibleWith((CallInfo) msg.obj);
+ break;
+ case MSG_CALL:
+ call((CallInfo) msg.obj);
+ break;
+ case MSG_ABORT:
+ abort((String) msg.obj);
+ break;
+ case MSG_SET_INCOMING_CALL_ID: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ String callId = (String) args.arg1;
+ Bundle extras = (Bundle) args.arg2;
+ setIncomingCallId(callId, extras);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_ANSWER:
+ answer((String) msg.obj);
+ break;
+ case MSG_REJECT:
+ reject((String) msg.obj);
+ break;
+ case MSG_DISCONNECT:
+ disconnect((String) msg.obj);
+ break;
+ case MSG_HOLD:
+ hold((String) msg.obj);
+ break;
+ case MSG_UNHOLD:
+ unhold((String) msg.obj);
+ break;
+ case MSG_ON_AUDIO_STATE_CHANGED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ String callId = (String) args.arg1;
+ CallAudioState audioState = (CallAudioState) args.arg2;
+ onAudioStateChanged(callId, audioState);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_PLAY_DTMF_TONE:
+ playDtmfTone((String) msg.obj, (char) msg.arg1);
+ break;
+ case MSG_STOP_DTMF_TONE:
+ stopDtmfTone((String) msg.obj);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
+ * Default ICallService implementation provided to CallsManager via {@link #onBind}.
+ */
+ private final class CallServiceBinder extends ICallService.Stub {
+ @Override
+ public void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter) {
+ mMessageHandler.obtainMessage(MSG_SET_CALL_SERVICE_ADAPTER, callServiceAdapter)
+ .sendToTarget();
+ }
+
+ @Override
+ public void isCompatibleWith(CallInfo callInfo) {
+ mMessageHandler.obtainMessage(MSG_IS_COMPATIBLE_WITH, callInfo).sendToTarget();
+ }
+
+ @Override
+ public void call(CallInfo callInfo) {
+ mMessageHandler.obtainMessage(MSG_CALL, callInfo).sendToTarget();
+ }
+
+ @Override
+ public void abort(String callId) {
+ mMessageHandler.obtainMessage(MSG_ABORT, callId).sendToTarget();
+ }
+
+ @Override
+ public void setIncomingCallId(String callId, Bundle extras) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = extras;
+ mMessageHandler.obtainMessage(MSG_SET_INCOMING_CALL_ID, args).sendToTarget();
+ }
+
+ @Override
+ public void answer(String callId) {
+ mMessageHandler.obtainMessage(MSG_ANSWER, callId).sendToTarget();
+ }
+
+ @Override
+ public void reject(String callId) {
+ mMessageHandler.obtainMessage(MSG_REJECT, callId).sendToTarget();
+ }
+
+ @Override
+ public void disconnect(String callId) {
+ mMessageHandler.obtainMessage(MSG_DISCONNECT, callId).sendToTarget();
+ }
+
+ @Override
+ public void hold(String callId) {
+ mMessageHandler.obtainMessage(MSG_HOLD, callId).sendToTarget();
+ }
+
+ @Override
+ public void unhold(String callId) {
+ mMessageHandler.obtainMessage(MSG_UNHOLD, callId).sendToTarget();
+ }
+
+ @Override
+ public void playDtmfTone(String callId, char digit) {
+ mMessageHandler.obtainMessage(MSG_PLAY_DTMF_TONE, digit, 0, callId).sendToTarget();
+ }
+
+ @Override
+ public void stopDtmfTone(String callId) {
+ mMessageHandler.obtainMessage(MSG_STOP_DTMF_TONE, callId).sendToTarget();
+ }
+
+ @Override
+ public void onAudioStateChanged(String callId, CallAudioState audioState) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = audioState;
+ mMessageHandler.obtainMessage(MSG_ON_AUDIO_STATE_CHANGED, args).sendToTarget();
+ }
+ }
+
+ /**
+ * Message handler for consolidating binder callbacks onto a single thread.
+ * See {@link CallServiceMessageHandler}.
+ */
+ private final CallServiceMessageHandler mMessageHandler = new CallServiceMessageHandler();
+
+ /**
+ * Default binder implementation of {@link ICallService} interface.
+ */
+ private final CallServiceBinder mBinder = new CallServiceBinder();
+
+ private CallServiceAdapter mAdapter = null;
+
+ /** {@inheritDoc} */
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return getBinder();
+ }
+
+ /**
+ * Returns binder object which can be used across IPC methods.
+ */
+ public final IBinder getBinder() {
+ return mBinder;
+ }
+
+ /**
+ * @return The attached {@link CallServiceAdapter} if the service is bound, null otherwise.
+ */
+ protected final CallServiceAdapter getAdapter() {
+ return mAdapter;
+ }
+
+ /**
+ * Lifecycle callback which is called when this {@link CallService} has been attached to a
+ * {@link CallServiceAdapter}, indicating {@link #getAdapter()} is now safe to use.
+ *
+ * @param adapter The adapter now attached to this call service.
+ */
+ protected void onAdapterAttached(CallServiceAdapter adapter) {
+ }
+
+ /**
+ * Determines if the CallService can place the specified call. Response is sent via
+ * {@link CallServiceAdapter#setIsCompatibleWith}. When responding, the correct call ID must be
+ * specified. Only used in the context of outgoing calls and call switching (handoff).
+ *
+ * @param callInfo The details of the relevant call.
+ */
+ public abstract void isCompatibleWith(CallInfo callInfo);
+
+ /**
+ * Attempts to call the relevant party using the specified call's handle, be it a phone number,
+ * SIP address, or some other kind of user ID. Note that the set of handle types is
+ * dynamically extensible since call providers should be able to implement arbitrary
+ * handle-calling systems. See {@link #isCompatibleWith}. It is expected that the
+ * call service respond via {@link CallServiceAdapter#handleSuccessfulOutgoingCall(String)}
+ * if it can successfully make the call. Only used in the context of outgoing calls.
+ *
+ * @param callInfo The details of the relevant call.
+ */
+ public abstract void call(CallInfo callInfo);
+
+ /**
+ * Aborts the outgoing call attempt. Invoked in the unlikely event that Telecomm decides to
+ * abort an attempt to place a call. Only ever be invoked after {@link #call} invocations.
+ * After this is invoked, Telecomm does not expect any more updates about the call and will
+ * actively ignore any such update. This is different from {@link #disconnect} where Telecomm
+ * expects confirmation via CallServiceAdapter.markCallAsDisconnected.
+ *
+ * @param callId The identifier of the call to abort.
+ */
+ public abstract void abort(String callId);
+
+ /**
+ * Receives a new call ID to use with an incoming call. Invoked by Telecomm after it is notified
+ * that this call service has a pending incoming call, see
+ * {@link TelecommConstants#ACTION_INCOMING_CALL}. The call service must first give Telecomm
+ * additional information about the call through {@link CallServiceAdapter#notifyIncomingCall}.
+ * Following that, the call service can update the call at will using the specified call ID.
+ *
+ * If a {@link Bundle} was passed (via {@link TelecommConstants#EXTRA_INCOMING_CALL_EXTRAS}) in
+ * with the {@link TelecommConstants#ACTION_INCOMING_CALL} intent, <code>extras</code> will be
+ * populated with this {@link Bundle}. Otherwise, an empty Bundle will be returned.
+ *
+ * @param callId The ID of the call.
+ * @param extras The optional extras which were passed in with the intent, or an empty Bundle.
+ */
+ public abstract void setIncomingCallId(String callId, Bundle extras);
+
+ /**
+ * Answers a ringing call identified by callId. Telecomm invokes this method as a result of the
+ * user hitting the "answer" button in the incoming call screen.
+ *
+ * @param callId The ID of the call.
+ */
+ public abstract void answer(String callId);
+
+ /**
+ * Rejects a ringing call identified by callId. Telecomm invokes this method as a result of the
+ * user hitting the "reject" button in the incoming call screen.
+ *
+ * @param callId The ID of the call.
+ */
+ public abstract void reject(String callId);
+
+ /**
+ * Disconnects the specified call.
+ *
+ * @param callId The ID of the call to disconnect.
+ */
+ public abstract void disconnect(String callId);
+
+ /**
+ * Puts the specified call on hold.
+ *
+ * @param callId The ID of the call to put on hold.
+ */
+ public abstract void hold(String callId);
+
+ /**
+ * Removes the specified call from hold.
+ *
+ * @param callId The ID of the call to unhold.
+ */
+ public abstract void unhold(String callId);
+
+ /**
+ * Plays a dual-tone multi-frequency signaling (DTMF) tone in a call.
+ *
+ * @param callId The unique ID of the call in which the tone will be played.
+ * @param digit A character representing the DTMF digit for which to play the tone. This
+ * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
+ */
+ public abstract void playDtmfTone(String callId, char digit);
+
+ /**
+ * Stops any dual-tone multi-frequency sinaling (DTMF) tone currently playing.
+ *
+ * DTMF tones are played by calling {@link #playDtmfTone(String,char)}. If no DTMF tone is
+ * currently playing, this method will do nothing.
+ *
+ * @param callId The unique ID of the call in which any currently playing tone will be stopped.
+ */
+ public abstract void stopDtmfTone(String callId);
+
+ /**
+ * Called when the audio state changes.
+ *
+ * @param activeCallId The identifier of the call that was active during the state change.
+ * @param audioState The new {@link CallAudioState}.
+ */
+ public abstract void onAudioStateChanged(String activeCallId, CallAudioState audioState);
+}
diff --git a/telecomm/java/android/telecomm/CallServiceAdapter.java b/telecomm/java/android/telecomm/CallServiceAdapter.java
new file mode 100644
index 0000000..d5bb989
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceAdapter.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.os.RemoteException;
+
+import com.android.internal.telecomm.ICallServiceAdapter;
+
+/**
+ * Provides methods for ICallService implementations to interact with the system phone app.
+ * TODO(santoscordon): Need final public-facing comments in this file.
+ */
+public final class CallServiceAdapter {
+ private final ICallServiceAdapter mAdapter;
+
+ /**
+ * {@hide}
+ */
+ public CallServiceAdapter(ICallServiceAdapter adapter) {
+ mAdapter = adapter;
+ }
+
+ /**
+ * Receives confirmation of a call service's ability to place a call. This method is used in
+ * response to {@link CallService#isCompatibleWith}.
+ *
+ * @param callId The identifier of the call for which compatibility is being received. This ID
+ * should correspond to the ID given as part of the call information in
+ * {@link CallService#isCompatibleWith}.
+ * @param isCompatible True if the call service can place the call.
+ */
+ public void setIsCompatibleWith(String callId, boolean isCompatible) {
+ try {
+ mAdapter.setIsCompatibleWith(callId, isCompatible);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Provides Telecomm with the details of an incoming call. An invocation of this method must
+ * follow {@link CallService#setIncomingCallId} and use the call ID specified therein. Upon
+ * the invocation of this method, Telecomm will bring up the incoming-call interface where the
+ * user can elect to answer or reject a call.
+ *
+ * @param callInfo The details of the relevant call.
+ */
+ public void notifyIncomingCall(CallInfo callInfo) {
+ try {
+ mAdapter.notifyIncomingCall(callInfo);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Tells Telecomm that an attempt to place the specified outgoing call succeeded.
+ * TODO(santoscordon): Consider adding a CallState parameter in case this outgoing call is
+ * somehow no longer in the DIALING state.
+ *
+ * @param callId The ID of the outgoing call.
+ */
+ public void handleSuccessfulOutgoingCall(String callId) {
+ try {
+ mAdapter.handleSuccessfulOutgoingCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Tells Telecomm that an attempt to place the specified outgoing call failed.
+ *
+ * @param callId The ID of the outgoing call.
+ * @param errorMessage The error associated with the failed call attempt.
+ */
+ public void handleFailedOutgoingCall(String callId, String errorMessage) {
+ try {
+ mAdapter.handleFailedOutgoingCall(callId, errorMessage);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Sets a call's state to active (e.g., an ongoing call where two parties can actively
+ * communicate).
+ *
+ * @param callId The unique ID of the call whose state is changing to active.
+ */
+ public void setActive(String callId) {
+ try {
+ mAdapter.setActive(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Sets a call's state to ringing (e.g., an inbound ringing call).
+ *
+ * @param callId The unique ID of the call whose state is changing to ringing.
+ */
+ public void setRinging(String callId) {
+ try {
+ mAdapter.setRinging(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Sets a call's state to dialing (e.g., dialing an outbound call).
+ *
+ * @param callId The unique ID of the call whose state is changing to dialing.
+ */
+ public void setDialing(String callId) {
+ try {
+ mAdapter.setDialing(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Sets a call's state to disconnected.
+ *
+ * @param callId The unique ID of the call whose state is changing to disconnected.
+ * @param disconnectCause The reason for the disconnection, any of
+ * {@link android.telephony.DisconnectCause}.
+ * @param disconnectMessage Optional call-service-provided message about the disconnect.
+ */
+ public void setDisconnected(String callId, int disconnectCause, String disconnectMessage) {
+ try {
+ mAdapter.setDisconnected(callId, disconnectCause, disconnectMessage);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Sets a call's state to be on hold.
+ *
+ * @param callId - The unique ID of the call whose state is changing to be on hold.
+ */
+ public void setOnHold(String callId) {
+ try {
+ mAdapter.setOnHold(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+
+}
diff --git a/telecomm/java/android/telecomm/CallServiceDescriptor.aidl b/telecomm/java/android/telecomm/CallServiceDescriptor.aidl
new file mode 100644
index 0000000..f517c73
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceDescriptor.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+parcelable CallServiceDescriptor;
diff --git a/telecomm/java/android/telecomm/CallServiceDescriptor.java b/telecomm/java/android/telecomm/CallServiceDescriptor.java
new file mode 100644
index 0000000..dec3791
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceDescriptor.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.util.Locale;
+import java.util.UUID;
+
+/**
+ * An immutable object containing information about a given {@link CallService}. Instances are
+ * created using the enclosed {@link Builder}.
+ */
+public final class CallServiceDescriptor implements Parcelable {
+ private static final String TAG = CallServiceDescriptor.class.getSimpleName();
+
+ /**
+ * A placeholder value indicating an invalid network type.
+ * @hide
+ */
+ private static final int FLAG_INVALID = 0;
+
+ /**
+ * Indicates that the device must be connected to a Wi-Fi network in order for the backing
+ * {@link CallService} to be used.
+ */
+ public static final int FLAG_WIFI = 0x01;
+
+ /**
+ * Indicates that the device must be connected to a cellular PSTN network in order for the
+ * backing {@link CallService} to be used.
+ */
+ public static final int FLAG_PSTN = 0x02;
+
+ /**
+ * Indicates that the device must be connected to a cellular data network in order for the
+ * backing {@link CallService} to be used.
+ */
+ public static final int FLAG_MOBILE = 0x04;
+
+ /**
+ * Represents all of the defined FLAG_ constants so validity can be easily checked.
+ * @hide
+ */
+ public static final int FLAG_ALL = FLAG_WIFI | FLAG_PSTN | FLAG_MOBILE;
+
+ /**
+ * A unique ID used to identify a given instance.
+ */
+ private final String mCallServiceId;
+
+ /**
+ * The {@link ComponentName} of the {@link CallService} implementation which this is describing.
+ */
+ private final ComponentName mComponentName;
+
+ /**
+ * The type of connection that the {@link CallService} requires; will be one of the FLAG_*
+ * constants defined in this class.
+ */
+ private final int mNetworkType;
+
+ private CallServiceDescriptor(
+ String callServiceId,
+ ComponentName componentName,
+ int networkType) {
+
+ mCallServiceId = callServiceId;
+ mComponentName = componentName;
+ mNetworkType = networkType;
+ }
+
+ /**
+ * @return The ID used to identify this {@link CallService}.
+ */
+ public String getCallServiceId() {
+ return mCallServiceId;
+ }
+
+ /**
+ * @return The {@link ComponentName} of the {@link CallService}.
+ */
+ public ComponentName getServiceComponent() {
+ return mComponentName;
+ }
+
+ /**
+ * @return The network type required by the {@link CallService} to place a call.
+ */
+ public int getNetworkType() {
+ return mNetworkType;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof CallServiceDescriptor)) {
+ return false;
+ }
+ CallServiceDescriptor descriptor = (CallServiceDescriptor) obj;
+ return mCallServiceId.equals(descriptor.mCallServiceId) &&
+ mComponentName.equals(descriptor.mComponentName) &&
+ mNetworkType == descriptor.mNetworkType;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(Locale.US, "[%s, component: %s]",
+ CallServiceDescriptor.class.getSimpleName(),
+ mComponentName == null ? "null" : mComponentName.flattenToShortString());
+ }
+
+ /**
+ * @param context {@link Context} to use for the construction of the {@link Builder}.
+ * @return A new {@link Builder} instance.
+ */
+ public static Builder newBuilder(Context context) {
+ return new Builder(context);
+ }
+
+ /**
+ * Creates {@link CallServiceDescriptor} instances. Builders should be created with the
+ * {@link CallServiceDescriptor#newBuilder(Context)} method.
+ */
+ public static class Builder {
+ /** The {@link Context} to use to verify {@link ComponentName} ownership. */
+ private Context mContext;
+
+ /** The {@link ComponentName} pointing to the backing {@link CallService}. */
+ private ComponentName mComponentName;
+
+ /** The required network type that the {@link CallService} needs. */
+ private int mNetworkType = FLAG_INVALID;
+
+ private Builder(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Set which {@link CallService} this {@link CallServiceDescriptor} is describing.
+ *
+ * @param callServiceClass The {@link CallService} class
+ * @return This {@link Builder} for method chaining.
+ */
+ public Builder setCallService(Class<? extends CallService> callServiceClass) {
+ mComponentName = new ComponentName(mContext, callServiceClass);
+ return this;
+ }
+
+ /**
+ * Which network type the backing {@link CallService} requires. This must be one of the
+ * {@link CallServiceDescriptor}.TYPE_* fields.
+ *
+ * @param networkType Which network type the backing {@link CallService} requires.
+ * @return This {@link Builder} for method chaining.
+ */
+ public Builder setNetworkType(int networkType) {
+ mNetworkType = networkType;
+ return this;
+ }
+
+ /**
+ * @return A constructed {@link CallServiceDescriptor} object.
+ */
+ public CallServiceDescriptor build() {
+ // STOPSHIP: Verify validity of ComponentName (permissions, intents, etc)
+
+ // Make sure that they passed in a valid network flag combination
+ if (mNetworkType == FLAG_INVALID || ((mNetworkType & FLAG_ALL) == 0)) {
+
+ Log.wtf(TAG, "Invalid network type for " + mComponentName);
+ // Revert them back to TYPE_INVALID so it won't be considered.
+ mNetworkType = FLAG_INVALID;
+ }
+
+ // TODO: Should we use a sha1 of the ComponentName? Would prevent duplicates.
+ return new CallServiceDescriptor(
+ UUID.randomUUID().toString(), mComponentName, mNetworkType);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mCallServiceId);
+ dest.writeParcelable(mComponentName, 0);
+ dest.writeInt(mNetworkType);
+ }
+
+ public static final Creator<CallServiceDescriptor> CREATOR =
+ new Creator<CallServiceDescriptor>() {
+ @Override
+ public CallServiceDescriptor createFromParcel(Parcel source) {
+ String id = source.readString();
+ ComponentName componentName = source.readParcelable(
+ CallServiceDescriptor.class.getClassLoader());
+ int networkType = source.readInt();
+
+ return new CallServiceDescriptor(id, componentName, networkType);
+ }
+
+ @Override
+ public CallServiceDescriptor[] newArray(int size) {
+ return new CallServiceDescriptor[size];
+ }
+ };
+}
diff --git a/telecomm/java/android/telecomm/CallServiceLookupResponse.java b/telecomm/java/android/telecomm/CallServiceLookupResponse.java
new file mode 100644
index 0000000..dd35a24
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceLookupResponse.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.os.RemoteException;
+
+import com.android.internal.telecomm.ICallServiceLookupResponse;
+
+import java.util.List;
+
+/**
+ * Used by {@link CallServiceProvider} to return a list of {@link CallServiceDescriptor}s.
+ */
+public final class CallServiceLookupResponse {
+ private final ICallServiceLookupResponse mResponse;
+
+ /**
+ * {@hide}
+ */
+ public CallServiceLookupResponse(ICallServiceLookupResponse response) {
+ mResponse = response;
+ }
+
+ /**
+ * Passes the sorted list of preferred {@link CallServiceDescriptor}s back to Telecomm. Used
+ * in the context of attempting to place a pending outgoing call.
+ *
+ * @param callServiceDescriptors The set of call-service descriptors from
+ * {@link CallServiceProvider}.
+ */
+ public void setCallServiceDescriptors(List<CallServiceDescriptor> callServiceDescriptors) {
+ try {
+ mResponse.setCallServiceDescriptors(callServiceDescriptors);
+ } catch (RemoteException e) {
+ }
+ }
+}
diff --git a/telecomm/java/android/telecomm/CallServiceProvider.java b/telecomm/java/android/telecomm/CallServiceProvider.java
new file mode 100644
index 0000000..c50334a
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceProvider.java
@@ -0,0 +1,109 @@
+/*
+ * 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 android.telecomm;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+
+import com.android.internal.telecomm.ICallServiceLookupResponse;
+import com.android.internal.telecomm.ICallServiceProvider;
+
+/**
+ * Base implementation of a call service provider which extends {@link Service}. This class
+ * should be extended by an app that wants to supply phone calls to be handled and managed by
+ * the device's in-call interface. All method-calls from the framework to the call service provider
+ * are passed through to the main thread for before executing the overriden methods of
+ * CallServiceProvider.
+ *
+ * TODO(santoscordon): Improve paragraph above once the final design is in place. Needs more
+ * about how this can be used.
+ */
+public abstract class CallServiceProvider extends Service {
+
+ /**
+ * Default Handler used to consolidate binder method calls onto a single thread.
+ */
+ private final class CallServiceProviderMessageHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_LOOKUP_CALL_SERVICES:
+ CallServiceLookupResponse response =
+ new CallServiceLookupResponse((ICallServiceLookupResponse) msg.obj);
+ lookupCallServices(response);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Default ICallServiceProvider implementation provided to CallsManager via {@link #onBind}.
+ */
+ private final class CallServiceProviderWrapper extends ICallServiceProvider.Stub {
+ /** {@inheritDoc} */
+ @Override
+ public void lookupCallServices(ICallServiceLookupResponse callServiceLookupResponse) {
+ Message message = mMessageHandler.obtainMessage(
+ MSG_LOOKUP_CALL_SERVICES, callServiceLookupResponse);
+ message.sendToTarget();
+ }
+ }
+
+ // Only used internally by this class.
+ // Binder method calls on this service can occur on multiple threads. These messages are used
+ // in conjunction with {@link #mMessageHandler} to ensure that all callbacks are handled on a
+ // single thread. Keeping it on a single thread allows CallService implementations to avoid
+ // needing multi-threaded code in their own callback routines.
+ private static final int MSG_LOOKUP_CALL_SERVICES = 1;
+
+ /**
+ * Message handler for consolidating binder callbacks onto a single thread.
+ * See {@link CallServiceProviderMessageHandler}.
+ */
+ private final CallServiceProviderMessageHandler mMessageHandler;
+
+ /**
+ * Default binder implementation of {@link ICallServiceProvider} interface.
+ */
+ private final CallServiceProviderWrapper mBinder;
+
+ /**
+ * Protected constructor called only by subclasses creates the binder interface and
+ * single-threaded message handler.
+ */
+ protected CallServiceProvider() {
+ mMessageHandler = new CallServiceProviderMessageHandler();
+ mBinder = new CallServiceProviderWrapper();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ /**
+ * Initiates the process to retrieve the list of {@link CallServiceDescriptor}s implemented by
+ * this provider.
+ *
+ * @param response The response object through which the list of call services is sent.
+ */
+ public abstract void lookupCallServices(CallServiceLookupResponse response);
+}
diff --git a/telecomm/java/android/telecomm/CallServiceSelector.java b/telecomm/java/android/telecomm/CallServiceSelector.java
new file mode 100644
index 0000000..c9c6ff6
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceSelector.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.app.Service;
+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 com.android.internal.os.SomeArgs;
+import com.android.internal.telecomm.ICallServiceSelector;
+import com.android.internal.telecomm.ICallServiceSelectorAdapter;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Allows for the organization of {@link CallService}s for outbound calls. Given a call and list of
+ * {@link CallService} IDs, order the list in terms of priority and return it using
+ * {@link #select(CallInfo, List)}.
+ */
+public abstract class CallServiceSelector extends Service {
+ private static final int MSG_SET_CALL_SERVICE_SELECTOR_ADAPTER = 0;
+ private static final int MSG_SELECT = 1;
+
+ private final HashMap<String, CallInfo> mCalls = new HashMap<String, CallInfo>();
+
+ /** Handler to move client-bound method calls to the main thread. */
+ private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SET_CALL_SERVICE_SELECTOR_ADAPTER:
+ mAdapter = new CallServiceSelectorAdapter(
+ (ICallServiceSelectorAdapter) msg.obj);
+ onAdapterAttached(mAdapter);
+ break;
+ case MSG_SELECT:
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ select((CallInfo) args.arg1, (List<CallServiceDescriptor>) args.arg2);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ }
+ };
+
+ /** Manages the binder calls so that the implementor does not need to deal with it. */
+ private final class CallServiceSelectorBinder extends ICallServiceSelector.Stub {
+ @Override
+ public void setCallServiceSelectorAdapter(ICallServiceSelectorAdapter adapter) {
+ mHandler.obtainMessage(MSG_SET_CALL_SERVICE_SELECTOR_ADAPTER, adapter)
+ .sendToTarget();
+ }
+
+ @Override
+ public void select(CallInfo callInfo, List<CallServiceDescriptor> descriptors) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callInfo;
+ args.arg2 = descriptors;
+ mHandler.obtainMessage(MSG_SELECT, args).sendToTarget();
+ }
+
+ @Override
+ public void onCallUpdated(CallInfo callInfo) {
+ mCalls.put(callInfo.getId(), callInfo);
+ }
+
+ @Override
+ public void onCallRemoved(String callId) {
+ mCalls.remove(callId);
+ }
+ }
+
+ private final CallServiceSelectorBinder mBinder;
+
+ private CallServiceSelectorAdapter mAdapter = null;
+
+ protected CallServiceSelector() {
+ mBinder = new CallServiceSelectorBinder();
+ }
+
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ /**
+ * Returns a list of all calls managed by this selector.
+ */
+ protected final Collection<CallInfo> getCalls() {
+ return Collections.unmodifiableCollection(mCalls.values());
+ }
+
+ /**
+ * @return The attached {@link CallServiceSelectorAdapter} if attached, or null otherwise.
+ */
+ protected final CallServiceSelectorAdapter getAdapter() {
+ return mAdapter;
+ }
+
+ /**
+ * Cancel the outgoing call. Any subsequent calls to {@link #select(CallInfo, List)} will be
+ * ignored.
+ *
+ * @param callInfo The call to canceled.
+ */
+ protected final void cancelOutgoingCall(CallInfo callInfo) {
+ getAdapter().cancelOutgoingCall(callInfo.getId());
+ }
+
+ /**
+ * Lifecycle callback which is called when this {@link CallServiceSelector} has been attached
+ * to a {@link CallServiceSelectorAdapter}, indicating {@link #getAdapter()} is now safe to use.
+ *
+ * @param adapter The adapter now attached to this call service selector.
+ */
+ protected void onAdapterAttached(CallServiceSelectorAdapter adapter) {
+ }
+
+ /**
+ * Given a list of {@link CallServiceDescriptor}s, order them into a prioritized list and return
+ * them through
+ * {@link CallServiceSelectorAdapter#setSelectedCallServices(String,List)}.
+ *
+ * @param callInfo The call being placed using the {@link CallService}s.
+ * @param descriptors The descriptors of the available {@link CallService}s with which to place
+ * the call.
+ */
+ protected abstract void select(CallInfo callInfo, List<CallServiceDescriptor> descriptors);
+}
diff --git a/telecomm/java/android/telecomm/CallServiceSelectorAdapter.java b/telecomm/java/android/telecomm/CallServiceSelectorAdapter.java
new file mode 100644
index 0000000..4d2e8aa
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceSelectorAdapter.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.telecomm.CallServiceDescriptor;
+
+import com.android.internal.telecomm.ICallServiceSelectorAdapter;
+
+import java.util.List;
+
+/**
+ * Provides methods for ICallServiceSelector implementations to interact with Telecomm.
+ */
+public final class CallServiceSelectorAdapter {
+ private final ICallServiceSelectorAdapter mAdapter;
+
+ /**
+ * {@hide}
+ */
+ public CallServiceSelectorAdapter(ICallServiceSelectorAdapter adapter) {
+ mAdapter = adapter;
+ }
+
+ /**
+ * Records the sorted set of call services that are preferred by the corresponding
+ * call-service selector.
+ *
+ * @param callId The ID of the call to complete.
+ * @param selectedCallServiceDescriptors The prioritized list of preferred call-service
+ * descriptors to use for completing the call.
+ */
+ public void setSelectedCallServices(
+ String callId,
+ List<CallServiceDescriptor> selectedCallServiceDescriptors) {
+ try {
+ mAdapter.setSelectedCallServices(callId, selectedCallServiceDescriptors);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Cancels the specified outgoing call.
+ *
+ * @param callId The ID of the call to cancel.
+ */
+ public void cancelOutgoingCall(String callId) {
+ try {
+ mAdapter.cancelOutgoingCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Associates handoff information with an ongoing call. Calls can switch from one call service
+ * to another. Setting handle to a non-null value marks the call as switchable.
+ *
+ * @param callId The ID of the call to set handoff information for.
+ * @param handle The handle used to place the call when switching.
+ * @param extras Optional extra that's attached to the call.
+ */
+ public void setHandoffInfo(String callId, Uri handle, Bundle extras) {
+ try {
+ mAdapter.setHandoffInfo(callId, handle, extras);
+ } catch (RemoteException e) {
+ }
+ }
+}
diff --git a/telecomm/java/android/telecomm/CallState.java b/telecomm/java/android/telecomm/CallState.java
new file mode 100644
index 0000000..152c2023
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallState.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+/**
+ * Defines call-state constants of the different states in which a call can exist. Although states
+ * have the notion of normal transitions, due to the volatile nature of telephony systems, code
+ * that uses these states should be resilient to unexpected state changes outside of what is
+ * considered traditional.
+ */
+public enum CallState {
+ /**
+ * Indicates that a call is new and not connected. This is used as the default state internally
+ * within Telecomm and should not be used between Telecomm and call services. Call services are
+ * not expected to ever interact with NEW calls, but {@link InCallService}s will see calls in
+ * this state.
+ */
+ NEW,
+
+ /**
+ * Indicates that a call is outgoing and in the dialing state. A call transitions to this state
+ * once an outgoing call has begun (e.g., user presses the dial button in Dialer). Calls in this
+ * state usually transition to {@link #ACTIVE} if the call was answered or {@link #DISCONNECTED}
+ * if the call was disconnected somehow (e.g., failure or cancellation of the call by the user).
+ */
+ DIALING,
+
+ /**
+ * Indicates that a call is incoming and the user still has the option of answering, rejecting,
+ * or doing nothing with the call. This state is usually associated with some type of audible
+ * ringtone. Normal transitions are to {@link #ACTIVE} if answered or {@link #DISCONNECTED}
+ * otherwise.
+ */
+ RINGING,
+
+ /**
+ * Indicates that the call is active but in a "post-dial" state where Telecomm is now sending
+ * some dual-tone multi-frequency signaling (DTMF) tones appended to the dialed number. Normal
+ * transitions are to {@link #POST_DIAL_WAIT} when the post-dial string requires user
+ * confirmation to proceed, {@link #ACTIVE} when the post-dial tones are completed, or
+ * {@link #DISCONNECTED}.
+ */
+ POST_DIAL,
+
+ /**
+ * Indicates that the call was in the {@link #POST_DIAL} state but is now waiting for user
+ * confirmation before the remaining digits can be sent. Normal transitions are to
+ * {@link #POST_DIAL} when the user asks Telecomm to proceed with the post-dial sequence.
+ */
+ POST_DIAL_WAIT,
+
+ /**
+ * Indicates that a call is currently connected to another party and a communication channel is
+ * open between them. The normal transition to this state is by the user answering a
+ * {@link #DIALING} call or a {@link #RINGING} call being answered by the other party.
+ */
+ ACTIVE,
+
+ /**
+ * Indicates that the call is currently on hold. In this state, the call is not terminated
+ * but no communication is allowed until the call is no longer on hold. The typical transition
+ * to this state is by the user putting an {@link #ACTIVE} call on hold by explicitly performing
+ * an action, such as clicking the hold button.
+ */
+ ON_HOLD,
+
+ /**
+ * Indicates that a call is currently disconnected. All states can transition to this state
+ * by the call service giving notice that the connection has been severed. When the user
+ * explicitly ends a call, it will not transition to this state until the call service confirms
+ * the disconnection or communication was lost to the call service currently responsible for
+ * this call (e.g., call service crashes).
+ */
+ DISCONNECTED,
+
+ /**
+ * Indicates that the call was attempted (mostly in the context of outgoing, at least at the
+ * time of writing) but cancelled before it was successfully connected.
+ * @hide
+ */
+ ABORTED;
+}
diff --git a/telecomm/java/android/telecomm/GatewayInfo.aidl b/telecomm/java/android/telecomm/GatewayInfo.aidl
new file mode 100644
index 0000000..d59e9b4
--- /dev/null
+++ b/telecomm/java/android/telecomm/GatewayInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+parcelable GatewayInfo;
diff --git a/telecomm/java/android/telecomm/GatewayInfo.java b/telecomm/java/android/telecomm/GatewayInfo.java
new file mode 100644
index 0000000..b95e6b6
--- /dev/null
+++ b/telecomm/java/android/telecomm/GatewayInfo.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * When calls are made, they may contain gateway information for services which route phone calls
+ * through their own service/numbers. The data consists of a number to call and the package name of
+ * the service. This data is used in two ways:
+ * <ol>
+ * <li> Call the appropriate routing number
+ * <li> Display information about how the call is being routed to the user
+ * </ol>
+ */
+public class GatewayInfo implements Parcelable {
+
+ private final String mGatewayProviderPackageName;
+ private final Uri mGatewayHandle;
+ private final Uri mOriginalHandle;
+
+ /** @hide */
+ public GatewayInfo(String packageName, Uri gatewayUri, Uri originalHandle) {
+ mGatewayProviderPackageName = packageName;
+ mGatewayHandle = gatewayUri;
+ mOriginalHandle = originalHandle;
+ }
+
+ /**
+ * Package name of the gateway provider service. used to place the call with.
+ */
+ public String getGatewayProviderPackageName() {
+ return mGatewayProviderPackageName;
+ }
+
+ /**
+ * Gateway provider handle to use when actually placing the call.
+ */
+ public Uri getGatewayHandle() {
+ return mGatewayHandle;
+ }
+
+ /**
+ * The actual call handle that the user is trying to connect to via the gateway.
+ */
+ public Uri getOriginalHandle() {
+ return mOriginalHandle;
+ }
+
+ public boolean isEmpty() {
+ return TextUtils.isEmpty(mGatewayProviderPackageName) || mGatewayHandle == null;
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Parcelable.Creator<GatewayInfo> CREATOR =
+ new Parcelable.Creator<GatewayInfo> () {
+
+ @Override
+ public GatewayInfo createFromParcel(Parcel source) {
+ String gatewayPackageName = source.readString();
+ Uri gatewayUri = Uri.CREATOR.createFromParcel(source);
+ Uri originalHandle = Uri.CREATOR.createFromParcel(source);
+ return new GatewayInfo(gatewayPackageName, gatewayUri, originalHandle);
+ }
+
+ @Override
+ public GatewayInfo[] newArray(int size) {
+ return new GatewayInfo[size];
+ }
+ };
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void writeToParcel(Parcel destination, int flags) {
+ destination.writeString(mGatewayProviderPackageName);
+ mGatewayHandle.writeToParcel(destination, 0);
+ mOriginalHandle.writeToParcel(destination, 0);
+ }
+}
diff --git a/telecomm/java/android/telecomm/InCallAdapter.java b/telecomm/java/android/telecomm/InCallAdapter.java
new file mode 100644
index 0000000..e41d3f6
--- /dev/null
+++ b/telecomm/java/android/telecomm/InCallAdapter.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.os.RemoteException;
+
+import com.android.internal.telecomm.IInCallAdapter;
+
+/**
+ * Receives commands from {@link InCallService} implementations which should be executed by
+ * Telecomm. When Telecomm binds to a {@link InCallService}, an instance of this class is given to
+ * the in-call service through which it can manipulate live (active, dialing, ringing) calls. When
+ * the in-call service is notified of new calls ({@link InCallService#addCall}), it can use the
+ * given call IDs to execute commands such as {@link #answerCall} for incoming calls or
+ * {@link #disconnectCall} for active calls the user would like to end. Some commands are only
+ * appropriate for calls in certain states; please consult each method for such limitations.
+ * TODO(santoscordon): Needs more/better comments once the API is finalized.
+ * TODO(santoscordon): Specify the adapter will stop functioning when there are no more calls.
+ */
+public final class InCallAdapter {
+ private final IInCallAdapter mAdapter;
+
+ /**
+ * {@hide}
+ */
+ public InCallAdapter(IInCallAdapter adapter) {
+ mAdapter = adapter;
+ }
+
+ /**
+ * Instructs Telecomm to answer the specified call.
+ *
+ * @param callId The identifier of the call to answer.
+ */
+ public void answerCall(String callId) {
+ try {
+ mAdapter.answerCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to reject the specified call.
+ * TODO(santoscordon): Add reject-with-text-message parameter when that feature
+ * is ported over.
+ *
+ * @param callId The identifier of the call to reject.
+ */
+ public void rejectCall(String callId) {
+ try {
+ mAdapter.rejectCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to disconnect the specified call.
+ *
+ * @param callId The identifier of the call to disconnect.
+ */
+ public void disconnectCall(String callId) {
+ try {
+ mAdapter.disconnectCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to put the specified call on hold.
+ *
+ * @param callId The identifier of the call to put on hold.
+ */
+ public void holdCall(String callId) {
+ try {
+ mAdapter.holdCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to release the specified call from hold.
+ *
+ * @param callId The identifier of the call to release from hold.
+ */
+ public void unholdCall(String callId) {
+ try {
+ mAdapter.unholdCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Mute the microphone.
+ *
+ * @param shouldMute True if the microphone should be muted.
+ */
+ public void mute(boolean shouldMute) {
+ try {
+ mAdapter.mute(shouldMute);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Sets the audio route (speaker, bluetooth, etc...). See {@link CallAudioState}.
+ *
+ * @param route The audio route to use.
+ */
+ public void setAudioRoute(int route) {
+ try {
+ mAdapter.setAudioRoute(route);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to play a dual-tone multi-frequency signaling (DTMF) tone in a call.
+ *
+ * Any other currently playing DTMF tone in the specified call is immediately stopped.
+ *
+ * @param callId The unique ID of the call in which the tone will be played.
+ * @param digit A character representing the DTMF digit for which to play the tone. This
+ * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
+ */
+ public void playDtmfTone(String callId, char digit) {
+ try {
+ mAdapter.playDtmfTone(callId, digit);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to stop any dual-tone multi-frequency signaling (DTMF) tone currently
+ * playing.
+ *
+ * DTMF tones are played by calling {@link #playDtmfTone(String,char)}. If no DTMF tone is
+ * currently playing, this method will do nothing.
+ *
+ * @param callId The unique ID of the call in which any currently playing tone will be stopped.
+ */
+ public void stopDtmfTone(String callId) {
+ try {
+ mAdapter.stopDtmfTone(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to continue playing a post-dial DTMF string.
+ *
+ * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
+ * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
+ * While these tones are playing, Telecomm will notify the {@link InCallService} that the call
+ * is in the {@link InCallService#setPostDial(String,String)} state.
+ *
+ * If the DTMF string contains a {@link TelecommConstants#DTMF_CHARACTER_PAUSE} symbol, Telecomm
+ * will temporarily pause playing the tones for a pre-defined period of time.
+ *
+ * If the DTMF string contains a {@link TelecommConstants#DTMF_CHARACTER_WAIT} symbol, Telecomm
+ * will pause playing the tones and notify the {@link InCallService} that the call is in the
+ * {@link InCallService#setPostDialWait(String,String)} state. When the user decides to continue
+ * the postdial sequence, the {@link InCallService} should invoke the
+ * {@link #postDialContinue(String)} method.
+ *
+ * @param callId The unique ID of the call for which postdial string playing should continue.
+ */
+ public void postDialContinue(String callId) {
+ try {
+ mAdapter.postDialContinue(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to handoff the call to another call service.
+ *
+ * @param callId The identifier of the call to handoff.
+ */
+ public void handoffCall(String callId) {
+ try {
+ mAdapter.handoffCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+}
diff --git a/telecomm/java/android/telecomm/InCallCall.aidl b/telecomm/java/android/telecomm/InCallCall.aidl
new file mode 100644
index 0000000..be2cdf8
--- /dev/null
+++ b/telecomm/java/android/telecomm/InCallCall.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+parcelable InCallCall;
diff --git a/telecomm/java/android/telecomm/InCallCall.java b/telecomm/java/android/telecomm/InCallCall.java
new file mode 100644
index 0000000..c3b2ae7
--- /dev/null
+++ b/telecomm/java/android/telecomm/InCallCall.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.DisconnectCause;
+
+import java.util.Date;
+import java.util.UUID;
+
+/**
+ * Information about a call that is used between InCallService and Telecomm.
+ */
+public final class InCallCall implements Parcelable {
+ private final String mId;
+ private final CallState mState;
+ private final int mDisconnectCause;
+ private final int mCapabilities;
+ private final long mConnectTimeMillis;
+ private final Uri mHandle;
+ private final GatewayInfo mGatewayInfo;
+ private final CallServiceDescriptor mCurrentCallServiceDescriptor;
+ private final CallServiceDescriptor mHandoffCallServiceDescriptor;
+
+ /** @hide */
+ public InCallCall(
+ String id,
+ CallState state,
+ int disconnectCause,
+ int capabilities,
+ long connectTimeMillis,
+ Uri handle,
+ GatewayInfo gatewayInfo,
+ CallServiceDescriptor descriptor,
+ CallServiceDescriptor handoffDescriptor) {
+ mId = id;
+ mState = state;
+ mDisconnectCause = disconnectCause;
+ mCapabilities = capabilities;
+ mConnectTimeMillis = connectTimeMillis;
+ mHandle = handle;
+ mGatewayInfo = gatewayInfo;
+ mCurrentCallServiceDescriptor = descriptor;
+ mHandoffCallServiceDescriptor = handoffDescriptor;
+ }
+
+ /** The unique ID of the call. */
+ public String getId() {
+ return mId;
+ }
+
+ /** The current state of the call. */
+ public CallState getState() {
+ return mState;
+ }
+
+ /**
+ * Reason for disconnection, values are defined in {@link DisconnectCause}. Valid when call
+ * state is {@link CallState#DISCONNECTED}.
+ */
+ public int getDisconnectCause() {
+ return mDisconnectCause;
+ }
+
+ // Bit mask of actions a call supports, values are defined in {@link CallCapabilities}.
+ public int getCapabilities() {
+ return mCapabilities;
+ }
+
+ /** The time that the call switched to the active state. */
+ public long getConnectTimeMillis() {
+ return mConnectTimeMillis;
+ }
+
+ /** The endpoint to which the call is connected. */
+ public Uri getHandle() {
+ return mHandle;
+ }
+
+ /** Gateway information for the call. */
+ public GatewayInfo getGatewayInfo() {
+ return mGatewayInfo;
+ }
+
+ /** The descriptor for the call service currently routing this call. */
+ public CallServiceDescriptor getCurrentCallServiceDescriptor() {
+ return mCurrentCallServiceDescriptor;
+ }
+
+ /**
+ * The descriptor for the call service that this call is being switched to, null if handoff is
+ * not in progress.
+ */
+ public CallServiceDescriptor getHandoffCallServiceDescriptor() {
+ return mHandoffCallServiceDescriptor;
+ }
+
+ /** Responsible for creating InCallCall objects for deserialized Parcels. */
+ public static final Parcelable.Creator<InCallCall> CREATOR =
+ new Parcelable.Creator<InCallCall> () {
+ @Override
+ public InCallCall createFromParcel(Parcel source) {
+ String id = source.readString();
+ CallState state = CallState.valueOf(source.readString());
+ int disconnectCause = source.readInt();
+ int capabilities = source.readInt();
+ long connectTimeMillis = source.readLong();
+ ClassLoader classLoader = InCallCall.class.getClassLoader();
+ Uri handle = source.readParcelable(classLoader);
+ GatewayInfo gatewayInfo = source.readParcelable(classLoader);
+ CallServiceDescriptor descriptor = source.readParcelable(classLoader);
+ CallServiceDescriptor handoffDescriptor = source.readParcelable(classLoader);
+ return new InCallCall(id, state, disconnectCause, capabilities, connectTimeMillis,
+ handle, gatewayInfo, descriptor, handoffDescriptor);
+ }
+
+ @Override
+ public InCallCall[] newArray(int size) {
+ return new InCallCall[size];
+ }
+ };
+
+ /** {@inheritDoc} */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Writes InCallCall object into a Parcel. */
+ @Override
+ public void writeToParcel(Parcel destination, int flags) {
+ destination.writeString(mId);
+ destination.writeString(mState.name());
+ destination.writeInt(mDisconnectCause);
+ destination.writeInt(mCapabilities);
+ destination.writeLong(mConnectTimeMillis);
+ destination.writeParcelable(mHandle, 0);
+ destination.writeParcelable(mGatewayInfo, 0);
+ destination.writeParcelable(mCurrentCallServiceDescriptor, 0);
+ destination.writeParcelable(mHandoffCallServiceDescriptor, 0);
+ }
+}
diff --git a/telecomm/java/android/telecomm/InCallService.java b/telecomm/java/android/telecomm/InCallService.java
new file mode 100644
index 0000000..63b2020
--- /dev/null
+++ b/telecomm/java/android/telecomm/InCallService.java
@@ -0,0 +1,209 @@
+/*
+ * 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 android.telecomm;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+
+import com.android.internal.os.SomeArgs;
+import com.android.internal.telecomm.IInCallAdapter;
+import com.android.internal.telecomm.IInCallService;
+
+/**
+ * This service is implemented by any app that wishes to provide the user-interface for managing
+ * phone calls. Telecomm binds to this service while there exists a live (active or incoming)
+ * call, and uses it to notify the in-call app of any live and and recently disconnected calls.
+ * TODO(santoscordon): Needs more/better description of lifecycle once the interface is better
+ * defined.
+ * TODO(santoscordon): What happens if two or more apps on a given device implement this interface?
+ */
+public abstract class InCallService extends Service {
+ private static final int MSG_SET_IN_CALL_ADAPTER = 1;
+ private static final int MSG_ADD_CALL = 2;
+ private static final int MSG_UPDATE_CALL = 3;
+ private static final int MSG_SET_POST_DIAL = 4;
+ private static final int MSG_SET_POST_DIAL_WAIT = 5;
+ private static final int MSG_ON_AUDIO_STATE_CHANGED = 6;
+
+ /** Default Handler used to consolidate binder method calls onto a single thread. */
+ private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SET_IN_CALL_ADAPTER:
+ mAdapter = new InCallAdapter((IInCallAdapter) msg.obj);
+ onAdapterAttached(mAdapter);
+ break;
+ case MSG_ADD_CALL:
+ addCall((InCallCall) msg.obj);
+ break;
+ case MSG_UPDATE_CALL:
+ updateCall((InCallCall) msg.obj);
+ break;
+ case MSG_SET_POST_DIAL: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ String callId = (String) args.arg1;
+ String remaining = (String) args.arg2;
+ setPostDial(callId, remaining);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_SET_POST_DIAL_WAIT: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ String callId = (String) args.arg1;
+ String remaining = (String) args.arg2;
+ setPostDialWait(callId, remaining);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_ON_AUDIO_STATE_CHANGED:
+ onAudioStateChanged((CallAudioState) msg.obj);
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
+ /** Manages the binder calls so that the implementor does not need to deal with it. */
+ private final class InCallServiceBinder extends IInCallService.Stub {
+ /** {@inheritDoc} */
+ @Override
+ public void setInCallAdapter(IInCallAdapter inCallAdapter) {
+ mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addCall(InCallCall call) {
+ mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateCall(InCallCall call) {
+ mHandler.obtainMessage(MSG_UPDATE_CALL, call).sendToTarget();
+ }
+
+ @Override
+ public void setPostDial(String callId, String remaining) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = remaining;
+ mHandler.obtainMessage(MSG_SET_POST_DIAL, args).sendToTarget();
+ }
+
+ @Override
+ public void setPostDialWait(String callId, String remaining) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = remaining;
+ mHandler.obtainMessage(MSG_SET_POST_DIAL_WAIT, args).sendToTarget();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onAudioStateChanged(CallAudioState audioState) {
+ mHandler.obtainMessage(MSG_ON_AUDIO_STATE_CHANGED, audioState).sendToTarget();
+ }
+ }
+
+ private final InCallServiceBinder mBinder;
+
+ private InCallAdapter mAdapter;
+
+ protected InCallService() {
+ mBinder = new InCallServiceBinder();
+ }
+
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ /**
+ * @return The attached {@link CallServiceSelectorAdapter} if attached, or null otherwise.
+ */
+ protected final InCallAdapter getAdapter() {
+ return mAdapter;
+ }
+
+ /**
+ * Lifecycle callback which is called when this {@link InCallService} has been attached
+ * to a {@link InCallAdapter}, indicating {@link #getAdapter()} is now safe to use.
+ *
+ * @param adapter The adapter now attached to this in-call service.
+ */
+ protected void onAdapterAttached(InCallAdapter adapter) {
+ }
+
+ /**
+ * Indicates to the in-call app that a new call has been created and an appropriate
+ * user-interface should be built and shown to notify the user.
+ *
+ * @param call Information about the new call.
+ */
+ protected abstract void addCall(InCallCall call);
+
+ /**
+ * Call when information about a call has changed.
+ *
+ * @param call Information about the new call.
+ */
+ protected abstract void updateCall(InCallCall call);
+
+ /**
+ * Indicates to the in-call app that the specified call is active but in a "post-dial" state
+ * where Telecomm is now sending some dual-tone multi-frequency signaling (DTMF) tones appended
+ * to the dialed number. Normal transitions are to {@link #setPostDialWait(String,String)} when
+ * the post-dial string requires user confirmation to proceed, and {@link CallState#ACTIVE} when
+ * the post-dial tones are completed.
+ *
+ * @param callId The identifier of the call changing state.
+ * @param remaining The remaining postdial string to be dialed.
+ */
+ protected abstract void setPostDial(String callId, String remaining);
+
+ /**
+ * Indicates to the in-call app that the specified call was in the
+ * {@link #setPostDial(String,String)} state but is now waiting for user confirmation before the
+ * remaining digits can be sent. Normal transitions are to {@link #setPostDial(String,String)}
+ * when the user asks Telecomm to proceed with the post-dial sequence and the in-call app
+ * informs Telecomm of this by invoking {@link InCallAdapter#postDialContinue(String)}.
+ *
+ * @param callId The identifier of the call changing state.
+ * @param remaining The remaining postdial string to be dialed.
+ */
+ protected abstract void setPostDialWait(String callId, String remaining);
+
+ /**
+ * Called when the audio state changes.
+ *
+ * @param audioState The new {@link CallAudioState}.
+ */
+ protected abstract void onAudioStateChanged(CallAudioState audioState);
+}
diff --git a/telecomm/java/android/telecomm/TelecommConstants.java b/telecomm/java/android/telecomm/TelecommConstants.java
new file mode 100644
index 0000000..8300c92
--- /dev/null
+++ b/telecomm/java/android/telecomm/TelecommConstants.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecomm;
+
+import android.os.Bundle;
+import android.telephony.TelephonyManager;
+
+/**
+ * Defines constants for use with the Telecomm system.
+ */
+public final class TelecommConstants {
+ /**
+ * <p>Activity action: Starts the UI for handing an incoming call. This intent starts the
+ * in-call UI by notifying the Telecomm system that an incoming call exists for a specific call
+ * service (see {@link android.telecomm.CallService}). Telecomm reads the Intent extras to find
+ * and bind to the appropriate {@link android.telecomm.CallService} which Telecomm will
+ * ultimately use to control and get information about the call.</p>
+ *
+ * <p>Input: get*Extra field {@link #EXTRA_CALL_SERVICE_DESCRIPTOR} contains the component name
+ * of the {@link android.telecomm.CallService} that Telecomm should bind to. Telecomm will then
+ * ask the call service for more information about the call prior to showing any UI.
+ *
+ * TODO(santoscordon): Needs permissions.
+ * TODO(santoscordon): Consider moving this into a simple method call on a system service.
+ */
+ public static final String ACTION_INCOMING_CALL = "android.intent.action.INCOMING_CALL";
+
+ /**
+ * The service action used to bind to {@link CallServiceProvider} implementations.
+ */
+ public static final String ACTION_CALL_SERVICE_PROVIDER = CallServiceProvider.class.getName();
+
+ /**
+ * The service action used to bind to {@link CallService} implementations.
+ */
+ public static final String ACTION_CALL_SERVICE = CallService.class.getName();
+
+ /**
+ * The service action used to bind to {@link CallServiceSelector} implementations.
+ */
+ public static final String ACTION_CALL_SERVICE_SELECTOR = CallServiceSelector.class.getName();
+
+ /**
+ * Extra for {@link #ACTION_INCOMING_CALL} containing the {@link CallServiceDescriptor} that
+ * describes the call service to use for the incoming call.
+ */
+ public static final String EXTRA_CALL_SERVICE_DESCRIPTOR =
+ "android.intent.extra.CALL_SERVICE_DESCRIPTOR";
+
+ /**
+ * Optional extra for {@link #ACTION_INCOMING_CALL} containing a {@link Bundle} which contains
+ * metadata about the call. This {@link Bundle} will be returned to the {@link CallService} as
+ * part of {@link CallService#setIncomingCallId(String,Bundle)}.
+ */
+ public static final String EXTRA_INCOMING_CALL_EXTRAS =
+ "android.intent.extra.INCOMING_CALL_EXTRAS";
+
+ /**
+ * Optional extra for {@link TelephonyManager#ACTION_PHONE_STATE_CHANGED} containing the
+ * disconnect code.
+ */
+ public static final String EXTRA_CALL_DISCONNECT_CAUSE =
+ "android.telecomm.extra.CALL_DISCONNECT_CAUSE";
+
+ /**
+ * Optional extra for {@link TelephonyManager#ACTION_PHONE_STATE_CHANGED} containing the
+ * disconnect message.
+ */
+ public static final String EXTRA_CALL_DISCONNECT_MESSAGE =
+ "android.telecomm.extra.CALL_DISCONNECT_MESSAGE";
+
+ /**
+ * The dual tone multi-frequency signaling character sent to indicate the dialing system should
+ * pause for a predefined period.
+ */
+ public static final char DTMF_CHARACTER_PAUSE = ',';
+
+ /**
+ * The dual-tone multi-frequency signaling character sent to indicate the dialing system should
+ * wait for user confirmation before proceeding.
+ */
+ public static final char DTMF_CHARACTER_WAIT = ';';
+}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallService.aidl b/telecomm/java/com/android/internal/telecomm/ICallService.aidl
new file mode 100644
index 0000000..cc0641c
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/ICallService.aidl
@@ -0,0 +1,58 @@
+/*
+ * 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.telecomm;
+
+import android.os.Bundle;
+import android.telecomm.CallAudioState;
+import android.telecomm.CallInfo;
+
+import com.android.internal.telecomm.ICallServiceAdapter;
+
+/**
+ * Internal remote interface for call services.
+ *
+ * @see android.telecomm.CallService
+ *
+ * @hide
+ */
+oneway interface ICallService {
+ void setCallServiceAdapter(in ICallServiceAdapter callServiceAdapter);
+
+ void isCompatibleWith(in CallInfo callInfo);
+
+ void call(in CallInfo callInfo);
+
+ void abort(String callId);
+
+ void setIncomingCallId(String callId, in Bundle extras);
+
+ void answer(String callId);
+
+ void reject(String callId);
+
+ void disconnect(String callId);
+
+ void hold(String callId);
+
+ void unhold(String callId);
+
+ void onAudioStateChanged(String activeCallId, in CallAudioState audioState);
+
+ void playDtmfTone(String callId, char digit);
+
+ void stopDtmfTone(String callId);
+}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl b/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl
new file mode 100644
index 0000000..dfdaa75
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl
@@ -0,0 +1,46 @@
+/*
+ * 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.telecomm;
+
+import android.telecomm.CallInfo;
+
+/**
+ * Internal remote callback interface for call services.
+ *
+ * @see android.telecomm.CallServiceAdapter
+ *
+ * {@hide}
+ */
+oneway interface ICallServiceAdapter {
+ void setIsCompatibleWith(String callId, boolean isCompatible);
+
+ void notifyIncomingCall(in CallInfo callInfo);
+
+ void handleSuccessfulOutgoingCall(String callId);
+
+ void handleFailedOutgoingCall(String callId, String errorMessage);
+
+ void setActive(String callId);
+
+ void setRinging(String callId);
+
+ void setDialing(String callId);
+
+ void setDisconnected(String callId, int disconnectCause, String disconnectMessage);
+
+ void setOnHold(String callId);
+}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallServiceLookupResponse.aidl b/telecomm/java/com/android/internal/telecomm/ICallServiceLookupResponse.aidl
new file mode 100644
index 0000000..10d73be
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/ICallServiceLookupResponse.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telecomm;
+
+import android.os.IBinder;
+import android.telecomm.CallServiceDescriptor;
+import java.util.List;
+
+/**
+ * Internal remote interface for call service lookup response.
+ *
+ * @see android.telecomm.CallServiceLookupResponse
+ *
+ * @hide
+ */
+oneway interface ICallServiceLookupResponse {
+ void setCallServiceDescriptors(in List<CallServiceDescriptor> callServiceDescriptors);
+}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallServiceProvider.aidl b/telecomm/java/com/android/internal/telecomm/ICallServiceProvider.aidl
new file mode 100644
index 0000000..96daeed
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/ICallServiceProvider.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.telecomm;
+
+import android.telecomm.CallServiceDescriptor;
+
+import com.android.internal.telecomm.ICallServiceLookupResponse;
+
+/**
+ * Internal remote interface for call service providers.
+ *
+ * @see android.telecomm.CallServiceProvider
+ *
+ * @hide
+ */
+oneway interface ICallServiceProvider {
+ void lookupCallServices(in ICallServiceLookupResponse response);
+}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallServiceSelector.aidl b/telecomm/java/com/android/internal/telecomm/ICallServiceSelector.aidl
new file mode 100644
index 0000000..9597dc1
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/ICallServiceSelector.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telecomm;
+
+import android.telecomm.CallInfo;
+import android.telecomm.CallServiceDescriptor;
+
+import com.android.internal.telecomm.ICallService;
+import com.android.internal.telecomm.ICallServiceSelectorAdapter;
+
+import java.util.List;
+
+/**
+ * Internal remote interface for call service selectors.
+ *
+ * @see android.telecomm.CallServiceSelector
+ *
+ * @hide
+ */
+oneway interface ICallServiceSelector {
+ void setCallServiceSelectorAdapter(in ICallServiceSelectorAdapter adapter);
+
+ void select(in CallInfo callInfo, in List<CallServiceDescriptor> callServiceDescriptors);
+
+ void onCallUpdated(in CallInfo callInfo);
+
+ void onCallRemoved(String callId);
+}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallServiceSelectorAdapter.aidl b/telecomm/java/com/android/internal/telecomm/ICallServiceSelectorAdapter.aidl
new file mode 100644
index 0000000..ad71e3c
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/ICallServiceSelectorAdapter.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telecomm;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.telecomm.CallInfo;
+import android.telecomm.CallServiceDescriptor;
+
+import java.util.List;
+
+/**
+ * Internal remote interface for call service selector adapter.
+ *
+ * @see android.telecomm.CallServiceSelectorAdapter
+ *
+ * @hide
+ */
+oneway interface ICallServiceSelectorAdapter {
+ void setSelectedCallServices(
+ String callId,
+ in List<CallServiceDescriptor> selectedCallServiceDescriptors);
+
+ void cancelOutgoingCall(String callId);
+
+ void setHandoffInfo(String callId, in Uri handle, in Bundle extras);
+}
diff --git a/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
new file mode 100644
index 0000000..512e898
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telecomm;
+
+import android.telecomm.CallAudioState;
+
+/**
+ * Internal remote callback interface for in-call services.
+ *
+ * @see android.telecomm.InCallAdapter
+ *
+ * {@hide}
+ */
+oneway interface IInCallAdapter {
+ void answerCall(String callId);
+
+ void rejectCall(String callId);
+
+ void disconnectCall(String callId);
+
+ void holdCall(String callId);
+
+ void unholdCall(String callId);
+
+ void mute(boolean shouldMute);
+
+ void setAudioRoute(int route);
+
+ void playDtmfTone(String callId, char digit);
+
+ void stopDtmfTone(String callId);
+
+ void postDialContinue(String callId);
+
+ void handoffCall(String callId);
+}
diff --git a/telecomm/java/com/android/internal/telecomm/IInCallService.aidl b/telecomm/java/com/android/internal/telecomm/IInCallService.aidl
new file mode 100644
index 0000000..ccf7e3f
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecomm/IInCallService.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telecomm;
+
+import android.telecomm.CallAudioState;
+import android.telecomm.InCallCall;
+
+import com.android.internal.telecomm.IInCallAdapter;
+
+/**
+ * Internal remote interface for in-call services.
+ *
+ * @see android.telecomm.InCallService
+ *
+ * {@hide}
+ */
+oneway interface IInCallService {
+ void setInCallAdapter(in IInCallAdapter inCallAdapter);
+
+ void addCall(in InCallCall call);
+
+ void updateCall(in InCallCall call);
+
+ void setPostDial(String callId, String remaining);
+
+ void setPostDialWait(String callId, String remaining);
+
+ void onAudioStateChanged(in CallAudioState audioState);
+}
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index 1c75658..8681344 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -17,10 +17,7 @@
package android.telephony;
/**
- * Contains disconnect call causes generated by the
- * framework and the RIL.
- *
- * @hide
+ * Contains disconnect call causes generated by the framework and the RIL.
*/
public class DisconnectCause {
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index c79e9bf..9da032a 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1492,6 +1492,10 @@
* @return the normalized number.
*/
public static String normalizeNumber(String phoneNumber) {
+ if (TextUtils.isEmpty(phoneNumber)) {
+ return "";
+ }
+
StringBuilder sb = new StringBuilder();
int len = phoneNumber.length();
for (int i = 0; i < len; i++) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index df972d5..7002744 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -19,6 +19,7 @@
import android.annotation.PrivateApi;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.content.ComponentName;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
@@ -67,6 +68,20 @@
private static ITelephonyRegistry sRegistry;
+ /**
+ * The allowed states of Wi-Fi calling.
+ *
+ * @hide
+ */
+ public interface WifiCallingChoices {
+ /** Always use Wi-Fi calling */
+ static final int ALWAYS_USE = 0;
+ /** Ask the user whether to use Wi-Fi on every call */
+ static final int ASK_EVERY_TIME = 1;
+ /** Never use Wi-Fi calling */
+ static final int NEVER_USE = 2;
+ }
+
private final HashMap<CallStateListener,Listener> mListeners
= new HashMap<CallStateListener,Listener>();
private final Context mContext;
diff --git a/telephony/java/com/android/internal/telephony/CallInfo.aidl b/telephony/java/com/android/internal/telephony/CallInfo.aidl
new file mode 100644
index 0000000..9140388
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/CallInfo.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 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.telephony;
+
+parcelable CallInfo;
diff --git a/telephony/java/com/android/internal/telephony/CallInfo.java b/telephony/java/com/android/internal/telephony/CallInfo.java
new file mode 100644
index 0000000..6bfc9d7
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/CallInfo.java
@@ -0,0 +1,77 @@
+/*
+** Copyright 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.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A parcelable holder class of Call information data.
+ */
+public class CallInfo implements Parcelable {
+
+ /**
+ * Endpoint to which the call is connected.
+ * This could be the dialed value for outgoing calls or the caller id of incoming calls.
+ */
+ private String handle;
+
+ public CallInfo(String handle) {
+ this.handle = handle;
+ }
+
+ public String getHandle() {
+ return handle;
+ }
+
+ //
+ // Parcelling related code below here.
+ //
+
+ /**
+ * Responsible for creating CallInfo objects for deserialized Parcels.
+ */
+ public static final Parcelable.Creator<CallInfo> CREATOR
+ = new Parcelable.Creator<CallInfo> () {
+
+ @Override
+ public CallInfo createFromParcel(Parcel source) {
+ return new CallInfo(source.readString());
+ }
+
+ @Override
+ public CallInfo[] newArray(int size) {
+ return new CallInfo[size];
+ }
+ };
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Writes CallInfo object into a serializeable Parcel.
+ */
+ @Override
+ public void writeToParcel(Parcel destination, int flags) {
+ destination.writeString(handle);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/ICallService.aidl b/telephony/java/com/android/internal/telephony/ICallService.aidl
new file mode 100644
index 0000000..cb9b2e8
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ICallService.aidl
@@ -0,0 +1,61 @@
+/*
+ * 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.telephony;
+
+import com.android.internal.telephony.ICallServiceAdapter;
+
+/**
+ * Service interface for services which would like to provide calls to be
+ * managed by the system in-call UI.
+ *
+ * This interface provides methods that the android framework can use to deliver commands
+ * for calls provided by this call service including making new calls and disconnecting
+ * existing ones. A binding to ICallService implementations exists for two conditions:
+ * 1) There exists one or more live calls for that call service,
+ * 2) Prior to an outbound call to test if this call service is compatible with the outgoing call.
+ */
+oneway interface ICallService {
+
+ /**
+ * Determines if the CallService can make calls to the handle.
+ * TODO(santoscordon): Move this method into its own service interface long term.
+ * TODO(santoscordon): Add response callback parameter.
+ */
+ void isCompatibleWith(String handle);
+
+ /**
+ * Attempts to call the relevant party using the specified handle, be it a phone number,
+ * SIP address, or some other kind of user ID. Note that the set of handle types is
+ * dynamically extensible since call providers should be able to implement arbitrary
+ * handle-calling systems. See {@link #isCompatibleWith}.
+ * TODO(santoscordon): Should this have a response attached to it to ensure that the call
+ * service actually plans to make the call?
+ */
+ void call(String handle);
+
+ /**
+ * Disconnects the call identified by callId.
+ */
+ void disconnect(String callId);
+
+ /**
+ * Sets an implementation of ICallServiceAdapter which the call service can use to add new calls
+ * and communicate state changes of existing calls. This is the first method that is called
+ * after a the framework binds to the call service.
+ */
+ void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter);
+}
diff --git a/telephony/java/com/android/internal/telephony/ICallServiceAdapter.aidl b/telephony/java/com/android/internal/telephony/ICallServiceAdapter.aidl
new file mode 100644
index 0000000..bc900f0
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ICallServiceAdapter.aidl
@@ -0,0 +1,61 @@
+/*
+ * 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.telephony;
+
+import com.android.internal.telephony.CallInfo;
+
+/**
+ * Provides methods for ICallService implementations to interact with the system phone app.
+ */
+oneway interface ICallServiceAdapter {
+
+ /**
+ * Retrieves a new unique call id for use with newOutgoingCall and newIncomingCall.
+ */
+ void getNextCallId(/* TODO(santoscordon): Needs response object */);
+
+ /**
+ * Tells CallsManager of a new incoming call.
+ */
+ void newIncomingCall(String callId, in CallInfo info);
+
+ /**
+ * Tells CallsManager of a new outgoing call.
+ */
+ void newOutgoingCall(String callId, in CallInfo info);
+
+ /**
+ * Sets a call's state to active (e.g., an ongoing call where two parties can actively
+ * communicate).
+ */
+ void setActive(String callId);
+
+ /**
+ * Sets a call's state to ringing (e.g., an inbound ringing call).
+ */
+ void setRinging(String callId);
+
+ /**
+ * Sets a call's state to dialing (e.g., dialing an outbound call).
+ */
+ void setDialing(String callId);
+
+ /**
+ * Sets a call's state to disconnected.
+ */
+ void setDisconnected(String callId);
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index fa74494..72398ad 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -16,6 +16,7 @@
package com.android.internal.telephony;
+import android.content.ComponentName;
import android.os.Bundle;
import android.telephony.CellInfo;
import android.telephony.NeighboringCellInfo;
@@ -24,6 +25,8 @@
import java.util.List;
+import java.util.List;
+
/**
* Interface used to interact with the phone. Mostly this is used by the
* TelephonyManager class. A few places are still using this directly.
@@ -407,7 +410,7 @@
*/
boolean nvResetConfig(int resetType);
- /**
+ /*
* Get the preferred network type.
* Used for device configuration by some CDMA operators.
*
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 8ea9b0d..b104c11 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -18,7 +18,7 @@
import android.content.Intent;
import android.net.LinkProperties;
-import android.net.LinkCapabilities;
+import android.net.NetworkCapabilities;
import android.os.Bundle;
import android.telephony.CellInfo;
import android.telephony.DataConnectionRealTimeInfo;
@@ -37,7 +37,7 @@
void notifyDataActivity(int state);
void notifyDataConnection(int state, boolean isDataConnectivityPossible,
String reason, String apn, String apnType, in LinkProperties linkProperties,
- in LinkCapabilities linkCapabilities, int networkType, boolean roaming);
+ in NetworkCapabilities networkCapabilities, int networkType, boolean roaming);
void notifyDataConnectionFailed(String reason, String apnType);
void notifyCellLocation(in Bundle cellLocation);
void notifyOtaspChanged(in int otaspMode);
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl
new file mode 100644
index 0000000..bcf2d81
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl
@@ -0,0 +1,46 @@
+/*
+ * 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.telephony;
+
+import com.android.internal.telephony.IThirdPartyCallProvider;
+
+/**
+ * Interface provided to ThirdPartyCallService. The service can use this to notify the listener of
+ * changes to the call state.
+ */
+oneway interface IThirdPartyCallListener {
+ /**
+ * Called by the service when a call provider is available to perform the outgoing or incoming
+ * call.
+ */
+ void onCallProviderAttached(IThirdPartyCallProvider callProvider);
+
+ /**
+ * Notifies the listener that ringing has started for this call.
+ */
+ void onRingingStarted();
+
+ /**
+ * Notifies the listener that the call has been successfully established.
+ */
+ void onCallEstablished();
+
+ /**
+ * Notifies the listener that the call has ended.
+ */
+ void onCallEnded(int reason);
+}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl
new file mode 100644
index 0000000..9d595b0
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl
@@ -0,0 +1,47 @@
+/*
+ * 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.telephony;
+
+import com.android.internal.telephony.IThirdPartyCallListener;
+import com.android.internal.telephony.IThirdPartyCallSendDtmfCallback;
+
+/**
+ * Interface sent to ThirdPartyCallListener.onCallProviderAttached. This is used to control an
+ * outgoing or incoming call.
+ */
+oneway interface IThirdPartyCallProvider {
+ /**
+ * Mutes or unmutes the call.
+ */
+ void mute(boolean shouldMute);
+
+ /**
+ * Ends the current call. If this is an unanswered incoming call then the call is rejected (for
+ * example, a notification is sent to a server that the user declined the call).
+ */
+ void hangup();
+
+ /**
+ * Accepts the incoming call.
+ */
+ void incomingCallAccept();
+
+ /**
+ * Sends the given DTMF code. The code can be '0'-'9', 'A'-'D', '#', or '*'.
+ */
+ void sendDtmf(char c, IThirdPartyCallSendDtmfCallback callback);
+}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallSendDtmfCallback.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallSendDtmfCallback.aidl
new file mode 100644
index 0000000..3a02b06
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IThirdPartyCallSendDtmfCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.telephony;
+
+/**
+ * Callback interface for when DTMF has been sent.
+ */
+oneway interface IThirdPartyCallSendDtmfCallback {
+ /**
+ * Called when the DTMF code has been sent.
+ */
+ void onSendDtmfCompleted();
+}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl
new file mode 100644
index 0000000..597567a
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.telephony;
+
+import com.android.internal.telephony.IThirdPartyCallListener;
+
+/**
+ * Interface provided by a service to start outgoing calls and attach to incoming calls.
+ */
+oneway interface IThirdPartyCallService {
+ /**
+ * Call to start a new outgoing call.
+ */
+ void outgoingCallInitiate(IThirdPartyCallListener listener, String number);
+
+ /**
+ * Call to attach to an incoming call. This is in response to a call to
+ * TelephonyManager.newIncomingThirdPartyCall.
+ */
+ void incomingCallAttach(IThirdPartyCallListener listener, String callId);
+}
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 8c42d25..08f4379 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -57,6 +57,7 @@
public static final int PHONE_TYPE_GSM = RILConstants.GSM_PHONE;
public static final int PHONE_TYPE_CDMA = RILConstants.CDMA_PHONE;
public static final int PHONE_TYPE_SIP = RILConstants.SIP_PHONE;
+ public static final int PHONE_TYPE_THIRD_PARTY = RILConstants.THIRD_PARTY_PHONE;
// Modes for LTE_ON_CDMA
public static final int LTE_ON_CDMA_UNKNOWN = RILConstants.LTE_ON_CDMA_UNKNOWN;
@@ -78,7 +79,7 @@
public static final String DATA_APN_TYPE_KEY = "apnType";
public static final String DATA_APN_KEY = "apn";
public static final String DATA_LINK_PROPERTIES_KEY = "linkProperties";
- public static final String DATA_LINK_CAPABILITIES_KEY = "linkCapabilities";
+ public static final String DATA_NETWORK_CAPABILITIES_KEY = "networkCapabilities";
public static final String DATA_IFACE_NAME_KEY = "iface";
public static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable";
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index d338857..815211c 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -84,6 +84,7 @@
int GSM_PHONE = 1;
int CDMA_PHONE = 2;
int SIP_PHONE = 3;
+ int THIRD_PARTY_PHONE = 4;
int LTE_ON_CDMA_UNKNOWN = -1;
int LTE_ON_CDMA_FALSE = 0;
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index a016933..3190fb0 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -33,6 +33,7 @@
import android.content.pm.InstrumentationInfo;
import android.content.pm.ManifestDigest;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
@@ -718,4 +719,9 @@
public void clearForwardingIntentFilters(int userIdOrig) {
throw new UnsupportedOperationException();
}
+
+ /** {@hide} */
+ public PackageInstaller getPackageInstaller() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
index 5c273de1..e4ea9367 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
@@ -16,6 +16,7 @@
package com.android.test.hwui;
+import android.animation.TimeInterpolator;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
@@ -27,6 +28,8 @@
import android.view.HardwareCanvas;
import android.view.RenderNodeAnimator;
import android.view.View;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.OvershootInterpolator;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
@@ -106,24 +109,28 @@
mToggle = !mToggle;
mRunningAnimations.add(new RenderNodeAnimator(
- mX, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 400.0f : 200.0f));
+ mX, mToggle ? 400.0f : 200.0f));
mRunningAnimations.add(new RenderNodeAnimator(
- mY, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 600.0f : 200.0f));
+ mY, mToggle ? 600.0f : 200.0f));
mRunningAnimations.add(new RenderNodeAnimator(
- mRadius, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 250.0f : 150.0f));
+ mRadius, mToggle ? 250.0f : 150.0f));
mRunningAnimations.add(new RenderNodeAnimator(
mPaint, RenderNodeAnimator.PAINT_ALPHA,
- RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 64.0f : 255.0f));
+ mToggle ? 64.0f : 255.0f));
mRunningAnimations.add(new RenderNodeAnimator(
mPaint, RenderNodeAnimator.PAINT_STROKE_WIDTH,
- RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 5.0f : 60.0f));
+ mToggle ? 5.0f : 60.0f));
+ TimeInterpolator interp = new OvershootInterpolator(3.0f);
for (int i = 0; i < mRunningAnimations.size(); i++) {
- mRunningAnimations.get(i).start(this);
+ RenderNodeAnimator anim = mRunningAnimations.get(i);
+ anim.setInterpolator(interp);
+ anim.setDuration(1000);
+ anim.start(this);
}
if (mToggle) {
diff --git a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
index 8f9cf58..b5b12d8 100644
--- a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
+++ b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
@@ -5,6 +5,7 @@
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
+import android.util.Log;
import android.view.HardwareRenderer;
import android.view.RenderNodeAnimator;
import android.view.View;
@@ -73,14 +74,20 @@
float delta = (pos - clickedPosition) * 1.1f;
if (delta == 0) delta = -1;
RenderNodeAnimator animator = new RenderNodeAnimator(
- RenderNodeAnimator.TRANSLATION_Y, RenderNodeAnimator.DELTA_TYPE_DELTA, dy * delta);
+ RenderNodeAnimator.TRANSLATION_Y, dy * delta);
animator.setDuration(DURATION);
+ if (child == clickedView) logTranslationY(clickedView);
animator.start(child);
+ if (child == clickedView) logTranslationY(clickedView);
}
//mHandler.postDelayed(mLaunchActivity, (long) (DURATION * .4));
mLaunchActivity.run();
}
+ private void logTranslationY(View v) {
+ Log.d("RTTest", "View has translationY: " + v.getTranslationY());
+ }
+
private Runnable mLaunchActivity = new Runnable() {
@Override
diff --git a/tests/Split/Android.mk b/tests/Split/Android.mk
new file mode 100644
index 0000000..7884d4d
--- /dev/null
+++ b/tests/Split/Android.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := Split
+
+LOCAL_AAPT_FLAGS := --split fr,de
+LOCAL_AAPT_FLAGS += -v
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/Split/AndroidManifest.xml b/tests/Split/AndroidManifest.xml
new file mode 100644
index 0000000..a4956a7
--- /dev/null
+++ b/tests/Split/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.example.split">
+ <application android:label="@string/app_title">
+ <activity android:name="ActivityMain">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/Split/assets/blah.txt b/tests/Split/assets/blah.txt
new file mode 100644
index 0000000..1b37e40
--- /dev/null
+++ b/tests/Split/assets/blah.txt
@@ -0,0 +1 @@
+This is some useful info.
diff --git a/tests/Split/assets/statement.xml b/tests/Split/assets/statement.xml
new file mode 100644
index 0000000..91750d1
--- /dev/null
+++ b/tests/Split/assets/statement.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<statement>
+ <value>Hello</value>
+</statement>
diff --git a/tests/Split/res/layout-fr-sw600dp/main.xml b/tests/Split/res/layout-fr-sw600dp/main.xml
new file mode 100644
index 0000000..2461c8c
--- /dev/null
+++ b/tests/Split/res/layout-fr-sw600dp/main.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+</FrameLayout>
diff --git a/tests/Split/res/layout/main.xml b/tests/Split/res/layout/main.xml
new file mode 100644
index 0000000..36992a2
--- /dev/null
+++ b/tests/Split/res/layout/main.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
diff --git a/tests/Split/res/values-de/values.xml b/tests/Split/res/values-de/values.xml
new file mode 100644
index 0000000..26d0507
--- /dev/null
+++ b/tests/Split/res/values-de/values.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string name="test">Achtung!</string>
+</resources>
diff --git a/tests/Split/res/values-fr/values.xml b/tests/Split/res/values-fr/values.xml
new file mode 100644
index 0000000..16532da
--- /dev/null
+++ b/tests/Split/res/values-fr/values.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string name="app_title">APK Divisé</string>
+ <string name="test">Bonjour, Monde!</string>
+ <string name="blah">Bleh..</string>
+ <string-array name="lotsofstrings">
+ <item>Hé là</item>
+ <item>Au revoir</item>
+ </string-array>
+</resources>
diff --git a/tests/Split/res/values-sw600dp/values.xml b/tests/Split/res/values-sw600dp/values.xml
new file mode 100644
index 0000000..a8329bb
--- /dev/null
+++ b/tests/Split/res/values-sw600dp/values.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <dimen name="width">230dp</dimen>
+</resources>
diff --git a/tests/Split/res/values/values.xml b/tests/Split/res/values/values.xml
new file mode 100644
index 0000000..68edc77
--- /dev/null
+++ b/tests/Split/res/values/values.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string name="app_title">Split APK</string>
+ <string name="test">Hello, World!</string>
+ <string name="boom">Boom!</string>
+ <string name="blah">Blah...</string>
+ <string-array name="lotsofstrings">
+ <item>Hello there</item>
+ <item>Good bye</item>
+ </string-array>
+
+ <plurals name="plur">
+ <item quantity="zero">I no haz :(</item>
+ <item quantity="one">I haz 1!1! :)</item>
+ <item quantity="many">I haz ALL!</item>
+ </plurals>
+
+ <bool name="que">true</bool>
+ <color name="green">#00FF00</color>
+ <dimen name="width">23dp</dimen>
+ <item type="id" name="identifier" />
+ <integer name="number">123</integer>
+ <integer-array name="numList">
+ <item>1234</item>
+ </integer-array>
+
+ <array name="ary">
+ <item>@string/test</item>
+ <item>@string/boom</item>
+ <item>25dp</item>
+ </array>
+</resources>
diff --git a/tests/Split/src/java/com/android/example/split/ActivityMain.java b/tests/Split/src/java/com/android/example/split/ActivityMain.java
new file mode 100644
index 0000000..a15fb3c
--- /dev/null
+++ b/tests/Split/src/java/com/android/example/split/ActivityMain.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.example.split;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class ActivityMain extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ TextView text = new TextView(this);
+ text.setText(R.string.test);
+ setContentView(text);
+ }
+}
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
index d0f2a2d..118f258 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
@@ -24,13 +24,12 @@
android:viewportHeight="480"
android:viewportWidth="480" />
- <group>
- <path
- android:name="box1"
- android:pathData="m20,200l100,90l180,-180l-35,-35l-145,145l-60,-60l-40,40z"
- android:fill="?android:attr/colorControlActivated"
- android:stroke="?android:attr/colorControlActivated"
- android:strokeLineCap="round"
- android:strokeLineJoin="round" />
- </group>
-</vector>
+ <path
+ android:name="box1"
+ android:fill="?android:attr/colorControlActivated"
+ android:pathData="m20,200l100,90l180,-180l-35,-35l-145,145l-60,-60l-40,40z"
+ android:stroke="?android:attr/colorControlActivated"
+ android:strokeLineCap="round"
+ android:strokeLineJoin="round" />
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
index 728624a..034f7a0 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,23 +16,23 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
- <viewport android:viewportWidth="320"
- android:viewportHeight="320"/>
+ <viewport
+ android:viewportHeight="320"
+ android:viewportWidth="320" />
- <group>
- <path
- android:name="house"
- android:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z"
- android:fill="#ff440000"
- android:stroke="#FF00FF00"
- android:strokeWidth="10"
- android:rotation="180"
- android:pivotX="70"
- android:pivotY="120"
- android:trimPathStart=".1"
- android:trimPathEnd=".9"/>
- </group>
-</vector>
+ <path
+ android:name="house"
+ android:fill="#ff440000"
+ android:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z"
+ android:pivotX="70"
+ android:pivotY="120"
+ android:rotation="180"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="10"
+ android:trimPathEnd=".9"
+ android:trimPathStart=".1" />
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
index 1792683..451b28e 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,51 +16,47 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
<viewport
- android:viewportWidth="7.30625"
- android:viewportHeight="12.25"/>
+ android:viewportHeight="12.25"
+ android:viewportWidth="7.30625" />
- <group>
-
- <path
- android:name="clip1"
- android:pathData="
+ <path
+ android:name="clip1"
+ android:clipToPath="true"
+ android:pathData="
M 0, 0
l 7.3, 0
l 0, 0
l -7.3, 0
z"
- android:clipToPath="true"
- android:rotation="-30"
- android:pivotX="3.65"
- android:pivotY="6.125"
- />
- <path
- android:name="one"
- android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
+ android:pivotX="3.65"
+ android:pivotY="6.125"
+ android:rotation="-30" />
+ <path
+ android:name="one"
+ android:fill="#ff88ff"
+ android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
- l -5.046875,0.0 0.0,-1.0Z"
- android:fill="#ff88ff"
- />
- <path
- android:name="clip2"
- android:pathData="
+ l -5.046875,0.0 0.0,-1.0Z" />
+ <path
+ android:name="clip2"
+ android:clipToPath="true"
+ android:pathData="
M 0, 0
l 7.3, 0
l 0, 12.25
l -7.3, 0
z"
- android:clipToPath="true"
- android:rotation="-30"
- android:pivotX="3.65"
- android:pivotY="6.125"
- />
- <path
- android:name="two"
- android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
+ android:pivotX="3.65"
+ android:pivotY="6.125"
+ android:rotation="-30" />
+ <path
+ android:name="two"
+ android:fill="#ff88ff"
+ android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
@@ -67,8 +64,6 @@
q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
- q -0.78125024,0.8125 -2.2187502,2.265625Z"
- android:fill="#ff88ff"
- />
- </group>
-</vector>
+ q -0.78125024,0.8125 -2.2187502,2.265625Z" />
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
index 90694fb..6f9caa8 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,48 +13,44 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android">
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
<viewport
- android:viewportWidth="7.30625"
- android:viewportHeight="12.25"/>
+ android:viewportHeight="12.25"
+ android:viewportWidth="7.30625" />
- <group>
- <path
- android:name="clip1"
- android:pathData="
+ <path
+ android:name="clip1"
+ android:clipToPath="true"
+ android:fill="#112233"
+ android:pathData="
M 3.65, 6.125
m -.001, 0
a .001,.001 0 1,0 .002,0
- a .001,.001 0 1,0 -.002,0z"
- android:clipToPath="true"
- android:fill="#112233"
- />
-
- <path
- android:name="one"
- android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
+ a .001,.001 0 1,0 -.002,0z" />
+ <path
+ android:name="one"
+ android:fill="#ff88ff"
+ android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
- l -5.046875,0.0 0.0,-1.0Z"
- android:fill="#ff88ff"
- />
- <path
- android:name="clip2"
- android:pathData="
+ l -5.046875,0.0 0.0,-1.0Z" />
+ <path
+ android:name="clip2"
+ android:clipToPath="true"
+ android:fill="#112233"
+ android:pathData="
M 3.65, 6.125
m -6, 0
a 6,6 0 1,0 12,0
- a 6,6 0 1,0 -12,0z"
- android:clipToPath="true"
- android:fill="#112233"
- />
- <path
- android:name="two"
- android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
+ a 6,6 0 1,0 -12,0z" />
+ <path
+ android:name="two"
+ android:fill="#ff88ff"
+ android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
@@ -61,8 +58,6 @@
q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
- q -0.78125024,0.8125 -2.2187502,2.265625Z"
- android:fill="#ff88ff"
- />
- </group>
-</vector>
+ q -0.78125024,0.8125 -2.2187502,2.265625Z" />
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
index c6595fa..e6c2557 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
@@ -23,18 +23,17 @@
android:viewportHeight="12.25"
android:viewportWidth="7.30625" />
- <group>
- <path
- android:name="one"
- android:fill="#ffff00"
- android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
+ <path
+ android:name="one"
+ android:fill="#ffff00"
+ android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
l -5.046875,0.0 0.0,-1.0Z" />
- <path
- android:name="two"
- android:fill="#ffff00"
- android:fillOpacity="0"
- android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
+ <path
+ android:name="two"
+ android:fill="#ffff00"
+ android:fillOpacity="0"
+ android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
@@ -43,5 +42,5 @@
q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
q -0.78125024,0.8125 -2.2187502,2.265625Z" />
- </group>
+
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
index 850de28..3f8cc09 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,34 +16,38 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
<viewport
- android:viewportWidth="700"
- android:viewportHeight="700"/>
+ android:viewportHeight="700"
+ android:viewportWidth="700" />
- <group>
- <path android:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
- android:name="path2451"
- android:stroke="#FF000000"
- android:strokeWidth="30.65500000000000"/>
- <path android:pathData="M 365.015 311.066"
- android:name="path2453"
- android:stroke="#FF000000"
- android:strokeWidth="30.655000000000001"/>
- <path android:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928"
- android:name="path2455"
- android:stroke="#FF000000"
- android:fill="#FFFFFFFF"
- android:strokeWidth="30.655000000000001"/>
- <path android:pathData="M 170.515 451.566L 305.61 313.46"
- android:name="path2457"
- android:stroke="#000000"
- android:strokeWidth="30.655000000000001"/>
- <path android:pathData="M 557.968 449.974L 426.515 315.375"
- android:name="path2459"
- android:stroke="#000000"
- android:strokeWidth="30.655000000000001"/>
- </group>
-</vector>
+ <path
+ android:name="path2451"
+ android:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
+ android:stroke="#FF000000"
+ android:strokeWidth="30.65500000000000" />
+ <path
+ android:name="path2453"
+ android:pathData="M 365.015 311.066"
+ android:stroke="#FF000000"
+ android:strokeWidth="30.655000000000001" />
+ <path
+ android:name="path2455"
+ android:fill="#FFFFFFFF"
+ android:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928"
+ android:stroke="#FF000000"
+ android:strokeWidth="30.655000000000001" />
+ <path
+ android:name="path2457"
+ android:pathData="M 170.515 451.566L 305.61 313.46"
+ android:stroke="#000000"
+ android:strokeWidth="30.655000000000001" />
+ <path
+ android:name="path2459"
+ android:pathData="M 557.968 449.974L 426.515 315.375"
+ android:stroke="#000000"
+ android:strokeWidth="30.655000000000001" />
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
index 7c7e679..4db5090 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,21 +13,21 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
- <viewport android:viewportWidth="140"
- android:viewportHeight="110"/>
+ <viewport
+ android:viewportHeight="110"
+ android:viewportWidth="140" />
- <group>
- <path
- android:name="back"
- android:pathData="M 20,55 l 35.3,-35.3 7.07,7.07 -35.3,35.3 z
+ <path
+ android:name="back"
+ android:fill="#ffffffff"
+ android:pathData="M 20,55 l 35.3,-35.3 7.07,7.07 -35.3,35.3 z
M 27,50 l 97,0 0,10 -97,0 z
- M 20,55 l 7.07,-7.07 35.3,35.3 -7.07,7.07 z"
- android:fill="#ffffffff"
- />
- </group>
-</vector>
+ M 20,55 l 7.07,-7.07 35.3,35.3 -7.07,7.07 z" />
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
index 59f7459..44ef979 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,20 +16,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
+ <viewport
+ android:viewportHeight="600"
+ android:viewportWidth="600" />
- <viewport android:viewportWidth="600"
- android:viewportHeight="600"/>
+ <path
+ android:name="pie1"
+ android:fill="#ffffcc00"
+ android:pathData="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="1" />
- <group>
- <path
- android:name="pie1"
- android:pathData="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z"
- android:fill="#ffffcc00"
- android:stroke="#FF00FF00"
- android:strokeWidth="1"/>
- </group>
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
index 2e379d6..248a143 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
@@ -23,14 +23,12 @@
android:viewportHeight="200"
android:viewportWidth="200" />
- <group>
- <path
- android:name="house"
- android:fill="#ffffffff"
- android:pathData="M 100,20 l 0,0 0,140 -80,0 z M 100,20 l 0,0 80,140 -80,0 z"
- android:pivotX="100"
- android:pivotY="100"
- android:rotation="90" />
- </group>
+ <path
+ android:name="house"
+ android:fill="#ffffffff"
+ android:pathData="M 100,20 l 0,0 0,140 -80,0 z M 100,20 l 0,0 80,140 -80,0 z"
+ android:pivotX="100"
+ android:pivotY="100"
+ android:rotation="90" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
index 8484e9e..56c2972 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
@@ -21,26 +21,24 @@
android:width="64dp" />
<viewport
- android:viewportWidth="200"
- android:viewportHeight="200"/>
+ android:viewportHeight="200"
+ android:viewportWidth="200" />
- <group>
- <path
- android:name="bar3"
- android:fill="#FFFFFFFF"
- android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
- <path
- android:name="bar2"
- android:fill="#FFFFFFFF"
- android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
- <path
- android:name="bar1"
- android:fill="#FF555555"
- android:pathData="M14.001,34.645 L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
- <path
- android:name="bar0"
- android:fill="#FF555555"
- android:pathData="M0,20.502l6.999,7.071 c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
- </group>
+ <path
+ android:name="bar3"
+ android:fill="#FFFFFFFF"
+ android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
+ <path
+ android:name="bar2"
+ android:fill="#FFFFFFFF"
+ android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
+ <path
+ android:name="bar1"
+ android:fill="#FF555555"
+ android:pathData="M14.001,34.645 L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
+ <path
+ android:name="bar0"
+ android:fill="#FF555555"
+ android:pathData="M0,20.502l6.999,7.071 c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
index 2b6c5d3..16d8b48 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
@@ -23,18 +23,16 @@
android:viewportHeight="80"
android:viewportWidth="40" />
- <group>
- <path
- android:name="battery"
- android:fill="#3388ff"
- android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
- android:rotation="0"
- android:stroke="#ff8833"
- android:strokeWidth="1" />
- <path
- android:name="spark"
- android:fill="#FFFF0000"
- android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
- </group>
+ <path
+ android:name="battery"
+ android:fill="#3388ff"
+ android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
+ android:rotation="0"
+ android:stroke="#ff8833"
+ android:strokeWidth="1" />
+ <path
+ android:name="spark"
+ android:fill="#FFFF0000"
+ android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
index 681eb4f..0a0407d 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
@@ -23,22 +23,20 @@
android:viewportHeight="600"
android:viewportWidth="600" />
- <group>
- <path
- android:name="pie1"
- android:pathData="M300,70 a230,230 0 1,0 1,0 z"
- android:stroke="#FF00FF00"
- android:strokeWidth="70"
- android:trimPathEnd=".75"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="v"
- android:fill="#FF00FF00"
- android:pathData="M300,70 l 0,-70 70,70 -70,70z"
- android:pivotX="300"
- android:pivotY="300"
- android:rotation="0" />
- </group>
+ <path
+ android:name="pie1"
+ android:pathData="M300,70 a230,230 0 1,0 1,0 z"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="70"
+ android:trimPathEnd=".75"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
+ <path
+ android:name="v"
+ android:fill="#FF00FF00"
+ android:pathData="M300,70 l 0,-70 70,70 -70,70z"
+ android:pivotX="300"
+ android:pivotY="300"
+ android:rotation="0" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
index ef1b8e4..385b1e9 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
@@ -23,22 +23,20 @@
android:viewportHeight="400"
android:viewportWidth="600" />
- <group>
- <path
- android:name="pie1"
- android:fill="#ffffffff"
- android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
- android:stroke="#FF00FF00"
- android:strokeWidth="1" />
- <path
- android:name="half"
- android:fill="#FFFF0000"
- android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
- android:pivotX="300"
- android:pivotY="200"
- android:rotation="0"
- android:stroke="#FF0000FF"
- android:strokeWidth="5" />
- </group>
+ <path
+ android:name="pie1"
+ android:fill="#ffffffff"
+ android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="1" />
+ <path
+ android:name="half"
+ android:fill="#FFFF0000"
+ android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
+ android:pivotX="300"
+ android:pivotY="200"
+ android:rotation="0"
+ android:stroke="#FF0000FF"
+ android:strokeWidth="5" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
index 77bf723..b701b35 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
@@ -23,19 +23,17 @@
android:viewportHeight="500"
android:viewportWidth="800" />
- <group>
- <path
- android:name="pie2"
- android:pathData="M200,350 l 50,-25
+ <path
+ android:name="pie2"
+ android:pathData="M200,350 l 50,-25
a25,12 -30 0,1 100,-50 l 50,-25
a25,25 -30 0,1 100,-50 l 50,-25
a25,37 -30 0,1 100,-50 l 50,-25
a25,50 -30 0,1 100,-50 l 50,-25"
- android:pivotX="90"
- android:pivotY="100"
- android:rotation="20"
- android:stroke="#FF00FF00"
- android:strokeWidth="10" />
- </group>
+ android:pivotX="90"
+ android:pivotY="100"
+ android:rotation="20"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="10" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
index df5838c..8d773e1 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
@@ -23,16 +23,14 @@
android:viewportHeight="400"
android:viewportWidth="500" />
- <group>
- <path
- android:name="house"
- android:fill="#ff440000"
- android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
- android:pivotX="250"
- android:pivotY="200"
- android:rotation="180"
- android:stroke="#FFFF0000"
- android:strokeWidth="10" />
- </group>
+ <path
+ android:name="house"
+ android:fill="#ff440000"
+ android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+ android:pivotX="250"
+ android:pivotY="200"
+ android:rotation="180"
+ android:stroke="#FFFF0000"
+ android:strokeWidth="10" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
index 0bdcda5..3b7926c 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
@@ -23,15 +23,13 @@
android:viewportHeight="200"
android:viewportWidth="200" />
- <group>
- <path
- android:name="house"
- android:pathData="M 100,10 v 90 M 10,100 h 90"
- android:pivotX="100"
- android:pivotY="100"
- android:rotation="360"
- android:stroke="#FF00FF00"
- android:strokeWidth="10" />
- </group>
+ <path
+ android:name="house"
+ android:pathData="M 100,10 v 90 M 10,100 h 90"
+ android:pivotX="100"
+ android:pivotY="100"
+ android:rotation="360"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="10" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
index 4453ae4..1ec72be 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+ Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,21 +16,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
- <viewport android:viewportWidth="1200"
- android:viewportHeight="600"/>
+ <viewport
+ android:viewportHeight="600"
+ android:viewportWidth="1200" />
- <group>
- <path
- android:name="house"
- android:pathData="M200,300 Q400,50 600,300 T1000,300"
- android:stroke="#FFFF0000"
- android:strokeWidth="10"
- android:rotation="360"
- android:pivotX="600"
- android:pivotY="300"/>
- </group>
+ <path
+ android:name="house"
+ android:pathData="M200,300 Q400,50 600,300 T1000,300"
+ android:pivotX="600"
+ android:pivotY="300"
+ android:rotation="360"
+ android:stroke="#FFFF0000"
+ android:strokeWidth="10" />
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
index dfae9ac..12d0e93 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
@@ -23,15 +23,13 @@
android:viewportHeight="400"
android:viewportWidth="500" />
- <group>
- <path
- android:name="house"
- android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
- android:pivotX="250"
- android:pivotY="200"
- android:rotation="360"
- android:stroke="#FFFFFF00"
- android:strokeWidth="10" />
- </group>
+ <path
+ android:name="house"
+ android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+ android:pivotX="250"
+ android:pivotY="200"
+ android:rotation="360"
+ android:stroke="#FFFFFF00"
+ android:strokeWidth="10" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
index a890fd6..017e04c 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
@@ -23,14 +23,12 @@
android:viewportHeight="800"
android:viewportWidth="1000" />
- <group>
- <path
- android:name="house"
- android:pathData="M10,300 Q400,550 600,300 T1000,300"
- android:pivotX="90"
- android:pivotY="100"
- android:stroke="#FFFF0000"
- android:strokeWidth="60" />
- </group>
+ <path
+ android:name="house"
+ android:pathData="M10,300 Q400,550 600,300 T1000,300"
+ android:pivotX="90"
+ android:pivotY="100"
+ android:stroke="#FFFF0000"
+ android:strokeWidth="60" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
index b8af7e2..b7002a3 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
@@ -23,16 +23,14 @@
android:viewportHeight="480"
android:viewportWidth="480" />
- <group>
- <path
- android:name="edit"
- android:fill="#FF00FFFF"
- android:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333
+ <path
+ android:name="edit"
+ android:fill="#FF00FFFF"
+ android:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333
c-13.333 -13.334 -33.333,0 -33.333,0l-160,160c0,0 -40,153.333 -40,173.333c0,13.333,13.333,13.333,13.333,13.333l173.334 -40
c0,0,146.666 -146.666,160 -160C420,200,406.667,180,406.667,180z M226.399,356.823L131.95,378.62l-38.516 -38.522
c7.848 -34.675,20.152 -82.52,23.538 -95.593l3.027,2.162l106.667,106.666L226.399,356.823z"
- android:stroke="#FF000000"
- android:strokeWidth="10" />
- </group>
+ android:stroke="#FF000000"
+ android:strokeWidth="10" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
index 22ce795..cda213d 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
@@ -23,10 +23,8 @@
android:viewportHeight="24"
android:viewportWidth="24" />
- <group>
- <path
- android:fill="#FF000000"
- android:pathData="M3.0,17.25L3.0,21.0l3.75,0.0L17.813995,9.936001l-3.75,-3.75L3.0,17.25zM20.707,7.0429993c0.391,-0.391 0.391,-1.023 0.0,-1.414l-2.336,-2.336c-0.391,-0.391 -1.023,-0.391 -1.414,0.0l-1.832,1.832l3.75,3.75L20.707,7.0429993z" />
- </group>
+ <path
+ android:fill="#FF000000"
+ android:pathData="M3.0,17.25L3.0,21.0l3.75,0.0L17.813995,9.936001l-3.75,-3.75L3.0,17.25zM20.707,7.0429993c0.391,-0.391 0.391,-1.023 0.0,-1.414l-2.336,-2.336c-0.391,-0.391 -1.023,-0.391 -1.414,0.0l-1.832,1.832l3.75,3.75L20.707,7.0429993z" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
index 042173c..2cb6381 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
@@ -23,10 +23,8 @@
android:viewportHeight="24"
android:viewportWidth="24" />
- <group>
- <path
- android:fill="#FF000000"
- android:pathData="M6.0,19.0c0.0,1.104 0.896,2.0 2.0,2.0l8.0,0.0c1.104,0.0 2.0,-0.896 2.0,-2.0l0.0,-12.0L6.0,7.0L6.0,19.0zM18.0,4.0l-2.5,0.0l-1.0,-1.0l-5.0,0.0l-1.0,1.0L6.0,4.0C5.4469986,4.0 5.0,4.4469986 5.0,5.0l0.0,1.0l14.0,0.0l0.0,-1.0C19.0,4.4469986 18.552002,4.0 18.0,4.0z" />
- </group>
+ <path
+ android:fill="#FF000000"
+ android:pathData="M6.0,19.0c0.0,1.104 0.896,2.0 2.0,2.0l8.0,0.0c1.104,0.0 2.0,-0.896 2.0,-2.0l0.0,-12.0L6.0,7.0L6.0,19.0zM18.0,4.0l-2.5,0.0l-1.0,-1.0l-5.0,0.0l-1.0,1.0L6.0,4.0C5.4469986,4.0 5.0,4.4469986 5.0,5.0l0.0,1.0l14.0,0.0l0.0,-1.0C19.0,4.4469986 18.552002,4.0 18.0,4.0z" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
index 6b6f43d..d58942e 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
@@ -23,10 +23,8 @@
android:viewportHeight="24"
android:viewportWidth="24" />
- <group>
- <path
- android:fill="#FF000000"
- android:pathData="M16.0,5.0c-1.955,0.0 -3.83,1.268 -4.5,3.0c-0.67,-1.732 -2.547,-3.0 -4.5,-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207,-5.242 9.0,-7.971 9.0,-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z" />
- </group>
+ <path
+ android:fill="#FF000000"
+ android:pathData="M16.0,5.0c-1.955,0.0 -3.83,1.268 -4.5,3.0c-0.67,-1.732 -2.547,-3.0 -4.5,-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207,-5.242 9.0,-7.971 9.0,-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
index ba8ebca..4717be4 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
@@ -23,13 +23,11 @@
android:viewportHeight="24"
android:viewportWidth="24" />
- <group>
- <path
- android:fillOpacity="0.9"
- android:pathData="M11.994999,2.0C6.4679985,2.0 2.0,6.4780006 2.0,12.0s4.468,10.0 9.995,10.0S22.0,17.522 22.0,12.0S17.521,2.0 11.994999,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.582 -8.0,-8.0s3.58,-8.0 8.0,-8.0s8.0,3.582 8.0,8.0S16.419998,20.0 12.0,20.0z" />
- <path
- android:fillOpacity="0.9"
- android:pathData="M12.5,6.0l-1.5,0.0 0.0,7.0 5.3029995,3.1819992 0.75,-1.249999 -4.5529995,-2.7320004z" />
- </group>
+ <path
+ android:fillOpacity="0.9"
+ android:pathData="M11.994999,2.0C6.4679985,2.0 2.0,6.4780006 2.0,12.0s4.468,10.0 9.995,10.0S22.0,17.522 22.0,12.0S17.521,2.0 11.994999,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.582 -8.0,-8.0s3.58,-8.0 8.0,-8.0s8.0,3.582 8.0,8.0S16.419998,20.0 12.0,20.0z" />
+ <path
+ android:fillOpacity="0.9"
+ android:pathData="M12.5,6.0l-1.5,0.0 0.0,7.0 5.3029995,3.1819992 0.75,-1.249999 -4.5529995,-2.7320004z" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
index 896a938..c626325 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
@@ -23,10 +23,8 @@
android:viewportHeight="24"
android:viewportWidth="24" />
- <group>
- <path
- android:fill="#FF000000"
- android:pathData="M19.429,12.975998c0.042,-0.32 0.07,-0.645 0.07,-0.976s-0.029,-0.655 -0.07,-0.976l2.113,-1.654c0.188,-0.151 0.243,-0.422 0.118,-0.639l-2.0,-3.463c-0.125,-0.217 -0.386,-0.304 -0.612,-0.218l-2.49,1.004c-0.516,-0.396 -1.081,-0.731 -1.69,-0.984l-0.375,-2.648C14.456,2.1829987 14.25,2.0 14.0,2.0l-4.0,0.0C9.75,2.0 9.544,2.1829987 9.506,2.422001L9.131,5.0699997C8.521,5.322998 7.957,5.6570015 7.44,6.054001L4.952,5.0509987C4.726,4.965 4.464,5.052002 4.34,5.269001l-2.0,3.463C2.2150002,8.947998 2.27,9.219002 2.4580002,9.369999l2.112,1.653C4.528,11.344002 4.5,11.668999 4.5,12.0s0.029,0.656 0.071,0.977L2.4580002,14.630001c-0.188,0.151 -0.243,0.422 -0.118,0.639l2.0,3.463c0.125,0.217 0.386,0.304 0.612,0.218l2.489,-1.004c0.516,0.396 1.081,0.731 1.69,0.984l0.375,2.648C9.544,21.817001 9.75,22.0 10.0,22.0l4.0,0.0c0.25,0.0 0.456,-0.183 0.494,-0.422l0.375,-2.648c0.609,-0.253 1.174,-0.588 1.689,-0.984l2.49,1.004c0.226,0.086 0.487,-0.001 0.612,-0.218l2.0,-3.463c0.125,-0.217 0.07,-0.487 -0.118,-0.639L19.429,12.975998zM12.0,16.0c-2.21,0.0 -4.0,-1.791 -4.0,-4.0c0.0,-2.21 1.79,-4.0 4.0,-4.0c2.208,0.0 4.0,1.79 4.0,4.0C16.0,14.209 14.208,16.0 12.0,16.0z" />
- </group>
+ <path
+ android:fill="#FF000000"
+ android:pathData="M19.429,12.975998c0.042,-0.32 0.07,-0.645 0.07,-0.976s-0.029,-0.655 -0.07,-0.976l2.113,-1.654c0.188,-0.151 0.243,-0.422 0.118,-0.639l-2.0,-3.463c-0.125,-0.217 -0.386,-0.304 -0.612,-0.218l-2.49,1.004c-0.516,-0.396 -1.081,-0.731 -1.69,-0.984l-0.375,-2.648C14.456,2.1829987 14.25,2.0 14.0,2.0l-4.0,0.0C9.75,2.0 9.544,2.1829987 9.506,2.422001L9.131,5.0699997C8.521,5.322998 7.957,5.6570015 7.44,6.054001L4.952,5.0509987C4.726,4.965 4.464,5.052002 4.34,5.269001l-2.0,3.463C2.2150002,8.947998 2.27,9.219002 2.4580002,9.369999l2.112,1.653C4.528,11.344002 4.5,11.668999 4.5,12.0s0.029,0.656 0.071,0.977L2.4580002,14.630001c-0.188,0.151 -0.243,0.422 -0.118,0.639l2.0,3.463c0.125,0.217 0.386,0.304 0.612,0.218l2.489,-1.004c0.516,0.396 1.081,0.731 1.69,0.984l0.375,2.648C9.544,21.817001 9.75,22.0 10.0,22.0l4.0,0.0c0.25,0.0 0.456,-0.183 0.494,-0.422l0.375,-2.648c0.609,-0.253 1.174,-0.588 1.689,-0.984l2.49,1.004c0.226,0.086 0.487,-0.001 0.612,-0.218l2.0,-3.463c0.125,-0.217 0.07,-0.487 -0.118,-0.639L19.429,12.975998zM12.0,16.0c-2.21,0.0 -4.0,-1.791 -4.0,-4.0c0.0,-2.21 1.79,-4.0 4.0,-4.0c2.208,0.0 4.0,1.79 4.0,4.0C16.0,14.209 14.208,16.0 12.0,16.0z" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_test01.xml b/tests/VectorDrawableTest/res/drawable/vector_test01.xml
index a9091ab..bad5a46 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_test01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_test01.xml
@@ -23,12 +23,10 @@
android:viewportHeight="512"
android:viewportWidth="512" />
- <group>
- <path
- android:name="002b"
- android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0t-200,299"
- android:stroke="#FF0000FF"
- android:strokeWidth="4" />
- </group>
+ <path
+ android:name="002b"
+ android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0t-200,299"
+ android:stroke="#FF0000FF"
+ android:strokeWidth="4" />
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_test02.xml b/tests/VectorDrawableTest/res/drawable/vector_test02.xml
index ab58c06..c92b6f4 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_test02.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_test02.xml
@@ -23,12 +23,10 @@
android:viewportHeight="512"
android:viewportWidth="512" />
- <group>
- <path
- android:name="002b"
- android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0T-200,299"
- android:stroke="#FF0000FF"
- android:strokeWidth="4" />
- </group>
+ <path
+ android:name="002b"
+ android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0T-200,299"
+ android:stroke="#FF0000FF"
+ android:strokeWidth="4" />
</vector>
\ No newline at end of file
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index e0dab78..12d5389 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -3,8 +3,10 @@
//
#include "AaptAssets.h"
-#include "ResourceFilter.h"
+#include "AaptConfig.h"
+#include "AaptUtil.h"
#include "Main.h"
+#include "ResourceFilter.h"
#include <utils/misc.h>
#include <utils/SortedVector.h>
@@ -14,7 +16,6 @@
#include <errno.h>
static const char* kDefaultLocale = "default";
-static const char* kWildcardName = "any";
static const char* kAssetDir = "assets";
static const char* kResourceDir = "res";
static const char* kValuesDir = "values";
@@ -149,24 +150,6 @@
// =========================================================================
// =========================================================================
-/* static */ void AaptLocaleValue::splitAndLowerCase(const char* const chars,
- Vector<String8>* parts, const char separator) {
- const char *p = chars;
- const char *q;
- while (NULL != (q = strchr(p, separator))) {
- String8 val(p, q - p);
- val.toLower();
- parts->add(val);
- p = q+1;
- }
-
- if (p < chars + strlen(chars)) {
- String8 val(p);
- val.toLower();
- parts->add(val);
- }
-}
-
/* static */
inline bool isAlpha(const String8& string) {
const size_t length = string.length();
@@ -230,8 +213,7 @@
bool AaptLocaleValue::initFromFilterString(const String8& str) {
// A locale (as specified in the filter) is an underscore separated name such
// as "en_US", "en_Latn_US", or "en_US_POSIX".
- Vector<String8> parts;
- splitAndLowerCase(str.string(), &parts, '_');
+ Vector<String8> parts = AaptUtil::splitAndLowerCase(str, '_');
const int numTags = parts.size();
bool valid = false;
@@ -301,8 +283,7 @@
if (part[0] == 'b' && part[1] == '+') {
// This is a "modified" BCP-47 language tag. Same semantics as BCP-47 tags,
// except that the separator is "+" and not "-".
- Vector<String8> subtags;
- AaptLocaleValue::splitAndLowerCase(part.string(), &subtags, '+');
+ Vector<String8> subtags = AaptUtil::splitAndLowerCase(part, '+');
subtags.removeItemsAt(0);
if (subtags.size() == 1) {
setLanguage(subtags[0]);
@@ -438,1349 +419,46 @@
}
}
-
-/* static */ bool
-AaptGroupEntry::parseFilterNamePart(const String8& part, int* axis, AxisValue* value)
-{
- ResTable_config config;
- memset(&config, 0, sizeof(ResTable_config));
-
- // IMSI - MCC
- if (getMccName(part.string(), &config)) {
- *axis = AXIS_MCC;
- value->intValue = config.mcc;
- return true;
- }
-
- // IMSI - MNC
- if (getMncName(part.string(), &config)) {
- *axis = AXIS_MNC;
- value->intValue = config.mnc;
- return true;
- }
-
- // locale - language
- if (value->localeValue.initFromFilterString(part)) {
- *axis = AXIS_LOCALE;
- return true;
- }
-
- // layout direction
- if (getLayoutDirectionName(part.string(), &config)) {
- *axis = AXIS_LAYOUTDIR;
- value->intValue = (config.screenLayout&ResTable_config::MASK_LAYOUTDIR);
- return true;
- }
-
- // smallest screen dp width
- if (getSmallestScreenWidthDpName(part.string(), &config)) {
- *axis = AXIS_SMALLESTSCREENWIDTHDP;
- value->intValue = config.smallestScreenWidthDp;
- return true;
- }
-
- // screen dp width
- if (getScreenWidthDpName(part.string(), &config)) {
- *axis = AXIS_SCREENWIDTHDP;
- value->intValue = config.screenWidthDp;
- return true;
- }
-
- // screen dp height
- if (getScreenHeightDpName(part.string(), &config)) {
- *axis = AXIS_SCREENHEIGHTDP;
- value->intValue = config.screenHeightDp;
- return true;
- }
-
- // screen layout size
- if (getScreenLayoutSizeName(part.string(), &config)) {
- *axis = AXIS_SCREENLAYOUTSIZE;
- value->intValue = (config.screenLayout&ResTable_config::MASK_SCREENSIZE);
- return true;
- }
-
- // screen layout long
- if (getScreenLayoutLongName(part.string(), &config)) {
- *axis = AXIS_SCREENLAYOUTLONG;
- value->intValue = (config.screenLayout&ResTable_config::MASK_SCREENLONG);
- return true;
- }
-
- // orientation
- if (getOrientationName(part.string(), &config)) {
- *axis = AXIS_ORIENTATION;
- value->intValue = config.orientation;
- return true;
- }
-
- // ui mode type
- if (getUiModeTypeName(part.string(), &config)) {
- *axis = AXIS_UIMODETYPE;
- value->intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
- return true;
- }
-
- // ui mode night
- if (getUiModeNightName(part.string(), &config)) {
- *axis = AXIS_UIMODENIGHT;
- value->intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
- return true;
- }
-
- // density
- if (getDensityName(part.string(), &config)) {
- *axis = AXIS_DENSITY;
- value->intValue = config.density;
- return true;
- }
-
- // touchscreen
- if (getTouchscreenName(part.string(), &config)) {
- *axis = AXIS_TOUCHSCREEN;
- value->intValue = config.touchscreen;
- return true;
- }
-
- // keyboard hidden
- if (getKeysHiddenName(part.string(), &config)) {
- *axis = AXIS_KEYSHIDDEN;
- value->intValue = config.inputFlags;
- return true;
- }
-
- // keyboard
- if (getKeyboardName(part.string(), &config)) {
- *axis = AXIS_KEYBOARD;
- value->intValue = config.keyboard;
- return true;
- }
-
- // navigation hidden
- if (getNavHiddenName(part.string(), &config)) {
- *axis = AXIS_NAVHIDDEN;
- value->intValue = config.inputFlags;
- return 0;
- }
-
- // navigation
- if (getNavigationName(part.string(), &config)) {
- *axis = AXIS_NAVIGATION;
- value->intValue = config.navigation;
- return true;
- }
-
- // screen size
- if (getScreenSizeName(part.string(), &config)) {
- *axis = AXIS_SCREENSIZE;
- value->intValue = config.screenSize;
- return true;
- }
-
- // version
- if (getVersionName(part.string(), &config)) {
- *axis = AXIS_VERSION;
- value->intValue = config.version;
- return true;
- }
-
- return false;
-}
-
-AxisValue
-AaptGroupEntry::getConfigValueForAxis(const ResTable_config& config, int axis)
-{
- AxisValue value;
- switch (axis) {
- case AXIS_MCC:
- value.intValue = config.mcc;
- break;
- case AXIS_MNC:
- value.intValue = config.mnc;
- break;
- case AXIS_LOCALE:
- value.localeValue.initFromResTable(config);
- break;
- case AXIS_LAYOUTDIR:
- value.intValue = config.screenLayout&ResTable_config::MASK_LAYOUTDIR;
- break;
- case AXIS_SCREENLAYOUTSIZE:
- value.intValue = config.screenLayout&ResTable_config::MASK_SCREENSIZE;
- break;
- case AXIS_ORIENTATION:
- value.intValue = config.orientation;
- break;
- case AXIS_UIMODETYPE:
- value.intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
- break;
- case AXIS_UIMODENIGHT:
- value.intValue = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
- break;
- case AXIS_DENSITY:
- value.intValue = config.density;
- break;
- case AXIS_TOUCHSCREEN:
- value.intValue = config.touchscreen;
- break;
- case AXIS_KEYSHIDDEN:
- value.intValue = config.inputFlags;
- break;
- case AXIS_KEYBOARD:
- value.intValue = config.keyboard;
- break;
- case AXIS_NAVIGATION:
- value.intValue = config.navigation;
- break;
- case AXIS_SCREENSIZE:
- value.intValue = config.screenSize;
- break;
- case AXIS_SMALLESTSCREENWIDTHDP:
- value.intValue = config.smallestScreenWidthDp;
- break;
- case AXIS_SCREENWIDTHDP:
- value.intValue = config.screenWidthDp;
- break;
- case AXIS_SCREENHEIGHTDP:
- value.intValue = config.screenHeightDp;
- break;
- case AXIS_VERSION:
- value.intValue = config.version;
- break;
- }
-
- return value;
-}
-
-bool
-AaptGroupEntry::configSameExcept(const ResTable_config& config,
- const ResTable_config& otherConfig, int axis)
-{
- for (int i=AXIS_START; i<=AXIS_END; i++) {
- if (i == axis) {
- continue;
- }
- if (getConfigValueForAxis(config, i) != getConfigValueForAxis(otherConfig, i)) {
- return false;
- }
- }
- return true;
-}
-
bool
AaptGroupEntry::initFromDirName(const char* dir, String8* resType)
{
- mParamsChanged = true;
+ const char* q = strchr(dir, '-');
+ size_t typeLen;
+ if (q != NULL) {
+ typeLen = q - dir;
+ } else {
+ typeLen = strlen(dir);
+ }
- Vector<String8> parts;
- AaptLocaleValue::splitAndLowerCase(dir, &parts, '-');
-
- String8 mcc, mnc, layoutsize, layoutlong, orient, den;
- String8 touch, key, keysHidden, nav, navHidden, size, layoutDir, vers;
- String8 uiModeType, uiModeNight, smallestwidthdp, widthdp, heightdp;
-
- AaptLocaleValue locale;
- int numLocaleComponents = 0;
-
- const int N = parts.size();
- int index = 0;
- String8 part = parts[index];
-
- // resource type
- if (!isValidResourceType(part)) {
+ String8 type(dir, typeLen);
+ if (!isValidResourceType(type)) {
return false;
}
- *resType = part;
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
-
- // imsi - mcc
- if (getMccName(part.string())) {
- mcc = part;
-
- index++;
- if (index == N) {
- goto success;
+ if (q != NULL) {
+ if (!AaptConfig::parse(String8(q + 1), &mParams)) {
+ return false;
}
- part = parts[index];
- } else {
- //printf("not mcc: %s\n", part.string());
}
- // imsi - mnc
- if (getMncName(part.string())) {
- mnc = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not mnc: %s\n", part.string());
- }
-
- index = locale.initFromDirName(parts, index);
- if (index == -1) {
- return false;
- }
- if (index >= N){
- goto success;
- }
-
- part = parts[index];
- if (getLayoutDirectionName(part.string())) {
- layoutDir = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not layout direction: %s\n", part.string());
- }
-
- if (getSmallestScreenWidthDpName(part.string())) {
- smallestwidthdp = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not smallest screen width dp: %s\n", part.string());
- }
-
- if (getScreenWidthDpName(part.string())) {
- widthdp = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not screen width dp: %s\n", part.string());
- }
-
- if (getScreenHeightDpName(part.string())) {
- heightdp = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not screen height dp: %s\n", part.string());
- }
-
- if (getScreenLayoutSizeName(part.string())) {
- layoutsize = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not screen layout size: %s\n", part.string());
- }
-
- if (getScreenLayoutLongName(part.string())) {
- layoutlong = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not screen layout long: %s\n", part.string());
- }
-
- // orientation
- if (getOrientationName(part.string())) {
- orient = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not orientation: %s\n", part.string());
- }
-
- // ui mode type
- if (getUiModeTypeName(part.string())) {
- uiModeType = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not ui mode type: %s\n", part.string());
- }
-
- // ui mode night
- if (getUiModeNightName(part.string())) {
- uiModeNight = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not ui mode night: %s\n", part.string());
- }
-
- // density
- if (getDensityName(part.string())) {
- den = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not density: %s\n", part.string());
- }
-
- // touchscreen
- if (getTouchscreenName(part.string())) {
- touch = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not touchscreen: %s\n", part.string());
- }
-
- // keyboard hidden
- if (getKeysHiddenName(part.string())) {
- keysHidden = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not keysHidden: %s\n", part.string());
- }
-
- // keyboard
- if (getKeyboardName(part.string())) {
- key = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not keyboard: %s\n", part.string());
- }
-
- // navigation hidden
- if (getNavHiddenName(part.string())) {
- navHidden = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not navHidden: %s\n", part.string());
- }
-
- if (getNavigationName(part.string())) {
- nav = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not navigation: %s\n", part.string());
- }
-
- if (getScreenSizeName(part.string())) {
- size = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not screen size: %s\n", part.string());
- }
-
- if (getVersionName(part.string())) {
- vers = part;
-
- index++;
- if (index == N) {
- goto success;
- }
- part = parts[index];
- } else {
- //printf("not version: %s\n", part.string());
- }
-
- // if there are extra parts, it doesn't match
- return false;
-
-success:
- this->mcc = mcc;
- this->mnc = mnc;
- this->locale = locale;
- this->screenLayoutSize = layoutsize;
- this->screenLayoutLong = layoutlong;
- this->smallestScreenWidthDp = smallestwidthdp;
- this->screenWidthDp = widthdp;
- this->screenHeightDp = heightdp;
- this->orientation = orient;
- this->uiModeType = uiModeType;
- this->uiModeNight = uiModeNight;
- this->density = den;
- this->touchscreen = touch;
- this->keysHidden = keysHidden;
- this->keyboard = key;
- this->navHidden = navHidden;
- this->navigation = nav;
- this->screenSize = size;
- this->layoutDirection = layoutDir;
- this->version = vers;
-
- // what is this anyway?
- this->vendor = "";
-
+ *resType = type;
return true;
}
String8
-AaptGroupEntry::toString() const
-{
- String8 s = this->mcc;
- s += ",";
- s += this->mnc;
- s += ",";
- s += locale.toDirName();
- s += ",";
- s += layoutDirection;
- s += ",";
- s += smallestScreenWidthDp;
- s += ",";
- s += screenWidthDp;
- s += ",";
- s += screenHeightDp;
- s += ",";
- s += screenLayoutSize;
- s += ",";
- s += screenLayoutLong;
- s += ",";
- s += this->orientation;
- s += ",";
- s += uiModeType;
- s += ",";
- s += uiModeNight;
- s += ",";
- s += density;
- s += ",";
- s += touchscreen;
- s += ",";
- s += keysHidden;
- s += ",";
- s += keyboard;
- s += ",";
- s += navHidden;
- s += ",";
- s += navigation;
- s += ",";
- s += screenSize;
- s += ",";
- s += version;
- return s;
-}
-
-String8
AaptGroupEntry::toDirName(const String8& resType) const
{
String8 s = resType;
- if (this->mcc != "") {
+ String8 params = mParams.toString();
+ if (params.length() > 0) {
if (s.length() > 0) {
s += "-";
}
- s += mcc;
+ s += params;
}
- if (this->mnc != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += mnc;
- }
-
- const String8 localeComponent = locale.toDirName();
- if (localeComponent != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += localeComponent;
- }
-
- if (this->layoutDirection != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += layoutDirection;
- }
- if (this->smallestScreenWidthDp != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += smallestScreenWidthDp;
- }
- if (this->screenWidthDp != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += screenWidthDp;
- }
- if (this->screenHeightDp != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += screenHeightDp;
- }
- if (this->screenLayoutSize != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += screenLayoutSize;
- }
- if (this->screenLayoutLong != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += screenLayoutLong;
- }
- if (this->orientation != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += orientation;
- }
- if (this->uiModeType != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += uiModeType;
- }
- if (this->uiModeNight != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += uiModeNight;
- }
- if (this->density != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += density;
- }
- if (this->touchscreen != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += touchscreen;
- }
- if (this->keysHidden != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += keysHidden;
- }
- if (this->keyboard != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += keyboard;
- }
- if (this->navHidden != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += navHidden;
- }
- if (this->navigation != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += navigation;
- }
- if (this->screenSize != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += screenSize;
- }
- if (this->version != "") {
- if (s.length() > 0) {
- s += "-";
- }
- s += version;
- }
-
return s;
}
-bool AaptGroupEntry::getMccName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->mcc = 0;
- return true;
- }
- const char* c = name;
- if (tolower(*c) != 'm') return false;
- c++;
- if (tolower(*c) != 'c') return false;
- c++;
- if (tolower(*c) != 'c') return false;
- c++;
-
- const char* val = c;
-
- while (*c >= '0' && *c <= '9') {
- c++;
- }
- if (*c != 0) return false;
- if (c-val != 3) return false;
-
- int d = atoi(val);
- if (d != 0) {
- if (out) out->mcc = d;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getMncName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->mcc = 0;
- return true;
- }
- const char* c = name;
- if (tolower(*c) != 'm') return false;
- c++;
- if (tolower(*c) != 'n') return false;
- c++;
- if (tolower(*c) != 'c') return false;
- c++;
-
- const char* val = c;
-
- while (*c >= '0' && *c <= '9') {
- c++;
- }
- if (*c != 0) return false;
- if (c-val == 0 || c-val > 3) return false;
-
- if (out) {
- out->mnc = atoi(val);
- if (out->mnc == 0) {
- out->mnc = ACONFIGURATION_MNC_ZERO;
- }
- }
-
- return true;
-}
-
-bool AaptGroupEntry::getLayoutDirectionName(const char* name, ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
- | ResTable_config::LAYOUTDIR_ANY;
- return true;
- } else if (strcmp(name, "ldltr") == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
- | ResTable_config::LAYOUTDIR_LTR;
- return true;
- } else if (strcmp(name, "ldrtl") == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
- | ResTable_config::LAYOUTDIR_RTL;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getScreenLayoutSizeName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
- | ResTable_config::SCREENSIZE_ANY;
- return true;
- } else if (strcmp(name, "small") == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
- | ResTable_config::SCREENSIZE_SMALL;
- return true;
- } else if (strcmp(name, "normal") == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
- | ResTable_config::SCREENSIZE_NORMAL;
- return true;
- } else if (strcmp(name, "large") == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
- | ResTable_config::SCREENSIZE_LARGE;
- return true;
- } else if (strcmp(name, "xlarge") == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
- | ResTable_config::SCREENSIZE_XLARGE;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getScreenLayoutLongName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
- | ResTable_config::SCREENLONG_ANY;
- return true;
- } else if (strcmp(name, "long") == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
- | ResTable_config::SCREENLONG_YES;
- return true;
- } else if (strcmp(name, "notlong") == 0) {
- if (out) out->screenLayout =
- (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
- | ResTable_config::SCREENLONG_NO;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getOrientationName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->orientation = out->ORIENTATION_ANY;
- return true;
- } else if (strcmp(name, "port") == 0) {
- if (out) out->orientation = out->ORIENTATION_PORT;
- return true;
- } else if (strcmp(name, "land") == 0) {
- if (out) out->orientation = out->ORIENTATION_LAND;
- return true;
- } else if (strcmp(name, "square") == 0) {
- if (out) out->orientation = out->ORIENTATION_SQUARE;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getUiModeTypeName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
- | ResTable_config::UI_MODE_TYPE_ANY;
- return true;
- } else if (strcmp(name, "desk") == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
- | ResTable_config::UI_MODE_TYPE_DESK;
- return true;
- } else if (strcmp(name, "car") == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
- | ResTable_config::UI_MODE_TYPE_CAR;
- return true;
- } else if (strcmp(name, "television") == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
- | ResTable_config::UI_MODE_TYPE_TELEVISION;
- return true;
- } else if (strcmp(name, "appliance") == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
- | ResTable_config::UI_MODE_TYPE_APPLIANCE;
- return true;
- } else if (strcmp(name, "watch") == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
- | ResTable_config::UI_MODE_TYPE_WATCH;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getUiModeNightName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
- | ResTable_config::UI_MODE_NIGHT_ANY;
- return true;
- } else if (strcmp(name, "night") == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
- | ResTable_config::UI_MODE_NIGHT_YES;
- return true;
- } else if (strcmp(name, "notnight") == 0) {
- if (out) out->uiMode =
- (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
- | ResTable_config::UI_MODE_NIGHT_NO;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getDensityName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->density = ResTable_config::DENSITY_DEFAULT;
- return true;
- }
-
- if (strcmp(name, "nodpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_NONE;
- return true;
- }
-
- if (strcmp(name, "ldpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_LOW;
- return true;
- }
-
- if (strcmp(name, "mdpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_MEDIUM;
- return true;
- }
-
- if (strcmp(name, "tvdpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_TV;
- return true;
- }
-
- if (strcmp(name, "hdpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_HIGH;
- return true;
- }
-
- if (strcmp(name, "xhdpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_XHIGH;
- return true;
- }
-
- if (strcmp(name, "xxhdpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_XXHIGH;
- return true;
- }
-
- if (strcmp(name, "xxxhdpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
- return true;
- }
-
- char* c = (char*)name;
- while (*c >= '0' && *c <= '9') {
- c++;
- }
-
- // check that we have 'dpi' after the last digit.
- if (toupper(c[0]) != 'D' ||
- toupper(c[1]) != 'P' ||
- toupper(c[2]) != 'I' ||
- c[3] != 0) {
- return false;
- }
-
- // temporarily replace the first letter with \0 to
- // use atoi.
- char tmp = c[0];
- c[0] = '\0';
-
- int d = atoi(name);
- c[0] = tmp;
-
- if (d != 0) {
- if (out) out->density = d;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getTouchscreenName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
- return true;
- } else if (strcmp(name, "notouch") == 0) {
- if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
- return true;
- } else if (strcmp(name, "stylus") == 0) {
- if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
- return true;
- } else if (strcmp(name, "finger") == 0) {
- if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getKeysHiddenName(const char* name,
- ResTable_config* out)
-{
- uint8_t mask = 0;
- uint8_t value = 0;
- if (strcmp(name, kWildcardName) == 0) {
- mask = ResTable_config::MASK_KEYSHIDDEN;
- value = ResTable_config::KEYSHIDDEN_ANY;
- } else if (strcmp(name, "keysexposed") == 0) {
- mask = ResTable_config::MASK_KEYSHIDDEN;
- value = ResTable_config::KEYSHIDDEN_NO;
- } else if (strcmp(name, "keyshidden") == 0) {
- mask = ResTable_config::MASK_KEYSHIDDEN;
- value = ResTable_config::KEYSHIDDEN_YES;
- } else if (strcmp(name, "keyssoft") == 0) {
- mask = ResTable_config::MASK_KEYSHIDDEN;
- value = ResTable_config::KEYSHIDDEN_SOFT;
- }
-
- if (mask != 0) {
- if (out) out->inputFlags = (out->inputFlags&~mask) | value;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getKeyboardName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->keyboard = out->KEYBOARD_ANY;
- return true;
- } else if (strcmp(name, "nokeys") == 0) {
- if (out) out->keyboard = out->KEYBOARD_NOKEYS;
- return true;
- } else if (strcmp(name, "qwerty") == 0) {
- if (out) out->keyboard = out->KEYBOARD_QWERTY;
- return true;
- } else if (strcmp(name, "12key") == 0) {
- if (out) out->keyboard = out->KEYBOARD_12KEY;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getNavHiddenName(const char* name,
- ResTable_config* out)
-{
- uint8_t mask = 0;
- uint8_t value = 0;
- if (strcmp(name, kWildcardName) == 0) {
- mask = ResTable_config::MASK_NAVHIDDEN;
- value = ResTable_config::NAVHIDDEN_ANY;
- } else if (strcmp(name, "navexposed") == 0) {
- mask = ResTable_config::MASK_NAVHIDDEN;
- value = ResTable_config::NAVHIDDEN_NO;
- } else if (strcmp(name, "navhidden") == 0) {
- mask = ResTable_config::MASK_NAVHIDDEN;
- value = ResTable_config::NAVHIDDEN_YES;
- }
-
- if (mask != 0) {
- if (out) out->inputFlags = (out->inputFlags&~mask) | value;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getNavigationName(const char* name,
- ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) out->navigation = out->NAVIGATION_ANY;
- return true;
- } else if (strcmp(name, "nonav") == 0) {
- if (out) out->navigation = out->NAVIGATION_NONAV;
- return true;
- } else if (strcmp(name, "dpad") == 0) {
- if (out) out->navigation = out->NAVIGATION_DPAD;
- return true;
- } else if (strcmp(name, "trackball") == 0) {
- if (out) out->navigation = out->NAVIGATION_TRACKBALL;
- return true;
- } else if (strcmp(name, "wheel") == 0) {
- if (out) out->navigation = out->NAVIGATION_WHEEL;
- return true;
- }
-
- return false;
-}
-
-bool AaptGroupEntry::getScreenSizeName(const char* name, ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) {
- out->screenWidth = out->SCREENWIDTH_ANY;
- out->screenHeight = out->SCREENHEIGHT_ANY;
- }
- return true;
- }
-
- const char* x = name;
- while (*x >= '0' && *x <= '9') x++;
- if (x == name || *x != 'x') return false;
- String8 xName(name, x-name);
- x++;
-
- const char* y = x;
- while (*y >= '0' && *y <= '9') y++;
- if (y == name || *y != 0) return false;
- String8 yName(x, y-x);
-
- uint16_t w = (uint16_t)atoi(xName.string());
- uint16_t h = (uint16_t)atoi(yName.string());
- if (w < h) {
- return false;
- }
-
- if (out) {
- out->screenWidth = w;
- out->screenHeight = h;
- }
-
- return true;
-}
-
-bool AaptGroupEntry::getSmallestScreenWidthDpName(const char* name, ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) {
- out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
- }
- return true;
- }
-
- if (*name != 's') return false;
- name++;
- if (*name != 'w') return false;
- name++;
- const char* x = name;
- while (*x >= '0' && *x <= '9') x++;
- if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
- String8 xName(name, x-name);
-
- if (out) {
- out->smallestScreenWidthDp = (uint16_t)atoi(xName.string());
- }
-
- return true;
-}
-
-bool AaptGroupEntry::getScreenWidthDpName(const char* name, ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) {
- out->screenWidthDp = out->SCREENWIDTH_ANY;
- }
- return true;
- }
-
- if (*name != 'w') return false;
- name++;
- const char* x = name;
- while (*x >= '0' && *x <= '9') x++;
- if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
- String8 xName(name, x-name);
-
- if (out) {
- out->screenWidthDp = (uint16_t)atoi(xName.string());
- }
-
- return true;
-}
-
-bool AaptGroupEntry::getScreenHeightDpName(const char* name, ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) {
- out->screenHeightDp = out->SCREENWIDTH_ANY;
- }
- return true;
- }
-
- if (*name != 'h') return false;
- name++;
- const char* x = name;
- while (*x >= '0' && *x <= '9') x++;
- if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
- String8 xName(name, x-name);
-
- if (out) {
- out->screenHeightDp = (uint16_t)atoi(xName.string());
- }
-
- return true;
-}
-
-bool AaptGroupEntry::getVersionName(const char* name, ResTable_config* out)
-{
- if (strcmp(name, kWildcardName) == 0) {
- if (out) {
- out->sdkVersion = out->SDKVERSION_ANY;
- out->minorVersion = out->MINORVERSION_ANY;
- }
- return true;
- }
-
- if (*name != 'v') {
- return false;
- }
-
- name++;
- const char* s = name;
- while (*s >= '0' && *s <= '9') s++;
- if (s == name || *s != 0) return false;
- String8 sdkName(name, s-name);
-
- if (out) {
- out->sdkVersion = (uint16_t)atoi(sdkName.string());
- out->minorVersion = 0;
- }
-
- return true;
-}
-
-int AaptGroupEntry::compare(const AaptGroupEntry& o) const
-{
- int v = mcc.compare(o.mcc);
- if (v == 0) v = mnc.compare(o.mnc);
- if (v == 0) v = locale.compare(o.locale);
- if (v == 0) v = layoutDirection.compare(o.layoutDirection);
- if (v == 0) v = vendor.compare(o.vendor);
- if (v == 0) v = smallestScreenWidthDp.compare(o.smallestScreenWidthDp);
- if (v == 0) v = screenWidthDp.compare(o.screenWidthDp);
- if (v == 0) v = screenHeightDp.compare(o.screenHeightDp);
- if (v == 0) v = screenLayoutSize.compare(o.screenLayoutSize);
- if (v == 0) v = screenLayoutLong.compare(o.screenLayoutLong);
- if (v == 0) v = orientation.compare(o.orientation);
- if (v == 0) v = uiModeType.compare(o.uiModeType);
- if (v == 0) v = uiModeNight.compare(o.uiModeNight);
- if (v == 0) v = density.compare(o.density);
- if (v == 0) v = touchscreen.compare(o.touchscreen);
- if (v == 0) v = keysHidden.compare(o.keysHidden);
- if (v == 0) v = keyboard.compare(o.keyboard);
- if (v == 0) v = navHidden.compare(o.navHidden);
- if (v == 0) v = navigation.compare(o.navigation);
- if (v == 0) v = screenSize.compare(o.screenSize);
- if (v == 0) v = version.compare(o.version);
- return v;
-}
-
-const ResTable_config AaptGroupEntry::toParams() const
-{
- if (!mParamsChanged) {
- return mParams;
- }
-
- mParamsChanged = false;
- ResTable_config& params = mParams;
- memset(¶ms, 0, sizeof(ResTable_config));
- getMccName(mcc.string(), ¶ms);
- getMncName(mnc.string(), ¶ms);
- locale.writeTo(¶ms);
- getLayoutDirectionName(layoutDirection.string(), ¶ms);
- getSmallestScreenWidthDpName(smallestScreenWidthDp.string(), ¶ms);
- getScreenWidthDpName(screenWidthDp.string(), ¶ms);
- getScreenHeightDpName(screenHeightDp.string(), ¶ms);
- getScreenLayoutSizeName(screenLayoutSize.string(), ¶ms);
- getScreenLayoutLongName(screenLayoutLong.string(), ¶ms);
- getOrientationName(orientation.string(), ¶ms);
- getUiModeTypeName(uiModeType.string(), ¶ms);
- getUiModeNightName(uiModeNight.string(), ¶ms);
- getDensityName(density.string(), ¶ms);
- getTouchscreenName(touchscreen.string(), ¶ms);
- getKeysHiddenName(keysHidden.string(), ¶ms);
- getKeyboardName(keyboard.string(), ¶ms);
- getNavHiddenName(navHidden.string(), ¶ms);
- getNavigationName(navigation.string(), ¶ms);
- getScreenSizeName(screenSize.string(), ¶ms);
- getVersionName(version.string(), ¶ms);
-
- // Fix up version number based on specified parameters.
- int minSdk = 0;
- if (params.smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
- || params.screenWidthDp != ResTable_config::SCREENWIDTH_ANY
- || params.screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
- minSdk = SDK_HONEYCOMB_MR2;
- } else if ((params.uiMode&ResTable_config::MASK_UI_MODE_TYPE)
- != ResTable_config::UI_MODE_TYPE_ANY
- || (params.uiMode&ResTable_config::MASK_UI_MODE_NIGHT)
- != ResTable_config::UI_MODE_NIGHT_ANY) {
- minSdk = SDK_FROYO;
- } else if ((params.screenLayout&ResTable_config::MASK_SCREENSIZE)
- != ResTable_config::SCREENSIZE_ANY
- || (params.screenLayout&ResTable_config::MASK_SCREENLONG)
- != ResTable_config::SCREENLONG_ANY
- || params.density != ResTable_config::DENSITY_DEFAULT) {
- minSdk = SDK_DONUT;
- }
-
- if (minSdk > params.sdkVersion) {
- params.sdkVersion = minSdk;
- }
-
- return params;
-}
// =========================================================================
// =========================================================================
@@ -2229,9 +907,7 @@
: AaptDir(String8(), String8()),
mHavePrivateSymbols(false),
mChanged(false), mHaveIncludedAssets(false),
- mRes(NULL)
-{
-}
+ mRes(NULL) {}
const SortedVector<AaptGroupEntry>& AaptAssets::getGroupEntries() const {
if (mChanged) {
@@ -2506,7 +1182,7 @@
String8 resType;
bool b = group.initFromDirName(entry->d_name, &resType);
if (!b) {
- fprintf(stderr, "invalid resource directory name: %s/%s\n", srcDir.string(),
+ fprintf(stderr, "invalid resource directory name: %s %s\n", srcDir.string(),
entry->d_name);
err = -1;
continue;
@@ -2654,30 +1330,35 @@
status_t AaptAssets::filter(Bundle* bundle)
{
- ResourceFilter reqFilter;
+ WeakResourceFilter reqFilter;
status_t err = reqFilter.parse(bundle->getConfigurations());
if (err != NO_ERROR) {
return err;
}
- ResourceFilter prefFilter;
- err = prefFilter.parse(bundle->getPreferredConfigurations());
- if (err != NO_ERROR) {
- return err;
+ uint32_t preferredDensity = 0;
+ if (bundle->getPreferredDensity().size() > 0) {
+ ResTable_config preferredConfig;
+ if (!AaptConfig::parseDensity(bundle->getPreferredDensity().string(), &preferredConfig)) {
+ fprintf(stderr, "Error parsing preferred density: %s\n",
+ bundle->getPreferredDensity().string());
+ return UNKNOWN_ERROR;
+ }
+ preferredDensity = preferredConfig.density;
}
- if (reqFilter.isEmpty() && prefFilter.isEmpty()) {
+ if (reqFilter.isEmpty() && preferredDensity == 0) {
return NO_ERROR;
}
if (bundle->getVerbose()) {
if (!reqFilter.isEmpty()) {
printf("Applying required filter: %s\n",
- bundle->getConfigurations());
+ bundle->getConfigurations().string());
}
- if (!prefFilter.isEmpty()) {
- printf("Applying preferred filter: %s\n",
- bundle->getPreferredConfigurations());
+ if (preferredDensity > 0) {
+ printf("Applying preferred density filter: %s\n",
+ bundle->getPreferredDensity().string());
}
}
@@ -2734,89 +1415,71 @@
}
// Quick check: no preferred filters, nothing more to do.
- if (prefFilter.isEmpty()) {
+ if (preferredDensity == 0) {
continue;
}
// Get the preferred density if there is one. We do not match exactly for density.
// If our preferred density is hdpi but we only have mdpi and xhdpi resources, we
// pick xhdpi.
- uint32_t preferredDensity = 0;
- const SortedVector<AxisValue>* preferredConfigs = prefFilter.configsForAxis(AXIS_DENSITY);
- if (preferredConfigs != NULL && preferredConfigs->size() > 0) {
- preferredDensity = (*preferredConfigs)[0].intValue;
- }
+ for (size_t k=0; k<grp->getFiles().size(); k++) {
+ sp<AaptFile> file = grp->getFiles().valueAt(k);
+ if (k == 0 && grp->getFiles().size() == 1) {
+ // If this is the only file left, we need to keep it.
+ // Otherwise the resource IDs we are using will be inconsistent
+ // with what we get when not stripping. Sucky, but at least
+ // for now we can rely on the back-end doing another filtering
+ // pass to take this out and leave us with this resource name
+ // containing no entries.
+ continue;
+ }
+ if (file->getPath().getPathExtension() == ".xml") {
+ // We can't remove .xml files at this point, because when
+ // we parse them they may add identifier resources, so
+ // removing them can cause our resource identifiers to
+ // become inconsistent.
+ continue;
+ }
+ const ResTable_config& config(file->getGroupEntry().toParams());
+ if (config.density != 0 && config.density != preferredDensity) {
+ // This is a resource we would prefer not to have. Check
+ // to see if have a similar variation that we would like
+ // to have and, if so, we can drop it.
+ uint32_t bestDensity = config.density;
- // Now deal with preferred configurations.
- for (int axis=AXIS_START; axis<=AXIS_END; axis++) {
- for (size_t k=0; k<grp->getFiles().size(); k++) {
- sp<AaptFile> file = grp->getFiles().valueAt(k);
- if (k == 0 && grp->getFiles().size() == 1) {
- // If this is the only file left, we need to keep it.
- // Otherwise the resource IDs we are using will be inconsistent
- // with what we get when not stripping. Sucky, but at least
- // for now we can rely on the back-end doing another filtering
- // pass to take this out and leave us with this resource name
- // containing no entries.
- continue;
- }
- if (file->getPath().getPathExtension() == ".xml") {
- // We can't remove .xml files at this point, because when
- // we parse them they may add identifier resources, so
- // removing them can cause our resource identifiers to
- // become inconsistent.
- continue;
- }
- const ResTable_config& config(file->getGroupEntry().toParams());
- if (!prefFilter.match(axis, config)) {
- // This is a resource we would prefer not to have. Check
- // to see if have a similar variation that we would like
- // to have and, if so, we can drop it.
-
- uint32_t bestDensity = config.density;
-
- for (size_t m=0; m<grp->getFiles().size(); m++) {
- if (m == k) continue;
- sp<AaptFile> mfile = grp->getFiles().valueAt(m);
- const ResTable_config& mconfig(mfile->getGroupEntry().toParams());
- if (AaptGroupEntry::configSameExcept(config, mconfig, axis)) {
- if (axis == AXIS_DENSITY && preferredDensity > 0) {
- // See if there is a better density resource
- if (mconfig.density < bestDensity &&
- mconfig.density > preferredDensity &&
- bestDensity > preferredDensity) {
- // This density is between our best density and
- // the preferred density, therefore it is better.
- bestDensity = mconfig.density;
- } else if (mconfig.density > bestDensity &&
- bestDensity < preferredDensity) {
- // This density is better than our best density and
- // our best density was smaller than our preferred
- // density, so it is better.
- bestDensity = mconfig.density;
- }
- } else if (prefFilter.match(axis, mconfig)) {
- if (bundle->getVerbose()) {
- printf("Pruning unneeded resource: %s\n",
- file->getPrintableSource().string());
- }
- grp->removeFile(k);
- k--;
- break;
- }
- }
+ for (size_t m=0; m<grp->getFiles().size(); m++) {
+ if (m == k) {
+ continue;
}
- if (axis == AXIS_DENSITY && preferredDensity > 0 &&
- bestDensity != config.density) {
- if (bundle->getVerbose()) {
- printf("Pruning unneeded resource: %s\n",
- file->getPrintableSource().string());
+ sp<AaptFile> mfile = grp->getFiles().valueAt(m);
+ const ResTable_config& mconfig(mfile->getGroupEntry().toParams());
+ if (AaptConfig::isSameExcept(config, mconfig, ResTable_config::CONFIG_DENSITY)) {
+ // See if there is a better density resource
+ if (mconfig.density < bestDensity &&
+ mconfig.density > preferredDensity &&
+ bestDensity > preferredDensity) {
+ // This density is between our best density and
+ // the preferred density, therefore it is better.
+ bestDensity = mconfig.density;
+ } else if (mconfig.density > bestDensity &&
+ bestDensity < preferredDensity) {
+ // This density is better than our best density and
+ // our best density was smaller than our preferred
+ // density, so it is better.
+ bestDensity = mconfig.density;
}
- grp->removeFile(k);
- k--;
}
}
+
+ if (bestDensity != config.density) {
+ if (bundle->getVerbose()) {
+ printf("Pruning unneeded resource: %s\n",
+ file->getPrintableSource().string());
+ }
+ grp->removeFile(k);
+ k--;
+ }
}
}
}
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 82dda5f..0c2576a 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -6,22 +6,24 @@
#ifndef __AAPT_ASSETS_H
#define __AAPT_ASSETS_H
-#include <stdlib.h>
#include <androidfw/AssetManager.h>
#include <androidfw/ResourceTypes.h>
+#include <stdlib.h>
+#include <set>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
#include <utils/Vector.h>
+
+#include "AaptConfig.h"
+#include "Bundle.h"
+#include "ConfigDescription.h"
+#include "SourcePos.h"
#include "ZipFile.h"
-#include "Bundle.h"
-#include "SourcePos.h"
-
using namespace android;
-
extern const char * const gDefaultIgnoreAssets;
extern const char * gUserIgnoreAssets;
@@ -82,9 +84,6 @@
return memcmp(this, &other, sizeof(AaptLocaleValue));
}
- static void splitAndLowerCase(const char* const chars, Vector<String8>* parts,
- const char separator);
-
inline bool operator<(const AaptLocaleValue& o) const { return compare(o) < 0; }
inline bool operator<=(const AaptLocaleValue& o) const { return compare(o) <= 0; }
inline bool operator==(const AaptLocaleValue& o) const { return compare(o) == 0; }
@@ -98,31 +97,6 @@
void setVariant(const char* variant);
};
-struct AxisValue {
- // Used for all axes except AXIS_LOCALE, which is represented
- // as a AaptLocaleValue value.
- int intValue;
- AaptLocaleValue localeValue;
-
- AxisValue() : intValue(0) {
- }
-
- inline int compare(const AxisValue &other) const {
- if (intValue != other.intValue) {
- return intValue - other.intValue;
- }
-
- return localeValue.compare(other.localeValue);
- }
-
- inline bool operator<(const AxisValue& o) const { return compare(o) < 0; }
- inline bool operator<=(const AxisValue& o) const { return compare(o) <= 0; }
- inline bool operator==(const AxisValue& o) const { return compare(o) == 0; }
- inline bool operator!=(const AxisValue& o) const { return compare(o) != 0; }
- inline bool operator>=(const AxisValue& o) const { return compare(o) >= 0; }
- inline bool operator>(const AxisValue& o) const { return compare(o) > 0; }
-};
-
/**
* This structure contains a specific variation of a single file out
* of all the variations it can have that we can have.
@@ -130,23 +104,11 @@
struct AaptGroupEntry
{
public:
- AaptGroupEntry() : mParamsChanged(true) {
- memset(&mParams, 0, sizeof(ResTable_config));
- }
-
bool initFromDirName(const char* dir, String8* resType);
- static bool parseFilterNamePart(const String8& part, int* axis, AxisValue* value);
+ inline const ConfigDescription& toParams() const { return mParams; }
- static AxisValue getConfigValueForAxis(const ResTable_config& config, int axis);
-
- static bool configSameExcept(const ResTable_config& config,
- const ResTable_config& otherConfig, int axis);
-
- int compare(const AaptGroupEntry& o) const;
-
- const ResTable_config toParams() const;
-
+ inline int compare(const AaptGroupEntry& o) const { return mParams.compareLogical(o.mParams); }
inline bool operator<(const AaptGroupEntry& o) const { return compare(o) < 0; }
inline bool operator<=(const AaptGroupEntry& o) const { return compare(o) <= 0; }
inline bool operator==(const AaptGroupEntry& o) const { return compare(o) == 0; }
@@ -154,56 +116,13 @@
inline bool operator>=(const AaptGroupEntry& o) const { return compare(o) >= 0; }
inline bool operator>(const AaptGroupEntry& o) const { return compare(o) > 0; }
- String8 toString() const;
+ String8 toString() const { return mParams.toString(); }
String8 toDirName(const String8& resType) const;
- const String8& getVersionString() const { return version; }
+ const String8 getVersionString() const { return AaptConfig::getVersion(mParams); }
private:
- static bool getMccName(const char* name, ResTable_config* out = NULL);
- static bool getMncName(const char* name, ResTable_config* out = NULL);
- static bool getScreenLayoutSizeName(const char* name, ResTable_config* out = NULL);
- static bool getScreenLayoutLongName(const char* name, ResTable_config* out = NULL);
- static bool getOrientationName(const char* name, ResTable_config* out = NULL);
- static bool getUiModeTypeName(const char* name, ResTable_config* out = NULL);
- static bool getUiModeNightName(const char* name, ResTable_config* out = NULL);
- static bool getDensityName(const char* name, ResTable_config* out = NULL);
- static bool getTouchscreenName(const char* name, ResTable_config* out = NULL);
- static bool getKeysHiddenName(const char* name, ResTable_config* out = NULL);
- static bool getKeyboardName(const char* name, ResTable_config* out = NULL);
- static bool getNavigationName(const char* name, ResTable_config* out = NULL);
- static bool getNavHiddenName(const char* name, ResTable_config* out = NULL);
- static bool getScreenSizeName(const char* name, ResTable_config* out = NULL);
- static bool getSmallestScreenWidthDpName(const char* name, ResTable_config* out = NULL);
- static bool getScreenWidthDpName(const char* name, ResTable_config* out = NULL);
- static bool getScreenHeightDpName(const char* name, ResTable_config* out = NULL);
- static bool getLayoutDirectionName(const char* name, ResTable_config* out = NULL);
- static bool getVersionName(const char* name, ResTable_config* out = NULL);
-
- String8 mcc;
- String8 mnc;
- AaptLocaleValue locale;
- String8 vendor;
- String8 smallestScreenWidthDp;
- String8 screenWidthDp;
- String8 screenHeightDp;
- String8 screenLayoutSize;
- String8 screenLayoutLong;
- String8 orientation;
- String8 uiModeType;
- String8 uiModeNight;
- String8 density;
- String8 touchscreen;
- String8 keysHidden;
- String8 keyboard;
- String8 navHidden;
- String8 navigation;
- String8 screenSize;
- String8 layoutDirection;
- String8 version;
-
- mutable bool mParamsChanged;
- mutable ResTable_config mParams;
+ ConfigDescription mParams;
};
inline int compare_type(const AaptGroupEntry& lhs, const AaptGroupEntry& rhs)
diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp
new file mode 100644
index 0000000..69a9c7f
--- /dev/null
+++ b/tools/aapt/AaptConfig.cpp
@@ -0,0 +1,790 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <androidfw/ResourceTypes.h>
+#include <ctype.h>
+
+#include "AaptConfig.h"
+#include "AaptAssets.h"
+#include "AaptUtil.h"
+#include "ResourceFilter.h"
+
+using android::String8;
+using android::Vector;
+using android::ResTable_config;
+
+namespace AaptConfig {
+
+static const char* kWildcardName = "any";
+
+bool parse(const String8& str, ConfigDescription* out) {
+ Vector<String8> parts = AaptUtil::splitAndLowerCase(str, '-');
+
+ ConfigDescription config;
+ AaptLocaleValue locale;
+ ssize_t index = 0;
+ ssize_t localeIndex = 0;
+ const ssize_t N = parts.size();
+ const char* part = parts[index].string();
+
+ if (str.length() == 0) {
+ goto success;
+ }
+
+ if (parseMcc(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseMnc(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ // Locale spans a few '-' separators, so we let it
+ // control the index.
+ localeIndex = locale.initFromDirName(parts, index);
+ if (localeIndex < 0) {
+ return false;
+ } else if (localeIndex > index) {
+ locale.writeTo(&config);
+ index = localeIndex;
+ if (index >= N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseLayoutDirection(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseSmallestScreenWidthDp(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseScreenWidthDp(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseScreenHeightDp(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseScreenLayoutSize(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseScreenLayoutLong(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseOrientation(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseUiModeType(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseUiModeNight(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseDensity(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseTouchscreen(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseKeysHidden(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseKeyboard(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseNavHidden(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseNavigation(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseScreenSize(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ if (parseVersion(part, &config)) {
+ index++;
+ if (index == N) {
+ goto success;
+ }
+ part = parts[index].string();
+ }
+
+ // Unrecognized.
+ return false;
+
+success:
+ if (out != NULL) {
+ applyVersionForCompatibility(&config);
+ *out = config;
+ }
+ return true;
+}
+
+bool parseCommaSeparatedList(const String8& str, std::set<ConfigDescription>* outSet) {
+ Vector<String8> parts = AaptUtil::splitAndLowerCase(str, ',');
+ const size_t N = parts.size();
+ for (size_t i = 0; i < N; i++) {
+ ConfigDescription config;
+ if (!parse(parts[i], &config)) {
+ return false;
+ }
+ outSet->insert(config);
+ }
+ return true;
+}
+
+void applyVersionForCompatibility(ConfigDescription* config) {
+ if (config == NULL) {
+ return;
+ }
+
+ uint16_t minSdk = 0;
+ if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
+ || config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY
+ || config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
+ minSdk = SDK_HONEYCOMB_MR2;
+ } else if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
+ != ResTable_config::UI_MODE_TYPE_ANY
+ || (config->uiMode & ResTable_config::MASK_UI_MODE_NIGHT)
+ != ResTable_config::UI_MODE_NIGHT_ANY) {
+ minSdk = SDK_FROYO;
+ } else if ((config->screenLayout & ResTable_config::MASK_SCREENSIZE)
+ != ResTable_config::SCREENSIZE_ANY
+ || (config->screenLayout & ResTable_config::MASK_SCREENLONG)
+ != ResTable_config::SCREENLONG_ANY
+ || config->density != ResTable_config::DENSITY_DEFAULT) {
+ minSdk = SDK_DONUT;
+ }
+
+ if (minSdk > config->sdkVersion) {
+ config->sdkVersion = minSdk;
+ }
+}
+
+bool parseMcc(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->mcc = 0;
+ return true;
+ }
+ const char* c = name;
+ if (tolower(*c) != 'm') return false;
+ c++;
+ if (tolower(*c) != 'c') return false;
+ c++;
+ if (tolower(*c) != 'c') return false;
+ c++;
+
+ const char* val = c;
+
+ while (*c >= '0' && *c <= '9') {
+ c++;
+ }
+ if (*c != 0) return false;
+ if (c-val != 3) return false;
+
+ int d = atoi(val);
+ if (d != 0) {
+ if (out) out->mcc = d;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseMnc(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->mcc = 0;
+ return true;
+ }
+ const char* c = name;
+ if (tolower(*c) != 'm') return false;
+ c++;
+ if (tolower(*c) != 'n') return false;
+ c++;
+ if (tolower(*c) != 'c') return false;
+ c++;
+
+ const char* val = c;
+
+ while (*c >= '0' && *c <= '9') {
+ c++;
+ }
+ if (*c != 0) return false;
+ if (c-val == 0 || c-val > 3) return false;
+
+ if (out) {
+ out->mnc = atoi(val);
+ if (out->mnc == 0) {
+ out->mnc = ACONFIGURATION_MNC_ZERO;
+ }
+ }
+
+ return true;
+}
+
+bool parseLayoutDirection(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
+ | ResTable_config::LAYOUTDIR_ANY;
+ return true;
+ } else if (strcmp(name, "ldltr") == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
+ | ResTable_config::LAYOUTDIR_LTR;
+ return true;
+ } else if (strcmp(name, "ldrtl") == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
+ | ResTable_config::LAYOUTDIR_RTL;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseScreenLayoutSize(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+ | ResTable_config::SCREENSIZE_ANY;
+ return true;
+ } else if (strcmp(name, "small") == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+ | ResTable_config::SCREENSIZE_SMALL;
+ return true;
+ } else if (strcmp(name, "normal") == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+ | ResTable_config::SCREENSIZE_NORMAL;
+ return true;
+ } else if (strcmp(name, "large") == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+ | ResTable_config::SCREENSIZE_LARGE;
+ return true;
+ } else if (strcmp(name, "xlarge") == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+ | ResTable_config::SCREENSIZE_XLARGE;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseScreenLayoutLong(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
+ | ResTable_config::SCREENLONG_ANY;
+ return true;
+ } else if (strcmp(name, "long") == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
+ | ResTable_config::SCREENLONG_YES;
+ return true;
+ } else if (strcmp(name, "notlong") == 0) {
+ if (out) out->screenLayout =
+ (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
+ | ResTable_config::SCREENLONG_NO;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseOrientation(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->orientation = out->ORIENTATION_ANY;
+ return true;
+ } else if (strcmp(name, "port") == 0) {
+ if (out) out->orientation = out->ORIENTATION_PORT;
+ return true;
+ } else if (strcmp(name, "land") == 0) {
+ if (out) out->orientation = out->ORIENTATION_LAND;
+ return true;
+ } else if (strcmp(name, "square") == 0) {
+ if (out) out->orientation = out->ORIENTATION_SQUARE;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseUiModeType(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+ | ResTable_config::UI_MODE_TYPE_ANY;
+ return true;
+ } else if (strcmp(name, "desk") == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+ | ResTable_config::UI_MODE_TYPE_DESK;
+ return true;
+ } else if (strcmp(name, "car") == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+ | ResTable_config::UI_MODE_TYPE_CAR;
+ return true;
+ } else if (strcmp(name, "television") == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+ | ResTable_config::UI_MODE_TYPE_TELEVISION;
+ return true;
+ } else if (strcmp(name, "appliance") == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+ | ResTable_config::UI_MODE_TYPE_APPLIANCE;
+ return true;
+ } else if (strcmp(name, "watch") == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+ | ResTable_config::UI_MODE_TYPE_WATCH;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseUiModeNight(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
+ | ResTable_config::UI_MODE_NIGHT_ANY;
+ return true;
+ } else if (strcmp(name, "night") == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
+ | ResTable_config::UI_MODE_NIGHT_YES;
+ return true;
+ } else if (strcmp(name, "notnight") == 0) {
+ if (out) out->uiMode =
+ (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
+ | ResTable_config::UI_MODE_NIGHT_NO;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseDensity(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->density = ResTable_config::DENSITY_DEFAULT;
+ return true;
+ }
+
+ if (strcmp(name, "nodpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_NONE;
+ return true;
+ }
+
+ if (strcmp(name, "ldpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_LOW;
+ return true;
+ }
+
+ if (strcmp(name, "mdpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_MEDIUM;
+ return true;
+ }
+
+ if (strcmp(name, "tvdpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_TV;
+ return true;
+ }
+
+ if (strcmp(name, "hdpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_HIGH;
+ return true;
+ }
+
+ if (strcmp(name, "xhdpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_XHIGH;
+ return true;
+ }
+
+ if (strcmp(name, "xxhdpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_XXHIGH;
+ return true;
+ }
+
+ if (strcmp(name, "xxxhdpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
+ return true;
+ }
+
+ char* c = (char*)name;
+ while (*c >= '0' && *c <= '9') {
+ c++;
+ }
+
+ // check that we have 'dpi' after the last digit.
+ if (toupper(c[0]) != 'D' ||
+ toupper(c[1]) != 'P' ||
+ toupper(c[2]) != 'I' ||
+ c[3] != 0) {
+ return false;
+ }
+
+ // temporarily replace the first letter with \0 to
+ // use atoi.
+ char tmp = c[0];
+ c[0] = '\0';
+
+ int d = atoi(name);
+ c[0] = tmp;
+
+ if (d != 0) {
+ if (out) out->density = d;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseTouchscreen(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
+ return true;
+ } else if (strcmp(name, "notouch") == 0) {
+ if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
+ return true;
+ } else if (strcmp(name, "stylus") == 0) {
+ if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
+ return true;
+ } else if (strcmp(name, "finger") == 0) {
+ if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseKeysHidden(const char* name, ResTable_config* out) {
+ uint8_t mask = 0;
+ uint8_t value = 0;
+ if (strcmp(name, kWildcardName) == 0) {
+ mask = ResTable_config::MASK_KEYSHIDDEN;
+ value = ResTable_config::KEYSHIDDEN_ANY;
+ } else if (strcmp(name, "keysexposed") == 0) {
+ mask = ResTable_config::MASK_KEYSHIDDEN;
+ value = ResTable_config::KEYSHIDDEN_NO;
+ } else if (strcmp(name, "keyshidden") == 0) {
+ mask = ResTable_config::MASK_KEYSHIDDEN;
+ value = ResTable_config::KEYSHIDDEN_YES;
+ } else if (strcmp(name, "keyssoft") == 0) {
+ mask = ResTable_config::MASK_KEYSHIDDEN;
+ value = ResTable_config::KEYSHIDDEN_SOFT;
+ }
+
+ if (mask != 0) {
+ if (out) out->inputFlags = (out->inputFlags&~mask) | value;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseKeyboard(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->keyboard = out->KEYBOARD_ANY;
+ return true;
+ } else if (strcmp(name, "nokeys") == 0) {
+ if (out) out->keyboard = out->KEYBOARD_NOKEYS;
+ return true;
+ } else if (strcmp(name, "qwerty") == 0) {
+ if (out) out->keyboard = out->KEYBOARD_QWERTY;
+ return true;
+ } else if (strcmp(name, "12key") == 0) {
+ if (out) out->keyboard = out->KEYBOARD_12KEY;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseNavHidden(const char* name, ResTable_config* out) {
+ uint8_t mask = 0;
+ uint8_t value = 0;
+ if (strcmp(name, kWildcardName) == 0) {
+ mask = ResTable_config::MASK_NAVHIDDEN;
+ value = ResTable_config::NAVHIDDEN_ANY;
+ } else if (strcmp(name, "navexposed") == 0) {
+ mask = ResTable_config::MASK_NAVHIDDEN;
+ value = ResTable_config::NAVHIDDEN_NO;
+ } else if (strcmp(name, "navhidden") == 0) {
+ mask = ResTable_config::MASK_NAVHIDDEN;
+ value = ResTable_config::NAVHIDDEN_YES;
+ }
+
+ if (mask != 0) {
+ if (out) out->inputFlags = (out->inputFlags&~mask) | value;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseNavigation(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) out->navigation = out->NAVIGATION_ANY;
+ return true;
+ } else if (strcmp(name, "nonav") == 0) {
+ if (out) out->navigation = out->NAVIGATION_NONAV;
+ return true;
+ } else if (strcmp(name, "dpad") == 0) {
+ if (out) out->navigation = out->NAVIGATION_DPAD;
+ return true;
+ } else if (strcmp(name, "trackball") == 0) {
+ if (out) out->navigation = out->NAVIGATION_TRACKBALL;
+ return true;
+ } else if (strcmp(name, "wheel") == 0) {
+ if (out) out->navigation = out->NAVIGATION_WHEEL;
+ return true;
+ }
+
+ return false;
+}
+
+bool parseScreenSize(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) {
+ out->screenWidth = out->SCREENWIDTH_ANY;
+ out->screenHeight = out->SCREENHEIGHT_ANY;
+ }
+ return true;
+ }
+
+ const char* x = name;
+ while (*x >= '0' && *x <= '9') x++;
+ if (x == name || *x != 'x') return false;
+ String8 xName(name, x-name);
+ x++;
+
+ const char* y = x;
+ while (*y >= '0' && *y <= '9') y++;
+ if (y == name || *y != 0) return false;
+ String8 yName(x, y-x);
+
+ uint16_t w = (uint16_t)atoi(xName.string());
+ uint16_t h = (uint16_t)atoi(yName.string());
+ if (w < h) {
+ return false;
+ }
+
+ if (out) {
+ out->screenWidth = w;
+ out->screenHeight = h;
+ }
+
+ return true;
+}
+
+bool parseSmallestScreenWidthDp(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) {
+ out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
+ }
+ return true;
+ }
+
+ if (*name != 's') return false;
+ name++;
+ if (*name != 'w') return false;
+ name++;
+ const char* x = name;
+ while (*x >= '0' && *x <= '9') x++;
+ if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
+ String8 xName(name, x-name);
+
+ if (out) {
+ out->smallestScreenWidthDp = (uint16_t)atoi(xName.string());
+ }
+
+ return true;
+}
+
+bool parseScreenWidthDp(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) {
+ out->screenWidthDp = out->SCREENWIDTH_ANY;
+ }
+ return true;
+ }
+
+ if (*name != 'w') return false;
+ name++;
+ const char* x = name;
+ while (*x >= '0' && *x <= '9') x++;
+ if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
+ String8 xName(name, x-name);
+
+ if (out) {
+ out->screenWidthDp = (uint16_t)atoi(xName.string());
+ }
+
+ return true;
+}
+
+bool parseScreenHeightDp(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) {
+ out->screenHeightDp = out->SCREENWIDTH_ANY;
+ }
+ return true;
+ }
+
+ if (*name != 'h') return false;
+ name++;
+ const char* x = name;
+ while (*x >= '0' && *x <= '9') x++;
+ if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
+ String8 xName(name, x-name);
+
+ if (out) {
+ out->screenHeightDp = (uint16_t)atoi(xName.string());
+ }
+
+ return true;
+}
+
+bool parseVersion(const char* name, ResTable_config* out) {
+ if (strcmp(name, kWildcardName) == 0) {
+ if (out) {
+ out->sdkVersion = out->SDKVERSION_ANY;
+ out->minorVersion = out->MINORVERSION_ANY;
+ }
+ return true;
+ }
+
+ if (*name != 'v') {
+ return false;
+ }
+
+ name++;
+ const char* s = name;
+ while (*s >= '0' && *s <= '9') s++;
+ if (s == name || *s != 0) return false;
+ String8 sdkName(name, s-name);
+
+ if (out) {
+ out->sdkVersion = (uint16_t)atoi(sdkName.string());
+ out->minorVersion = 0;
+ }
+
+ return true;
+}
+
+String8 getVersion(const ResTable_config& config) {
+ return String8::format("v%u", config.sdkVersion);
+}
+
+bool isSameExcept(const ResTable_config& a, const ResTable_config& b, int axisMask) {
+ return a.diff(b) == axisMask;
+}
+
+} // namespace AaptConfig
diff --git a/tools/aapt/AaptConfig.h b/tools/aapt/AaptConfig.h
new file mode 100644
index 0000000..2963539
--- /dev/null
+++ b/tools/aapt/AaptConfig.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AAPT_CONFIG_H
+#define __AAPT_CONFIG_H
+
+#include <set>
+#include <utils/String8.h>
+
+#include "ConfigDescription.h"
+
+/**
+ * Utility methods for dealing with configurations.
+ */
+namespace AaptConfig {
+
+/**
+ * Parse a string of the form 'fr-sw600dp-land' and fill in the
+ * given ResTable_config with resulting configuration parameters.
+ *
+ * The resulting configuration has the appropriate sdkVersion defined
+ * for backwards compatibility.
+ */
+bool parse(const android::String8& str, ConfigDescription* out = NULL);
+
+/**
+ * Parse a comma separated list of configuration strings. Duplicate configurations
+ * will be removed.
+ *
+ * Example input: "fr,de-land,fr-sw600dp-land"
+ */
+bool parseCommaSeparatedList(const android::String8& str, std::set<ConfigDescription>* outSet);
+
+/**
+ * If the configuration uses an axis that was added after
+ * the original Android release, make sure the SDK version
+ * is set accordingly.
+ */
+void applyVersionForCompatibility(ConfigDescription* config);
+
+// Individual axis
+bool parseMcc(const char* str, android::ResTable_config* out = NULL);
+bool parseMnc(const char* str, android::ResTable_config* out = NULL);
+bool parseLayoutDirection(const char* str, android::ResTable_config* out = NULL);
+bool parseSmallestScreenWidthDp(const char* str, android::ResTable_config* out = NULL);
+bool parseScreenWidthDp(const char* str, android::ResTable_config* out = NULL);
+bool parseScreenHeightDp(const char* str, android::ResTable_config* out = NULL);
+bool parseScreenLayoutSize(const char* str, android::ResTable_config* out = NULL);
+bool parseScreenLayoutLong(const char* str, android::ResTable_config* out = NULL);
+bool parseOrientation(const char* str, android::ResTable_config* out = NULL);
+bool parseUiModeType(const char* str, android::ResTable_config* out = NULL);
+bool parseUiModeNight(const char* str, android::ResTable_config* out = NULL);
+bool parseDensity(const char* str, android::ResTable_config* out = NULL);
+bool parseTouchscreen(const char* str, android::ResTable_config* out = NULL);
+bool parseKeysHidden(const char* str, android::ResTable_config* out = NULL);
+bool parseKeyboard(const char* str, android::ResTable_config* out = NULL);
+bool parseNavHidden(const char* str, android::ResTable_config* out = NULL);
+bool parseNavigation(const char* str, android::ResTable_config* out = NULL);
+bool parseScreenSize(const char* str, android::ResTable_config* out = NULL);
+bool parseVersion(const char* str, android::ResTable_config* out = NULL);
+
+android::String8 getVersion(const android::ResTable_config& config);
+
+/**
+ * Returns true if the two configurations only differ by the specified axis.
+ * The axis mask is a bitmask of CONFIG_* constants.
+ */
+bool isSameExcept(const android::ResTable_config& a, const android::ResTable_config& b, int configMask);
+
+} // namespace AaptConfig
+
+#endif // __AAPT_CONFIG_H
diff --git a/tools/aapt/AaptUtil.cpp b/tools/aapt/AaptUtil.cpp
new file mode 100644
index 0000000..293e144
--- /dev/null
+++ b/tools/aapt/AaptUtil.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AaptUtil.h"
+
+using android::Vector;
+using android::String8;
+
+namespace AaptUtil {
+
+Vector<String8> split(const String8& str, const char sep) {
+ Vector<String8> parts;
+ const char* p = str.string();
+ const char* q;
+
+ while (true) {
+ q = strchr(p, sep);
+ if (q == NULL) {
+ parts.add(String8(p, strlen(p)));
+ return parts;
+ }
+
+ parts.add(String8(p, q-p));
+ p = q + 1;
+ }
+ return parts;
+}
+
+Vector<String8> splitAndLowerCase(const String8& str, const char sep) {
+ Vector<String8> parts;
+ const char* p = str.string();
+ const char* q;
+
+ while (true) {
+ q = strchr(p, sep);
+ if (q == NULL) {
+ String8 val(p, strlen(p));
+ val.toLower();
+ parts.add(val);
+ return parts;
+ }
+
+ String8 val(p, q-p);
+ val.toLower();
+ parts.add(val);
+ p = q + 1;
+ }
+ return parts;
+}
+
+} // namespace AaptUtil
diff --git a/tools/aapt/AaptUtil.h b/tools/aapt/AaptUtil.h
new file mode 100644
index 0000000..47a704a
--- /dev/null
+++ b/tools/aapt/AaptUtil.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AAPT_UTIL_H
+#define __AAPT_UTIL_H
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace AaptUtil {
+
+android::Vector<android::String8> split(const android::String8& str, const char sep);
+android::Vector<android::String8> splitAndLowerCase(const android::String8& str, const char sep);
+
+} // namespace AaptUtil
+
+#endif // __AAPT_UTIL_H
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 806f8ff..700afa1 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -1,104 +1,168 @@
-#
-# Copyright 2006 The Android Open Source Project
#
-# Android Asset Packaging Tool
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# This tool is prebuilt if we're doing an app-only build.
ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),)
+# ==========================================================
+# Setup some common variables for the different build
+# targets here.
+# ==========================================================
+LOCAL_PATH:= $(call my-dir)
-aapt_src_files := \
- AaptAssets.cpp \
- Command.cpp \
- CrunchCache.cpp \
- FileFinder.cpp \
- Main.cpp \
- Package.cpp \
- StringPool.cpp \
- XMLNode.cpp \
- ResourceFilter.cpp \
- ResourceIdCache.cpp \
- ResourceTable.cpp \
- Images.cpp \
- Resource.cpp \
+aaptMain := Main.cpp
+aaptSources := \
+ AaptAssets.cpp \
+ AaptConfig.cpp \
+ AaptUtil.cpp \
+ ApkBuilder.cpp \
+ Command.cpp \
+ CrunchCache.cpp \
+ FileFinder.cpp \
+ Package.cpp \
+ StringPool.cpp \
+ XMLNode.cpp \
+ ResourceFilter.cpp \
+ ResourceIdCache.cpp \
+ ResourceTable.cpp \
+ Images.cpp \
+ Resource.cpp \
pseudolocalize.cpp \
SourcePos.cpp \
- WorkQueue.cpp \
+ WorkQueue.cpp \
ZipEntry.cpp \
ZipFile.cpp \
- qsort_r_compat.c
+ qsort_r_compat.c
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
+aaptTests := \
+ tests/AaptConfig_test.cpp \
+ tests/AaptGroupEntry_test.cpp \
+ tests/ResourceFilter_test.cpp
-LOCAL_SRC_FILES := $(aapt_src_files)
+aaptCIncludes := \
+ external/libpng \
+ external/zlib
-LOCAL_CFLAGS += -Wno-format-y2k
-ifeq (darwin,$(HOST_OS))
-LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS
-endif
-
-LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
-
-LOCAL_C_INCLUDES += external/libpng
-LOCAL_C_INCLUDES += external/zlib
-
-LOCAL_STATIC_LIBRARIES := \
- libandroidfw \
- libutils \
- libcutils \
- libexpat \
- libpng \
- liblog \
- libziparchive-host
+aaptHostLdLibs :=
+aaptHostStaticLibs := \
+ libandroidfw \
+ libpng \
+ liblog \
+ libutils \
+ libcutils \
+ libexpat \
+ libziparchive-host
ifeq ($(HOST_OS),linux)
-LOCAL_LDLIBS += -lrt -ldl -lpthread
+ aaptHostLdLibs += -lrt -ldl -lpthread
endif
# Statically link libz for MinGW (Win SDK under Linux),
# and dynamically link for all others.
ifneq ($(strip $(USE_MINGW)),)
- LOCAL_STATIC_LIBRARIES += libz
+ aaptHostStaticLibs += libz
else
- LOCAL_LDLIBS += -lz
+ aaptHostLdLibs += -lz
endif
+
+# ==========================================================
+# Build the host static library: libaapt
+# ==========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libaapt
+
+LOCAL_SRC_FILES := $(aaptSources)
+LOCAL_C_INCLUDES += $(aaptCIncludes)
+
+LOCAL_CFLAGS += -Wno-format-y2k
+LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
+ifeq (darwin,$(HOST_OS))
+LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS
+endif
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+# ==========================================================
+# Build the host executable: aapt
+# ==========================================================
+include $(CLEAR_VARS)
+
LOCAL_MODULE := aapt
+LOCAL_SRC_FILES := $(aaptMain)
+
+LOCAL_STATIC_LIBRARIES += \
+ libaapt \
+ $(aaptHostStaticLibs)
+LOCAL_LDLIBS += $(aaptHostLdLibs)
+
include $(BUILD_HOST_EXECUTABLE)
-# aapt for running on the device
-# =========================================================
+
+# ==========================================================
+# Build the host tests: libaapt_tests
+# ==========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libaapt_tests
+
+LOCAL_SRC_FILES += $(aaptTests)
+LOCAL_C_INCLUDES += $(LOCAL_PATH)
+
+LOCAL_STATIC_LIBRARIES += \
+ libaapt \
+ $(aaptHostStaticLibs)
+LOCAL_LDLIBS += $(aaptHostLdLibs)
+
+include $(BUILD_HOST_NATIVE_TEST)
+
+
+# ==========================================================
+# Build the device executable: aapt
+# ==========================================================
ifneq ($(SDK_ONLY),true)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(aapt_src_files)
-
LOCAL_MODULE := aapt
-LOCAL_C_INCLUDES += bionic
-LOCAL_C_INCLUDES += bionic/libstdc++/include
-LOCAL_C_INCLUDES += external/stlport/stlport
-LOCAL_C_INCLUDES += external/libpng
-LOCAL_C_INCLUDES += external/zlib
-
-LOCAL_CFLAGS += -Wno-non-virtual-dtor
+LOCAL_SRC_FILES := $(aaptSources) $(aaptMain)
+LOCAL_C_INCLUDES += \
+ $(aaptCIncludes) \
+ bionic \
+ external/stlport/stlport
LOCAL_SHARED_LIBRARIES := \
- libandroidfw \
- libutils \
- libcutils \
- libpng \
- liblog \
- libz
+ libandroidfw \
+ libutils \
+ libcutils \
+ libpng \
+ liblog \
+ libz
LOCAL_STATIC_LIBRARIES := \
- libstlport_static \
- libexpat_static
+ libstlport_static \
+ libexpat_static
+
+LOCAL_CPPFLAGS += -Wno-non-virtual-dtor
include $(BUILD_EXECUTABLE)
-endif
+
+endif # Not SDK_ONLY
endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
diff --git a/tools/aapt/ApkBuilder.cpp b/tools/aapt/ApkBuilder.cpp
new file mode 100644
index 0000000..12f6040
--- /dev/null
+++ b/tools/aapt/ApkBuilder.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AaptAssets.h"
+#include "ApkBuilder.h"
+
+using namespace android;
+
+ApkBuilder::ApkBuilder(const sp<WeakResourceFilter>& configFilter)
+ : mConfigFilter(configFilter)
+ , mDefaultFilter(new AndResourceFilter()) {
+ // Add the default split, which is present for all APKs.
+ mDefaultFilter->addFilter(mConfigFilter);
+ mSplits.add(new ApkSplit(std::set<ConfigDescription>(), mDefaultFilter, true));
+}
+
+status_t ApkBuilder::createSplitForConfigs(const std::set<ConfigDescription>& configs) {
+ const size_t N = mSplits.size();
+ for (size_t i = 0; i < N; i++) {
+ const std::set<ConfigDescription>& splitConfigs = mSplits[i]->getConfigs();
+ std::set<ConfigDescription>::const_iterator iter = configs.begin();
+ for (; iter != configs.end(); iter++) {
+ if (splitConfigs.count(*iter) > 0) {
+ // Can't have overlapping configurations.
+ fprintf(stderr, "ERROR: Split configuration '%s' is already defined "
+ "in another split.\n", iter->toString().string());
+ return ALREADY_EXISTS;
+ }
+ }
+ }
+
+ sp<StrongResourceFilter> splitFilter = new StrongResourceFilter(configs);
+
+ // Add the inverse filter of this split filter to the base apk filter so it will
+ // omit resources that belong in this split.
+ mDefaultFilter->addFilter(new InverseResourceFilter(splitFilter));
+
+ // Now add the apk-wide config filter to our split filter.
+ sp<AndResourceFilter> filter = new AndResourceFilter();
+ filter->addFilter(splitFilter);
+ filter->addFilter(mConfigFilter);
+ mSplits.add(new ApkSplit(configs, filter));
+ return NO_ERROR;
+}
+
+status_t ApkBuilder::addEntry(const String8& path, const sp<AaptFile>& file) {
+ const size_t N = mSplits.size();
+ for (size_t i = 0; i < N; i++) {
+ if (mSplits[i]->matches(file)) {
+ return mSplits.editItemAt(i)->addEntry(path, file);
+ }
+ }
+ // Entry can be dropped if it doesn't match any split. This will only happen
+ // if the enry doesn't mConfigFilter.
+ return NO_ERROR;
+}
+
+void ApkBuilder::print() const {
+ fprintf(stderr, "APK Builder\n");
+ fprintf(stderr, "-----------\n");
+ const size_t N = mSplits.size();
+ for (size_t i = 0; i < N; i++) {
+ mSplits[i]->print();
+ fprintf(stderr, "\n");
+ }
+}
+
+ApkSplit::ApkSplit(const std::set<ConfigDescription>& configs, const sp<ResourceFilter>& filter, bool isBase)
+ : mConfigs(configs), mFilter(filter), mIsBase(isBase) {
+ std::set<ConfigDescription>::const_iterator iter = configs.begin();
+ for (; iter != configs.end(); iter++) {
+ if (mName.size() > 0) {
+ mName.append(",");
+ mDirName.append("_");
+ }
+
+ String8 configStr = iter->toString();
+ mName.append(configStr);
+ mDirName.append(configStr);
+ }
+}
+
+status_t ApkSplit::addEntry(const String8& path, const sp<AaptFile>& file) {
+ if (!mFiles.insert(OutputEntry(path, file)).second) {
+ // Duplicate file.
+ return ALREADY_EXISTS;
+ }
+ return NO_ERROR;
+}
+
+void ApkSplit::print() const {
+ fprintf(stderr, "APK Split '%s'\n", mName.string());
+
+ std::set<OutputEntry>::const_iterator iter = mFiles.begin();
+ for (; iter != mFiles.end(); iter++) {
+ fprintf(stderr, " %s (%s)\n", iter->getPath().string(), iter->getFile()->getSourceFile().string());
+ }
+}
diff --git a/tools/aapt/ApkBuilder.h b/tools/aapt/ApkBuilder.h
new file mode 100644
index 0000000..db23c84
--- /dev/null
+++ b/tools/aapt/ApkBuilder.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __APK_BUILDER_H
+#define __APK_BUILDER_H
+
+#include <set>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+
+#include "ConfigDescription.h"
+#include "OutputSet.h"
+#include "ResourceFilter.h"
+
+class ApkSplit;
+class AaptFile;
+
+class ApkBuilder : public android::RefBase {
+public:
+ ApkBuilder(const sp<WeakResourceFilter>& configFilter);
+
+ /**
+ * Tells the builder to generate a separate APK for resources that
+ * match the configurations specified. Split APKs can not have
+ * overlapping resources.
+ *
+ * NOTE: All splits should be set up before any files are added.
+ */
+ android::status_t createSplitForConfigs(const std::set<ConfigDescription>& configs);
+
+ /**
+ * Adds a file to be written to the final APK. It's name must not collide
+ * with that of any files previously added. When a Split APK is being
+ * generated, duplicates can exist as long as they are in different splits
+ * (resources.arsc, AndroidManifest.xml).
+ */
+ android::status_t addEntry(const String8& path, const android::sp<AaptFile>& file);
+
+ android::Vector<sp<ApkSplit> >& getSplits() {
+ return mSplits;
+ }
+
+ android::sp<ApkSplit> getBaseSplit() {
+ return mSplits[0];
+ }
+
+ void print() const;
+
+private:
+ android::sp<ResourceFilter> mConfigFilter;
+ android::sp<AndResourceFilter> mDefaultFilter;
+ android::Vector<sp<ApkSplit> > mSplits;
+};
+
+class ApkSplit : public OutputSet {
+public:
+ android::status_t addEntry(const String8& path, const android::sp<AaptFile>& file);
+
+ const std::set<OutputEntry>& getEntries() const {
+ return mFiles;
+ }
+
+ const std::set<ConfigDescription>& getConfigs() const {
+ return mConfigs;
+ }
+
+ bool matches(const sp<AaptFile>& file) const {
+ return mFilter->match(file->getGroupEntry().toParams());
+ }
+
+ sp<ResourceFilter> getResourceFilter() const {
+ return mFilter;
+ }
+
+ const android::String8& getPrintableName() const {
+ return mName;
+ }
+
+ const android::String8& getDirectorySafeName() const {
+ return mDirName;
+ }
+
+ bool isBase() const {
+ return mIsBase;
+ }
+
+ void print() const;
+
+private:
+ friend class ApkBuilder;
+
+ ApkSplit(const std::set<ConfigDescription>& configs, const android::sp<ResourceFilter>& filter, bool isBase=false);
+
+ std::set<ConfigDescription> mConfigs;
+ const sp<ResourceFilter> mFilter;
+ const bool mIsBase;
+ String8 mName;
+ String8 mDirName;
+ std::set<OutputEntry> mFiles;
+};
+
+#endif // __APK_BUILDER_H
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index ebe1bed..ceb52a0 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -151,10 +151,12 @@
void setPublicOutputFile(const char* file) { mPublicOutputFile = file; }
const char* getRClassDir() const { return mRClassDir; }
void setRClassDir(const char* dir) { mRClassDir = dir; }
- const char* getConfigurations() const { return mConfigurations.size() > 0 ? mConfigurations.string() : NULL; }
+ const android::String8& getConfigurations() const { return mConfigurations; }
void addConfigurations(const char* val) { if (mConfigurations.size() > 0) { mConfigurations.append(","); mConfigurations.append(val); } else { mConfigurations = val; } }
- const char* getPreferredConfigurations() const { return mPreferredConfigurations.size() > 0 ? mPreferredConfigurations.string() : NULL; }
- void addPreferredConfigurations(const char* val) { if (mPreferredConfigurations.size() > 0) { mPreferredConfigurations.append(","); mPreferredConfigurations.append(val); } else { mPreferredConfigurations = val; } }
+ const android::String8& getPreferredDensity() const { return mPreferredDensity; }
+ void setPreferredDensity(const char* val) { mPreferredDensity = val; }
+ void addSplitConfigurations(const char* val) { mPartialConfigurations.add(android::String8(val)); }
+ const android::Vector<android::String8>& getSplitConfigurations() const { return mPartialConfigurations; }
const char* getResourceIntermediatesDir() const { return mResourceIntermediatesDir; }
void setResourceIntermediatesDir(const char* dir) { mResourceIntermediatesDir = dir; }
const android::Vector<const char*>& getPackageIncludes() const { return mPackageIncludes; }
@@ -286,7 +288,8 @@
const char* mRClassDir;
const char* mResourceIntermediatesDir;
android::String8 mConfigurations;
- android::String8 mPreferredConfigurations;
+ android::String8 mPreferredDensity;
+ android::Vector<android::String8> mPartialConfigurations;
android::Vector<const char*> mPackageIncludes;
android::Vector<const char*> mJarFiles;
android::Vector<const char*> mNoCompressExtensions;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 0af1ce1..24a94a7e 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -3,6 +3,7 @@
//
// Android Asset Packaging Tool main entry point.
//
+#include "ApkBuilder.h"
#include "Main.h"
#include "Bundle.h"
#include "ResourceFilter.h"
@@ -452,7 +453,7 @@
return retStr;
}
-static void printCompatibleScreens(ResXMLTree& tree) {
+static void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
size_t len;
ResXMLTree::event_code_t code;
int depth = 0;
@@ -470,7 +471,12 @@
continue;
}
depth++;
- String8 tag(tree.getElementName(&len));
+ const char16_t* ctag16 = tree.getElementName(&len);
+ if (ctag16 == NULL) {
+ *outError = "failed to get XML element name (bad string pool)";
+ return;
+ }
+ String8 tag(ctag16);
if (tag == "screen") {
int32_t screenSize = getIntegerAttribute(tree,
SCREEN_SIZE_ATTR, NULL, -1);
@@ -535,7 +541,12 @@
while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
depth--;
- String8 tag(tree.getElementName(&len));
+ const char16_t* ctag16 = tree.getElementName(&len);
+ if (ctag16 == NULL) {
+ *outError = "failed to get XML element name (bad string pool)";
+ return Vector<String8>();
+ }
+ String8 tag(ctag16);
if (depth == 0 && tag == serviceTagName) {
withinApduService = false;
@@ -543,7 +554,12 @@
} else if (code == ResXMLTree::START_TAG) {
depth++;
- String8 tag(tree.getElementName(&len));
+ const char16_t* ctag16 = tree.getElementName(&len);
+ if (ctag16 == NULL) {
+ *outError = "failed to get XML element name (bad string pool)";
+ return Vector<String8>();
+ }
+ String8 tag(ctag16);
if (depth == 1) {
if (tag == serviceTagName) {
@@ -710,7 +726,12 @@
continue;
}
depth++;
- String8 tag(tree.getElementName(&len));
+ const char16_t* ctag16 = tree.getElementName(&len);
+ if (ctag16 == NULL) {
+ fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
+ goto bail;
+ }
+ String8 tag(ctag16);
//printf("Depth %d tag %s\n", depth, tag.string());
if (depth == 1) {
if (tag != "manifest") {
@@ -969,7 +990,13 @@
continue;
}
depth++;
- String8 tag(tree.getElementName(&len));
+
+ const char16_t* ctag16 = tree.getElementName(&len);
+ if (ctag16 == NULL) {
+ fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
+ goto bail;
+ }
+ String8 tag(ctag16);
//printf("Depth %d, %s\n", depth, tag.string());
if (depth == 1) {
if (tag != "manifest") {
@@ -1296,7 +1323,12 @@
goto bail;
}
} else if (tag == "compatible-screens") {
- printCompatibleScreens(tree);
+ printCompatibleScreens(tree, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting compatible screens: %s\n",
+ error.string());
+ goto bail;
+ }
depth--;
} else if (tag == "package-verifier") {
String8 name = getAttribute(tree, NAME_ATTR, &error);
@@ -2034,6 +2066,58 @@
return (result != NO_ERROR);
}
+static status_t addResourcesToBuilder(const sp<AaptDir>& dir, const sp<ApkBuilder>& builder, bool ignoreConfig=false) {
+ const size_t numDirs = dir->getDirs().size();
+ for (size_t i = 0; i < numDirs; i++) {
+ bool ignore = ignoreConfig;
+ const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
+ const char* dirStr = subDir->getLeaf().string();
+ if (!ignore && strstr(dirStr, "mipmap") == dirStr) {
+ ignore = true;
+ }
+ status_t err = addResourcesToBuilder(subDir, builder, ignore);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ }
+
+ const size_t numFiles = dir->getFiles().size();
+ for (size_t i = 0; i < numFiles; i++) {
+ sp<AaptGroup> gp = dir->getFiles().valueAt(i);
+ const size_t numConfigs = gp->getFiles().size();
+ for (size_t j = 0; j < numConfigs; j++) {
+ status_t err = NO_ERROR;
+ if (ignoreConfig) {
+ err = builder->getBaseSplit()->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
+ } else {
+ err = builder->addEntry(gp->getPath(), gp->getFiles().valueAt(j));
+ }
+ if (err != NO_ERROR) {
+ fprintf(stderr, "Failed to add %s (%s) to builder.\n",
+ gp->getPath().string(), gp->getFiles()[j]->getPrintableSource().string());
+ return err;
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+static String8 buildApkName(const String8& original, const sp<ApkSplit>& split) {
+ if (split->isBase()) {
+ return original;
+ }
+
+ String8 ext(original.getPathExtension());
+ if (ext == String8(".apk")) {
+ return String8::format("%s_%s%s",
+ original.getBasePath().string(),
+ split->getDirectorySafeName().string(),
+ ext.string());
+ }
+
+ return String8::format("%s_%s", original.string(),
+ split->getDirectorySafeName().string());
+}
/*
* Package up an asset directory and associated application files.
@@ -2047,17 +2131,18 @@
int N;
FILE* fp;
String8 dependencyFile;
+ sp<ApkBuilder> builder;
// -c en_XA or/and ar_XB means do pseudolocalization
- ResourceFilter filter;
- err = filter.parse(bundle->getConfigurations());
+ sp<WeakResourceFilter> configFilter = new WeakResourceFilter();
+ err = configFilter->parse(bundle->getConfigurations());
if (err != NO_ERROR) {
goto bail;
}
- if (filter.containsPseudo()) {
+ if (configFilter->containsPseudo()) {
bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED);
}
- if (filter.containsPseudoBidi()) {
+ if (configFilter->containsPseudoBidi()) {
bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI);
}
@@ -2105,9 +2190,32 @@
assets->print(String8());
}
+ // Create the ApkBuilder, which will collect the compiled files
+ // to write to the final APK (or sets of APKs if we are building
+ // a Split APK.
+ builder = new ApkBuilder(configFilter);
+
+ // If we are generating a Split APK, find out which configurations to split on.
+ if (bundle->getSplitConfigurations().size() > 0) {
+ const Vector<String8>& splitStrs = bundle->getSplitConfigurations();
+ const size_t numSplits = splitStrs.size();
+ for (size_t i = 0; i < numSplits; i++) {
+ std::set<ConfigDescription> configs;
+ if (!AaptConfig::parseCommaSeparatedList(splitStrs[i], &configs)) {
+ fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].string());
+ goto bail;
+ }
+
+ err = builder->createSplitForConfigs(configs);
+ if (err != NO_ERROR) {
+ goto bail;
+ }
+ }
+ }
+
// If they asked for any fileAs that need to be compiled, do so.
if (bundle->getResourceSourceDirs().size() || bundle->getAndroidManifestFile()) {
- err = buildResources(bundle, assets);
+ err = buildResources(bundle, assets, builder);
if (err != 0) {
goto bail;
}
@@ -2194,11 +2302,24 @@
// Write the apk
if (outputAPKFile) {
- err = writeAPK(bundle, assets, String8(outputAPKFile));
+ // Gather all resources and add them to the APK Builder. The builder will then
+ // figure out which Split they belong in.
+ err = addResourcesToBuilder(assets, builder);
if (err != NO_ERROR) {
- fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputAPKFile);
goto bail;
}
+
+ const Vector<sp<ApkSplit> >& splits = builder->getSplits();
+ const size_t numSplits = splits.size();
+ for (size_t i = 0; i < numSplits; i++) {
+ const sp<ApkSplit>& split = splits[i];
+ String8 outputPath = buildApkName(String8(outputAPKFile), split);
+ err = writeAPK(bundle, outputPath, split);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.string());
+ goto bail;
+ }
+ }
}
// If we've been asked to generate a dependency file, we need to finish up here.
diff --git a/tools/aapt/ConfigDescription.h b/tools/aapt/ConfigDescription.h
new file mode 100644
index 0000000..779c423
--- /dev/null
+++ b/tools/aapt/ConfigDescription.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONFIG_DESCRIPTION_H
+#define __CONFIG_DESCRIPTION_H
+
+#include <androidfw/ResourceTypes.h>
+
+/**
+ * Subclass of ResTable_config that adds convenient
+ * initialization and comparison methods.
+ */
+struct ConfigDescription : public android::ResTable_config {
+ ConfigDescription() {
+ memset(this, 0, sizeof(*this));
+ size = sizeof(android::ResTable_config);
+ }
+ ConfigDescription(const android::ResTable_config&o) {
+ *static_cast<android::ResTable_config*>(this) = o;
+ size = sizeof(android::ResTable_config);
+ }
+ ConfigDescription(const ConfigDescription&o) {
+ *static_cast<android::ResTable_config*>(this) = o;
+ }
+
+ ConfigDescription& operator=(const android::ResTable_config& o) {
+ *static_cast<android::ResTable_config*>(this) = o;
+ size = sizeof(android::ResTable_config);
+ return *this;
+ }
+ ConfigDescription& operator=(const ConfigDescription& o) {
+ *static_cast<android::ResTable_config*>(this) = o;
+ return *this;
+ }
+
+ inline bool operator<(const ConfigDescription& o) const { return compare(o) < 0; }
+ inline bool operator<=(const ConfigDescription& o) const { return compare(o) <= 0; }
+ inline bool operator==(const ConfigDescription& o) const { return compare(o) == 0; }
+ inline bool operator!=(const ConfigDescription& o) const { return compare(o) != 0; }
+ inline bool operator>=(const ConfigDescription& o) const { return compare(o) >= 0; }
+ inline bool operator>(const ConfigDescription& o) const { return compare(o) > 0; }
+};
+
+#endif // __CONFIG_DESCRIPTION_H
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 1cf4783..5a60014 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -70,6 +70,7 @@
" [-F apk-file] [-J R-file-dir] \\\n"
" [--product product1,product2,...] \\\n"
" [-c CONFIGS] [--preferred-configurations CONFIGS] \\\n"
+ " [--split CONFIGS [--split CONFIGS]] \\\n"
" [raw-files-dir [raw-files-dir] ...] \\\n"
" [--output-text-symbols DIR]\n"
"\n"
@@ -166,10 +167,12 @@
" generate dependency files in the same directories for R.java and resource package\n"
" --auto-add-overlay\n"
" Automatically add resources that are only in overlays.\n"
- " --preferred-configurations\n"
- " Like the -c option for filtering out unneeded configurations, but\n"
- " only expresses a preference. If there is no resource available with\n"
- " the preferred configuration then it will not be stripped.\n"
+ " --preferred-density\n"
+ " Specifies a preference for a particular density. Resources that do not\n"
+ " match this density and have variants that are a closer match are removed.\n"
+ " --split\n"
+ " Builds a separate split APK for the configurations listed. This can\n"
+ " be loaded alongside the base APK at runtime.\n"
" --rename-manifest-package\n"
" Rewrite the manifest so that its package name is the package name\n"
" given here. Relative class names (for example .Foo) will be\n"
@@ -568,15 +571,24 @@
bundle.setGenDependencies(true);
} else if (strcmp(cp, "-utf16") == 0) {
bundle.setWantUTF16(true);
- } else if (strcmp(cp, "-preferred-configurations") == 0) {
+ } else if (strcmp(cp, "-preferred-density") == 0) {
argc--;
argv++;
if (!argc) {
- fprintf(stderr, "ERROR: No argument supplied for '--preferred-configurations' option\n");
+ fprintf(stderr, "ERROR: No argument supplied for '--preferred-density' option\n");
wantUsage = true;
goto bail;
}
- bundle.addPreferredConfigurations(argv[0]);
+ bundle.setPreferredDensity(argv[0]);
+ } else if (strcmp(cp, "-split") == 0) {
+ argc--;
+ argv++;
+ if (!argc) {
+ fprintf(stderr, "ERROR: No argument supplied for '--split' option\n");
+ wantUsage = true;
+ goto bail;
+ }
+ bundle.addSplitConfigurations(argv[0]);
} else if (strcmp(cp, "-rename-manifest-package") == 0) {
argc--;
argv++;
diff --git a/tools/aapt/Main.h b/tools/aapt/Main.h
index a6b39ac..34c4496 100644
--- a/tools/aapt/Main.h
+++ b/tools/aapt/Main.h
@@ -10,8 +10,12 @@
#include <utils/threads.h>
#include <utils/List.h>
#include <utils/Errors.h>
-#include "Bundle.h"
+#include <utils/StrongPointer.h>
+
#include "AaptAssets.h"
+#include "ApkBuilder.h"
+#include "Bundle.h"
+#include "ResourceFilter.h"
#include "ZipFile.h"
@@ -22,6 +26,8 @@
#include <time.h>
#endif /* BENCHMARK */
+class OutputSet;
+
extern int doVersion(Bundle* bundle);
extern int doList(Bundle* bundle);
extern int doDump(Bundle* bundle);
@@ -34,13 +40,13 @@
extern int calcPercent(long uncompressedLen, long compressedLen);
extern android::status_t writeAPK(Bundle* bundle,
- const sp<AaptAssets>& assets,
- const android::String8& outputFile);
+ const android::String8& outputFile,
+ const android::sp<OutputSet>& outputSet);
extern android::status_t updatePreProcessedCache(Bundle* bundle);
extern android::status_t buildResources(Bundle* bundle,
- const sp<AaptAssets>& assets);
+ const sp<AaptAssets>& assets, sp<ApkBuilder>& builder);
extern android::status_t writeResourceSymbols(Bundle* bundle,
const sp<AaptAssets>& assets, const String8& pkgName, bool includePrivate);
@@ -49,8 +55,6 @@
extern bool isValidResourceType(const String8& type);
-ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptAssets>& assets);
-
extern status_t filterResources(Bundle* bundle, const sp<AaptAssets>& assets);
int dumpResources(Bundle* bundle);
diff --git a/tools/aapt/OutputSet.h b/tools/aapt/OutputSet.h
new file mode 100644
index 0000000..ea9ef70
--- /dev/null
+++ b/tools/aapt/OutputSet.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __OUTPUT_SET_H
+#define __OUTPUT_SET_H
+
+#include <set>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+
+class AaptFile;
+
+class OutputEntry {
+public:
+ OutputEntry() {}
+ OutputEntry(const android::String8& path, const android::sp<const AaptFile>& file)
+ : mPath(path), mFile(file) {}
+
+ inline const android::sp<const AaptFile>& getFile() const {
+ return mFile;
+ }
+
+ inline const android::String8& getPath() const {
+ return mPath;
+ }
+
+ bool operator<(const OutputEntry& o) const { return getPath() < o.mPath; }
+ bool operator==(const OutputEntry& o) const { return getPath() == o.mPath; }
+
+private:
+ android::String8 mPath;
+ android::sp<const AaptFile> mFile;
+};
+
+class OutputSet : public virtual android::RefBase {
+public:
+ virtual const std::set<OutputEntry>& getEntries() const = 0;
+
+ virtual ~OutputSet() {}
+};
+
+#endif // __OUTPUT_SET_H
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index 872d95c..dc16e35 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -5,6 +5,7 @@
//
#include "Main.h"
#include "AaptAssets.h"
+#include "OutputSet.h"
#include "ResourceTable.h"
#include "ResourceFilter.h"
@@ -36,11 +37,8 @@
};
/* fwd decls, so I can write this downward */
-ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptAssets>& assets);
-ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptDir>& dir,
- const AaptGroupEntry& ge, const ResourceFilter* filter);
-bool processFile(Bundle* bundle, ZipFile* zip,
- const sp<AaptGroup>& group, const sp<AaptFile>& file);
+ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& outputSet);
+bool processFile(Bundle* bundle, ZipFile* zip, String8 storageName, const sp<const AaptFile>& file);
bool okayToCompress(Bundle* bundle, const String8& pathName);
ssize_t processJarFiles(Bundle* bundle, ZipFile* zip);
@@ -51,8 +49,7 @@
* On success, "bundle->numPackages" will be the number of Zip packages
* we created.
*/
-status_t writeAPK(Bundle* bundle, const sp<AaptAssets>& assets,
- const String8& outputFile)
+status_t writeAPK(Bundle* bundle, const String8& outputFile, const sp<OutputSet>& outputSet)
{
#if BENCHMARK
fprintf(stdout, "BENCHMARK: Starting APK Bundling \n");
@@ -112,7 +109,7 @@
printf("Writing all files...\n");
}
- count = processAssets(bundle, zip, assets);
+ count = processAssets(bundle, zip, outputSet);
if (count < 0) {
fprintf(stderr, "ERROR: unable to process assets while packaging '%s'\n",
outputFile.string());
@@ -218,72 +215,24 @@
return result;
}
-ssize_t processAssets(Bundle* bundle, ZipFile* zip,
- const sp<AaptAssets>& assets)
-{
- ResourceFilter filter;
- status_t status = filter.parse(bundle->getConfigurations());
- if (status != NO_ERROR) {
- return -1;
- }
-
- ssize_t count = 0;
-
- const size_t N = assets->getGroupEntries().size();
- for (size_t i=0; i<N; i++) {
- const AaptGroupEntry& ge = assets->getGroupEntries()[i];
-
- ssize_t res = processAssets(bundle, zip, assets, ge, &filter);
- if (res < 0) {
- return res;
- }
-
- count += res;
- }
-
- return count;
-}
-
-ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<AaptDir>& dir,
- const AaptGroupEntry& ge, const ResourceFilter* filter)
+ssize_t processAssets(Bundle* bundle, ZipFile* zip, const sp<const OutputSet>& outputSet)
{
ssize_t count = 0;
-
- const size_t ND = dir->getDirs().size();
- size_t i;
- for (i=0; i<ND; i++) {
- const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
-
- const bool filterable = filter != NULL && subDir->getLeaf().find("mipmap-") != 0;
-
- if (filterable && subDir->getLeaf() != subDir->getPath() && !filter->match(ge.toParams())) {
- continue;
- }
-
- ssize_t res = processAssets(bundle, zip, subDir, ge, filterable ? filter : NULL);
- if (res < 0) {
- return res;
- }
- count += res;
- }
-
- if (filter != NULL && !filter->match(ge.toParams())) {
- return count;
- }
-
- const size_t NF = dir->getFiles().size();
- for (i=0; i<NF; i++) {
- sp<AaptGroup> gp = dir->getFiles().valueAt(i);
- ssize_t fi = gp->getFiles().indexOfKey(ge);
- if (fi >= 0) {
- sp<AaptFile> fl = gp->getFiles().valueAt(fi);
- if (!processFile(bundle, zip, gp, fl)) {
+ const std::set<OutputEntry>& entries = outputSet->getEntries();
+ std::set<OutputEntry>::const_iterator iter = entries.begin();
+ for (; iter != entries.end(); iter++) {
+ const OutputEntry& entry = *iter;
+ if (entry.getFile() == NULL) {
+ fprintf(stderr, "warning: null file being processed.\n");
+ } else {
+ String8 storagePath(entry.getPath());
+ storagePath.convertToResPath();
+ if (!processFile(bundle, zip, storagePath, entry.getFile())) {
return UNKNOWN_ERROR;
}
count++;
}
}
-
return count;
}
@@ -294,12 +243,10 @@
* delete the existing entry before adding the new one.
*/
bool processFile(Bundle* bundle, ZipFile* zip,
- const sp<AaptGroup>& group, const sp<AaptFile>& file)
+ String8 storageName, const sp<const AaptFile>& file)
{
const bool hasData = file->hasData();
- String8 storageName(group->getPath());
- storageName.convertToResPath();
ZipEntry* entry;
bool fromGzip = false;
status_t result;
@@ -403,8 +350,8 @@
fprintf(stderr, " Unable to add '%s': file already in archive (try '-u'?)\n",
file->getPrintableSource().string());
} else {
- fprintf(stderr, " Unable to add '%s': Zip add failed\n",
- file->getPrintableSource().string());
+ fprintf(stderr, " Unable to add '%s': Zip add failed (%d)\n",
+ file->getPrintableSource().string(), result);
}
return false;
}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 1348be3..e599643 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -179,24 +179,6 @@
|| type == "color" || type == "menu" || type == "mipmap";
}
-static sp<AaptFile> getResourceFile(const sp<AaptAssets>& assets, bool makeIfNecessary=true)
-{
- sp<AaptGroup> group = assets->getFiles().valueFor(String8("resources.arsc"));
- sp<AaptFile> file;
- if (group != NULL) {
- file = group->getFiles().valueFor(AaptGroupEntry());
- if (file != NULL) {
- return file;
- }
- }
-
- if (!makeIfNecessary) {
- return NULL;
- }
- return assets->addFile(String8("resources.arsc"), AaptGroupEntry(), String8(),
- NULL, String8());
-}
-
static status_t parsePackage(Bundle* bundle, const sp<AaptAssets>& assets,
const sp<AaptGroup>& grp)
{
@@ -359,23 +341,6 @@
return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR;
}
-status_t postProcessImages(const sp<AaptAssets>& assets,
- ResourceTable* table,
- const sp<ResourceTypeSet>& set)
-{
- ResourceDirIterator it(set, String8("drawable"));
- bool hasErrors = false;
- ssize_t res;
- while ((res=it.next()) == NO_ERROR) {
- res = postProcessImage(assets, table, it.getFile());
- if (res < NO_ERROR) {
- hasErrors = true;
- }
- }
-
- return (hasErrors || (res < NO_ERROR)) ? UNKNOWN_ERROR : NO_ERROR;
-}
-
static void collect_files(const sp<AaptDir>& dir,
KeyedVector<String8, sp<ResourceTypeSet> >* resources)
{
@@ -906,7 +871,38 @@
return 0;
}
-status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
+status_t generateAndroidManifestForSplit(const String16& package, const sp<ApkSplit>& split,
+ sp<AaptFile>& outFile) {
+ const String8 filename("AndroidManifest.xml");
+ const String16 androidPrefix("android");
+ const String16 androidNSUri("http://schemas.android.com/apk/res/android");
+ sp<XMLNode> root = XMLNode::newNamespace(filename, androidPrefix, androidNSUri);
+
+ // Build the <manifest> tag
+ sp<XMLNode> manifest = XMLNode::newElement(filename, String16(), String16("manifest"));
+
+ // Add the 'package' attribute which is set to the original package name.
+ manifest->addAttribute(String16(), String16("package"), package);
+
+ // Add the 'split' attribute which describes the configurations included.
+ String8 splitName("config_");
+ splitName.append(split->getDirectorySafeName());
+ manifest->addAttribute(String16(), String16("split"), String16(splitName));
+
+ // Build an empty <application> tag (required).
+ sp<XMLNode> app = XMLNode::newElement(filename, String16(), String16("application"));
+ manifest->addChild(app);
+ root->addChild(manifest);
+
+ status_t err = root->flatten(outFile, true, true);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ outFile->setCompressionMethod(ZipEntry::kCompressDeflated);
+ return NO_ERROR;
+}
+
+status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuilder>& builder)
{
// First, look for a package file to parse. This is required to
// be able to generate the resource information.
@@ -1122,12 +1118,6 @@
// --------------------------------------------------------------------
if (table.hasResources()) {
- sp<AaptFile> resFile(getResourceFile(assets));
- if (resFile == NULL) {
- fprintf(stderr, "Error: unable to generate entry for resource data\n");
- return UNKNOWN_ERROR;
- }
-
err = table.assignResourceIds();
if (err < NO_ERROR) {
return err;
@@ -1235,16 +1225,24 @@
}
if (drawables != NULL) {
- err = postProcessImages(assets, &table, drawables);
- if (err != NO_ERROR) {
+ ResourceDirIterator it(drawables, String8("drawable"));
+ while ((err=it.next()) == NO_ERROR) {
+ err = postProcessImage(assets, &table, it.getFile());
+ if (err != NO_ERROR) {
+ hasErrors = true;
+ }
+ }
+
+ if (err < NO_ERROR) {
hasErrors = true;
}
+ err = NO_ERROR;
}
if (colors != NULL) {
ResourceDirIterator it(colors, String8("color"));
while ((err=it.next()) == NO_ERROR) {
- err = compileXmlFile(assets, it.getFile(), &table, xmlFlags);
+ err = compileXmlFile(assets, it.getFile(), &table, xmlFlags);
if (err != NO_ERROR) {
hasErrors = true;
}
@@ -1320,15 +1318,35 @@
return err;
}
- resFile = getResourceFile(assets);
- if (resFile == NULL) {
- fprintf(stderr, "Error: unable to generate entry for resource data\n");
- return UNKNOWN_ERROR;
- }
+ Vector<sp<ApkSplit> >& splits = builder->getSplits();
+ const size_t numSplits = splits.size();
+ for (size_t i = 0; i < numSplits; i++) {
+ sp<ApkSplit>& split = splits.editItemAt(i);
+ sp<AaptFile> flattenedTable = new AaptFile(String8("resources.arsc"),
+ AaptGroupEntry(), String8());
+ err = table.flatten(bundle, split->getResourceFilter(), flattenedTable);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "Failed to generate resource table for split '%s'\n",
+ split->getPrintableName().string());
+ return err;
+ }
+ split->addEntry(String8("resources.arsc"), flattenedTable);
- err = table.flatten(bundle, resFile);
- if (err < NO_ERROR) {
- return err;
+ if (split->isBase()) {
+ resFile = flattenedTable;
+ finalResTable.add(flattenedTable->getData(), flattenedTable->getSize());
+ } else {
+ sp<AaptFile> generatedManifest = new AaptFile(String8("AndroidManifest.xml"),
+ AaptGroupEntry(), String8());
+ err = generateAndroidManifestForSplit(String16(assets->getPackage()), split,
+ generatedManifest);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "Failed to generate AndroidManifest.xml for split '%s'\n",
+ split->getPrintableName().string());
+ return err;
+ }
+ split->addEntry(String8("AndroidManifest.xml"), generatedManifest);
+ }
}
if (bundle->getPublicOutputFile()) {
@@ -1344,18 +1362,13 @@
table.writePublicDefinitions(String16(assets->getPackage()), fp);
fclose(fp);
}
-
- // Read resources back in,
- finalResTable.add(resFile->getData(), resFile->getSize());
-
-#if 0
- NOISY(
- printf("Generated resources:\n");
- finalResTable.print();
- )
-#endif
+
+ if (finalResTable.getTableCount() == 0 || resFile == NULL) {
+ fprintf(stderr, "No resource table was generated.\n");
+ return UNKNOWN_ERROR;
+ }
}
-
+
// Perform a basic validation of the manifest file. This time we
// parse it with the comments intact, so that we can use them to
// generate java docs... so we are not going to write this one
diff --git a/tools/aapt/ResourceFilter.cpp b/tools/aapt/ResourceFilter.cpp
index 8ca852e..de8b4fc 100644
--- a/tools/aapt/ResourceFilter.cpp
+++ b/tools/aapt/ResourceFilter.cpp
@@ -1,119 +1,92 @@
//
-// Copyright 2011 The Android Open Source Project
+// Copyright 2014 The Android Open Source Project
//
// Build resource files from raw assets.
//
#include "ResourceFilter.h"
+#include "AaptUtil.h"
+#include "AaptConfig.h"
status_t
-ResourceFilter::parse(const char* arg)
+WeakResourceFilter::parse(const String8& str)
{
- if (arg == NULL) {
- return 0;
- }
-
- const char* p = arg;
- const char* q;
-
- while (true) {
- q = strchr(p, ',');
- if (q == NULL) {
- q = p + strlen(p);
- }
-
- String8 part(p, q-p);
-
+ Vector<String8> configStrs = AaptUtil::split(str, ',');
+ const size_t N = configStrs.size();
+ mConfigs.clear();
+ mConfigMask = 0;
+ mConfigs.resize(N);
+ for (size_t i = 0; i < N; i++) {
+ const String8& part = configStrs[i];
if (part == "en_XA") {
mContainsPseudoAccented = true;
} else if (part == "ar_XB") {
mContainsPseudoBidi = true;
}
- int axis;
- AxisValue value;
- if (!AaptGroupEntry::parseFilterNamePart(part, &axis, &value)) {
- fprintf(stderr, "Invalid configuration: %s\n", arg);
- fprintf(stderr, " ");
- for (int i=0; i<p-arg; i++) {
- fprintf(stderr, " ");
- }
- for (int i=0; i<q-p; i++) {
- fprintf(stderr, "^");
- }
- fprintf(stderr, "\n");
- return 1;
+
+ std::pair<ConfigDescription, uint32_t>& entry = mConfigs.editItemAt(i);
+
+ AaptLocaleValue val;
+ if (val.initFromFilterString(part)) {
+ // For backwards compatibility, we accept configurations that
+ // only specify locale in the standard 'en_US' format.
+ val.writeTo(&entry.first);
+ } else if (!AaptConfig::parse(part, &entry.first)) {
+ fprintf(stderr, "Invalid configuration: %s\n", part.string());
+ return UNKNOWN_ERROR;
}
- ssize_t index = mData.indexOfKey(axis);
- if (index < 0) {
- mData.add(axis, SortedVector<AxisValue>());
- }
- SortedVector<AxisValue>& sv = mData.editValueFor(axis);
- sv.add(value);
+ entry.second = mDefault.diff(entry.first);
- // If it's a locale with a region, script or variant, we should also match an
- // unmodified locale of the same language
- if (axis == AXIS_LOCALE) {
- if (value.localeValue.region[0] || value.localeValue.script[0] ||
- value.localeValue.variant[0]) {
- AxisValue copy;
- memcpy(copy.localeValue.language, value.localeValue.language,
- sizeof(value.localeValue.language));
- sv.add(copy);
- }
- }
- p = q;
- if (!*p) break;
- p++;
+ // Ignore the version
+ entry.second &= ~ResTable_config::CONFIG_VERSION;
+
+ mConfigMask |= entry.second;
}
return NO_ERROR;
}
bool
-ResourceFilter::isEmpty() const
+WeakResourceFilter::match(const ResTable_config& config) const
{
- return mData.size() == 0;
-}
-
-bool
-ResourceFilter::match(int axis, const AxisValue& value) const
-{
- if (value.intValue == 0 && (value.localeValue.language[0] == 0)) {
- // they didn't specify anything so take everything
+ uint32_t mask = mDefault.diff(config);
+ if ((mConfigMask & mask) == 0) {
+ // The two configurations don't have any common axis.
return true;
}
- ssize_t index = mData.indexOfKey(axis);
- if (index < 0) {
- // we didn't request anything on this axis so take everything
- return true;
- }
- const SortedVector<AxisValue>& sv = mData.valueAt(index);
- return sv.indexOf(value) >= 0;
-}
-bool
-ResourceFilter::match(int axis, const ResTable_config& config) const
-{
- return match(axis, AaptGroupEntry::getConfigValueForAxis(config, axis));
-}
-
-bool
-ResourceFilter::match(const ResTable_config& config) const
-{
- for (int i=AXIS_START; i<=AXIS_END; i++) {
- if (!match(i, AaptGroupEntry::getConfigValueForAxis(config, i))) {
- return false;
+ const size_t N = mConfigs.size();
+ for (size_t i = 0; i < N; i++) {
+ const std::pair<ConfigDescription, uint32_t>& entry = mConfigs[i];
+ uint32_t diff = entry.first.diff(config);
+ if ((diff & entry.second) == 0) {
+ return true;
+ } else if ((diff & entry.second) == ResTable_config::CONFIG_LOCALE) {
+ // If the locales differ, but the languages are the same and
+ // the locale we are matching only has a language specified,
+ // we match.
+ if (config.language[0] && memcmp(config.language, entry.first.language, sizeof(config.language)) == 0) {
+ if (config.country[0] == 0) {
+ return true;
+ }
+ }
}
}
- return true;
+ return false;
}
-const SortedVector<AxisValue>* ResourceFilter::configsForAxis(int axis) const
-{
- ssize_t index = mData.indexOfKey(axis);
- if (index < 0) {
- return NULL;
+status_t
+StrongResourceFilter::parse(const String8& str) {
+ Vector<String8> configStrs = AaptUtil::split(str, ',');
+ ConfigDescription config;
+ mConfigs.clear();
+ for (size_t i = 0; i < configStrs.size(); i++) {
+ if (!AaptConfig::parse(configStrs[i], &config)) {
+ fprintf(stderr, "Invalid configuration: %s\n", configStrs[i].string());
+ return UNKNOWN_ERROR;
+ }
+ mConfigs.insert(config);
}
- return &mData.valueAt(index);
+ return NO_ERROR;
}
diff --git a/tools/aapt/ResourceFilter.h b/tools/aapt/ResourceFilter.h
index c57770e..f459584 100644
--- a/tools/aapt/ResourceFilter.h
+++ b/tools/aapt/ResourceFilter.h
@@ -7,31 +7,137 @@
#ifndef RESOURCE_FILTER_H
#define RESOURCE_FILTER_H
+#include <androidfw/ResourceTypes.h>
+#include <set>
+#include <utility>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+
#include "AaptAssets.h"
+#include "ConfigDescription.h"
+
+class ResourceFilter : public virtual android::RefBase {
+public:
+ virtual bool match(const android::ResTable_config& config) const = 0;
+};
/**
* Implements logic for parsing and handling "-c" and "--preferred-configurations"
* options.
*/
-class ResourceFilter
-{
+class WeakResourceFilter : public ResourceFilter {
public:
- ResourceFilter() : mData(), mContainsPseudoAccented(false),
- mContainsPseudoBidi(false) {}
- status_t parse(const char* arg);
- bool isEmpty() const;
- bool match(int axis, const ResTable_config& config) const;
- bool match(const ResTable_config& config) const;
- const SortedVector<AxisValue>* configsForAxis(int axis) const;
- inline bool containsPseudo() const { return mContainsPseudoAccented; }
- inline bool containsPseudoBidi() const { return mContainsPseudoBidi; }
+ WeakResourceFilter()
+ : mContainsPseudoAccented(false)
+ , mContainsPseudoBidi(false) {}
+
+ android::status_t parse(const android::String8& str);
+
+ bool match(const android::ResTable_config& config) const;
+
+ inline bool isEmpty() const {
+ return mConfigMask == 0;
+ }
+
+ inline bool containsPseudo() const {
+ return mContainsPseudoAccented;
+ }
+
+ inline bool containsPseudoBidi() const {
+ return mContainsPseudoBidi;
+ }
private:
- bool match(int axis, const AxisValue& value) const;
+ ConfigDescription mDefault;
+ uint32_t mConfigMask;
+ android::Vector<std::pair<ConfigDescription, uint32_t> > mConfigs;
- KeyedVector<int,SortedVector<AxisValue> > mData;
bool mContainsPseudoAccented;
bool mContainsPseudoBidi;
};
+/**
+ * Matches resources that have at least one of the configurations
+ * that this filter is looking for. In order to match a configuration,
+ * the resource must have the exact same configuration.
+ *
+ * This filter acts as a logical OR when matching resources.
+ *
+ * For example, if the filter is looking for resources with
+ * fr-land, de-land, or sw600dp:
+ *
+ * (PASS) fr-land
+ * (FAIL) fr
+ * (PASS) de-land
+ * (FAIL) de
+ * (FAIL) de-sw600dp
+ * (PASS) sw600dp
+ * (FAIL) sw600dp-land
+ */
+class StrongResourceFilter : public ResourceFilter {
+public:
+ StrongResourceFilter() {}
+ StrongResourceFilter(const std::set<ConfigDescription>& configs)
+ : mConfigs(configs) {}
+
+ android::status_t parse(const android::String8& str);
+
+ bool match(const android::ResTable_config& config) const {
+ std::set<ConfigDescription>::const_iterator iter = mConfigs.begin();
+ for (; iter != mConfigs.end(); iter++) {
+ if (iter->compare(config) == 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ inline const std::set<ConfigDescription>& getConfigs() const {
+ return mConfigs;
+ }
+
+private:
+ std::set<ConfigDescription> mConfigs;
+};
+
+/**
+ * Negates the response of the target filter.
+ */
+class InverseResourceFilter : public ResourceFilter {
+public:
+ InverseResourceFilter(const android::sp<ResourceFilter>& filter)
+ : mFilter(filter) {}
+
+ bool match(const android::ResTable_config& config) const {
+ return !mFilter->match(config);
+ }
+
+private:
+ const android::sp<ResourceFilter> mFilter;
+};
+
+/**
+ * A logical AND of all the added filters.
+ */
+class AndResourceFilter : public ResourceFilter {
+public:
+ void addFilter(const android::sp<ResourceFilter>& filter) {
+ mFilters.add(filter);
+ }
+
+ bool match(const android::ResTable_config& config) const {
+ const size_t N = mFilters.size();
+ for (size_t i = 0; i < N; i++) {
+ if (!mFilters[i]->match(config)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+private:
+ android::Vector<android::sp<ResourceFilter> > mFilters;
+};
#endif
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 6eab65b..efbba40 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2095,10 +2095,10 @@
return mNumLocal > 0;
}
-sp<AaptFile> ResourceTable::flatten(Bundle* bundle)
+sp<AaptFile> ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter)
{
sp<AaptFile> data = new AaptFile(String8(), AaptGroupEntry(), String8());
- status_t err = flatten(bundle, data);
+ status_t err = flatten(bundle, filter, data);
return err == NO_ERROR ? data : NULL;
}
@@ -2658,8 +2658,8 @@
}
// Check that all requested localizations are present for this string
- if (mBundle->getConfigurations() != NULL && mBundle->getRequireLocalization()) {
- const char* allConfigs = mBundle->getConfigurations();
+ if (mBundle->getConfigurations().size() > 0 && mBundle->getRequireLocalization()) {
+ const char* allConfigs = mBundle->getConfigurations().string();
const char* start = allConfigs;
const char* comma;
@@ -2713,14 +2713,8 @@
return err;
}
-status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
+status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter, const sp<AaptFile>& dest)
{
- ResourceFilter filter;
- status_t err = filter.parse(bundle->getConfigurations());
- if (err != NO_ERROR) {
- return err;
- }
-
const ConfigDescription nullConfig;
const size_t N = mOrderedPackages.size();
@@ -2795,7 +2789,7 @@
const size_t N = c->getEntries().size();
for (size_t ei=0; ei<N; ei++) {
ConfigDescription config = c->getEntries().keyAt(ei);
- if (filterable && !filter.match(config)) {
+ if (filterable && !filter->match(config)) {
continue;
}
sp<Entry> e = c->getEntries().valueAt(ei);
@@ -2887,7 +2881,7 @@
return amt;
}
- err = flattenLibraryTable(data, libraryPackages);
+ status_t err = flattenLibraryTable(data, libraryPackages);
if (err != NO_ERROR) {
fprintf(stderr, "ERROR: failed to write library table\n");
return err;
@@ -2943,11 +2937,11 @@
}
const size_t CN = cl->getEntries().size();
for (size_t ci=0; ci<CN; ci++) {
- if (filterable && !filter.match(cl->getEntries().keyAt(ci))) {
+ if (filterable && !filter->match(cl->getEntries().keyAt(ci))) {
continue;
}
for (size_t cj=ci+1; cj<CN; cj++) {
- if (filterable && !filter.match(cl->getEntries().keyAt(cj))) {
+ if (filterable && !filter->match(cl->getEntries().keyAt(cj))) {
continue;
}
typeSpecFlags[ei] |= htodl(
@@ -2989,7 +2983,7 @@
config.screenHeightDp,
config.layoutDirection));
- if (filterable && !filter.match(config)) {
+ if (filterable && !filter->match(config)) {
continue;
}
@@ -3108,7 +3102,7 @@
}
ssize_t strStart = dest->getSize();
- err = valueStrings.writeStringBlock(dest);
+ status_t err = valueStrings.writeStringBlock(dest);
if (err != NO_ERROR) {
return err;
}
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index ec8fd175e..a73993c 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -7,8 +7,10 @@
#ifndef RESOURCE_TABLE_H
#define RESOURCE_TABLE_H
+#include "ConfigDescription.h"
#include "StringPool.h"
#include "SourcePos.h"
+#include "ResourceFilter.h"
#include <set>
#include <map>
@@ -76,37 +78,6 @@
class Type;
class Entry;
- struct ConfigDescription : public ResTable_config {
- ConfigDescription() {
- memset(this, 0, sizeof(*this));
- size = sizeof(ResTable_config);
- }
- ConfigDescription(const ResTable_config&o) {
- *static_cast<ResTable_config*>(this) = o;
- size = sizeof(ResTable_config);
- }
- ConfigDescription(const ConfigDescription&o) {
- *static_cast<ResTable_config*>(this) = o;
- }
-
- ConfigDescription& operator=(const ResTable_config& o) {
- *static_cast<ResTable_config*>(this) = o;
- size = sizeof(ResTable_config);
- return *this;
- }
- ConfigDescription& operator=(const ConfigDescription& o) {
- *static_cast<ResTable_config*>(this) = o;
- return *this;
- }
-
- inline bool operator<(const ConfigDescription& o) const { return compare(o) < 0; }
- inline bool operator<=(const ConfigDescription& o) const { return compare(o) <= 0; }
- inline bool operator==(const ConfigDescription& o) const { return compare(o) == 0; }
- inline bool operator!=(const ConfigDescription& o) const { return compare(o) != 0; }
- inline bool operator>=(const ConfigDescription& o) const { return compare(o) >= 0; }
- inline bool operator>(const ConfigDescription& o) const { return compare(o) > 0; }
- };
-
ResourceTable(Bundle* bundle, const String16& assetsPackage);
status_t addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets);
@@ -182,7 +153,7 @@
size_t numLocalResources() const;
bool hasResources() const;
- sp<AaptFile> flatten(Bundle*);
+ sp<AaptFile> flatten(Bundle* bundle, const sp<const ResourceFilter>& filter);
static inline uint32_t makeResId(uint32_t packageId,
uint32_t typeId,
@@ -223,7 +194,7 @@
void addLocalization(const String16& name, const String8& locale, const SourcePos& src);
status_t validateLocalizations(void);
- status_t flatten(Bundle*, const sp<AaptFile>& dest);
+ status_t flatten(Bundle* bundle, const sp<const ResourceFilter>& filter, const sp<AaptFile>& dest);
status_t flattenLibraryTable(const sp<AaptFile>& dest, const Vector<sp<Package> >& libs);
void writePublicDefinitions(const String16& package, FILE* fp);
diff --git a/tools/aapt/tests/AaptConfig_test.cpp b/tools/aapt/tests/AaptConfig_test.cpp
new file mode 100644
index 0000000..e795d818
--- /dev/null
+++ b/tools/aapt/tests/AaptConfig_test.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/String8.h>
+#include <gtest/gtest.h>
+
+#include "AaptConfig.h"
+#include "ConfigDescription.h"
+#include "TestHelper.h"
+
+using android::String8;
+
+static ::testing::AssertionResult TestParse(const String8& input, ConfigDescription* config=NULL) {
+ if (AaptConfig::parse(String8(input), config)) {
+ return ::testing::AssertionSuccess() << input << " was successfully parsed";
+ }
+ return ::testing::AssertionFailure() << input << " could not be parsed";
+}
+
+static ::testing::AssertionResult TestParse(const char* input, ConfigDescription* config=NULL) {
+ return TestParse(String8(input), config);
+}
+
+TEST(AaptConfigTest, ParseFailWhenQualifiersAreOutOfOrder) {
+ EXPECT_FALSE(TestParse("en-sw600dp-ldrtl"));
+ EXPECT_FALSE(TestParse("land-en"));
+ EXPECT_FALSE(TestParse("hdpi-320dpi"));
+}
+
+TEST(AaptConfigTest, ParseFailWhenQualifiersAreNotMatched) {
+ EXPECT_FALSE(TestParse("en-sw600dp-ILLEGAL"));
+}
+
+TEST(AaptConfigTest, ParseFailWhenQualifiersHaveTrailingDash) {
+ EXPECT_FALSE(TestParse("en-sw600dp-land-"));
+}
+
+TEST(AaptConfigTest, ParseBasicQualifiers) {
+ ConfigDescription config;
+ EXPECT_TRUE(TestParse("", &config));
+ EXPECT_EQ(String8(""), config.toString());
+
+ EXPECT_TRUE(TestParse("fr-land", &config));
+ EXPECT_EQ(String8("fr-land"), config.toString());
+
+ EXPECT_TRUE(TestParse("mcc310-pl-sw720dp-normal-long-port-night-"
+ "xhdpi-keyssoft-qwerty-navexposed-nonav", &config));
+ EXPECT_EQ(String8("mcc310-pl-sw720dp-normal-long-port-night-"
+ "xhdpi-keyssoft-qwerty-navexposed-nonav-v13"), config.toString());
+}
+
+TEST(AaptConfigTest, ParseLocales) {
+ ConfigDescription config;
+ EXPECT_TRUE(TestParse("en-rUS", &config));
+ EXPECT_EQ(String8("en-US"), config.toString());
+}
+
+TEST(AaptConfigTest, ParseQualifierAddedInApi13) {
+ ConfigDescription config;
+ EXPECT_TRUE(TestParse("sw600dp", &config));
+ EXPECT_EQ(String8("sw600dp-v13"), config.toString());
+
+ EXPECT_TRUE(TestParse("sw600dp-v8", &config));
+ EXPECT_EQ(String8("sw600dp-v13"), config.toString());
+}
diff --git a/tools/aapt/tests/AaptGroupEntry_test.cpp b/tools/aapt/tests/AaptGroupEntry_test.cpp
new file mode 100644
index 0000000..7348a08
--- /dev/null
+++ b/tools/aapt/tests/AaptGroupEntry_test.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/String8.h>
+#include <gtest/gtest.h>
+
+#include "AaptAssets.h"
+#include "ResourceFilter.h"
+#include "TestHelper.h"
+
+using android::String8;
+
+static ::testing::AssertionResult TestParse(AaptGroupEntry& entry, const String8& dirName,
+ String8* outType) {
+ if (entry.initFromDirName(dirName, outType)) {
+ return ::testing::AssertionSuccess() << dirName << " was successfully parsed";
+ }
+ return ::testing::AssertionFailure() << dirName << " could not be parsed";
+}
+
+static ::testing::AssertionResult TestParse(AaptGroupEntry& entry, const char* input,
+ String8* outType) {
+ return TestParse(entry, String8(input), outType);
+}
+
+TEST(AaptGroupEntryTest, ParseNoQualifier) {
+ AaptGroupEntry entry;
+ String8 type;
+ EXPECT_TRUE(TestParse(entry, "menu", &type));
+ EXPECT_EQ(String8("menu"), type);
+}
+
+TEST(AaptGroupEntryTest, ParseCorrectType) {
+ AaptGroupEntry entry;
+ String8 type;
+ EXPECT_TRUE(TestParse(entry, "anim", &type));
+ EXPECT_EQ(String8("anim"), type);
+
+ EXPECT_TRUE(TestParse(entry, "animator", &type));
+ EXPECT_EQ(String8("animator"), type);
+}
diff --git a/tools/aapt/tests/ResourceFilter_test.cpp b/tools/aapt/tests/ResourceFilter_test.cpp
new file mode 100644
index 0000000..30697bb
--- /dev/null
+++ b/tools/aapt/tests/ResourceFilter_test.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <androidfw/ResourceTypes.h>
+#include <utils/String8.h>
+#include <gtest/gtest.h>
+
+#include "AaptConfig.h"
+#include "ResourceFilter.h"
+#include "ConfigDescription.h"
+
+using android::String8;
+
+// In this context, 'Axis' represents a particular field in the configuration,
+// such as language or density.
+
+TEST(WeakResourceFilterTest, EmptyFilterMatchesAnything) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("")));
+
+ ConfigDescription config;
+ config.density = 320;
+
+ EXPECT_TRUE(filter.match(config));
+
+ config.language[0] = 'f';
+ config.language[1] = 'r';
+
+ EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesConfigWithUnrelatedAxis) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("fr")));
+
+ ConfigDescription config;
+ config.density = 320;
+
+ EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesConfigWithSameValueAxis) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("fr")));
+
+ ConfigDescription config;
+ config.language[0] = 'f';
+ config.language[1] = 'r';
+
+ EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesConfigWithSameValueAxisAndOtherUnrelatedAxis) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("fr")));
+
+ ConfigDescription config;
+ config.language[0] = 'f';
+ config.language[1] = 'r';
+ config.density = 320;
+
+ EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, DoesNotMatchConfigWithDifferentValueAxis) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("fr")));
+
+ ConfigDescription config;
+ config.language[0] = 'd';
+ config.language[1] = 'e';
+
+ EXPECT_FALSE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesConfigWithSameLanguageButNoRegionSpecified) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("de-rDE")));
+
+ ConfigDescription config;
+ config.language[0] = 'd';
+ config.language[1] = 'e';
+
+ EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, ParsesStandardLocaleOnlyString) {
+ WeakResourceFilter filter;
+ EXPECT_EQ(NO_ERROR, filter.parse(String8("de_DE")));
+}
+
+TEST(WeakResourceFilterTest, IgnoresVersion) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("normal-v4")));
+
+ ConfigDescription config;
+ config.smallestScreenWidthDp = 600;
+ config.version = 13;
+
+ // The configs don't match on any axis besides version, which should be ignored.
+ EXPECT_TRUE(filter.match(config));
+}
+
+TEST(WeakResourceFilterTest, MatchesConfigWithRegion) {
+ WeakResourceFilter filter;
+ ASSERT_EQ(NO_ERROR, filter.parse(String8("kok,kok_IN,kok_419")));
+
+ ConfigDescription config;
+ AaptLocaleValue val;
+ ASSERT_TRUE(val.initFromFilterString(String8("kok_IN")));
+ val.writeTo(&config);
+
+ EXPECT_TRUE(filter.match(config));
+}
+
diff --git a/tools/aapt/tests/TestHelper.h b/tools/aapt/tests/TestHelper.h
new file mode 100644
index 0000000..79174832
--- /dev/null
+++ b/tools/aapt/tests/TestHelper.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TEST_HELPER_H
+#define __TEST_HELPER_H
+
+#include <utils/String8.h>
+
+namespace android {
+
+/**
+ * Stream operator for nicely printing String8's in gtest output.
+ */
+inline std::ostream& operator<<(std::ostream& stream, const String8& str) {
+ return stream << str.string();
+}
+
+}
+
+#endif
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 9787432..4af73cf 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
@@ -183,6 +183,7 @@
SessionParams params = getParams();
BridgeContext context = getContext();
+
RenderResources resources = getParams().getResources();
DisplayMetrics metrics = getContext().getMetrics();
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 813a895..59979ce 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
@@ -137,6 +137,7 @@
"android.text.format.DateFormat#is24HourFormat",
"android.view.Choreographer#getRefreshRate",
"android.view.Display#updateDisplayInfoLocked",
+ "android.view.Display#getWindowManager",
"android.view.LayoutInflater#rInflate",
"android.view.LayoutInflater#parseInclude",
"android.view.View#isInEditMode",
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 5af1e4e..15b65c1 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -402,12 +402,12 @@
public static final String EXTRA_LINK_PROPERTIES = "linkProperties";
/**
- * The lookup key for a {@link android.net.LinkCapabilities} object associated with the
+ * The lookup key for a {@link android.net.NetworkCapabilities} object associated with the
* Wi-Fi network. Retrieve with
* {@link android.content.Intent#getParcelableExtra(String)}.
* @hide
*/
- public static final String EXTRA_LINK_CAPABILITIES = "linkCapabilities";
+ public static final String EXTRA_NETWORK_CAPABILITIES = "networkCapabilities";
/**
* The network IDs of the configured networks could have changed.
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
deleted file mode 100644
index 7ded171..0000000
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.BaseNetworkStateTracker;
-import android.net.LinkCapabilities;
-import android.net.LinkQualityInfo;
-import android.net.LinkProperties;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
-import android.net.SamplingDataTracker;
-import android.net.WifiLinkQualityInfo;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
-import android.util.Slog;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Track the state of wifi for connectivity service.
- *
- * @hide
- */
-public class WifiStateTracker extends BaseNetworkStateTracker {
-
- private static final String NETWORKTYPE = "WIFI";
- private static final String TAG = "WifiStateTracker";
-
- private static final boolean LOGV = true;
-
- private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
- private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
- private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
-
- private NetworkInfo.State mLastState = NetworkInfo.State.UNKNOWN;
-
- private WifiInfo mWifiInfo;
-
- /* For sending events to connectivity service handler */
- private Handler mCsHandler;
- private BroadcastReceiver mWifiStateReceiver;
- private WifiManager mWifiManager;
-
- private SamplingDataTracker mSamplingDataTracker = new SamplingDataTracker();
-
- public WifiStateTracker(int netType, String networkName) {
- mNetworkInfo = new NetworkInfo(netType, 0, networkName, "");
- mLinkProperties = new LinkProperties();
- mLinkCapabilities = new LinkCapabilities();
-
- mNetworkInfo.setIsAvailable(false);
- setTeardownRequested(false);
- }
-
-
- public void setTeardownRequested(boolean isRequested) {
- mTeardownRequested.set(isRequested);
- }
-
- public boolean isTeardownRequested() {
- return mTeardownRequested.get();
- }
-
- /**
- * Begin monitoring wifi connectivity
- */
- public void startMonitoring(Context context, Handler target) {
- mCsHandler = target;
- mContext = context;
-
- mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- IntentFilter filter = new IntentFilter();
- filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
- filter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
-
- mWifiStateReceiver = new WifiStateReceiver();
- mContext.registerReceiver(mWifiStateReceiver, filter);
- }
-
- /**
- * Disable connectivity to a network
- * TODO: do away with return value after making MobileDataStateTracker async
- */
- public boolean teardown() {
- mTeardownRequested.set(true);
- mWifiManager.stopWifi();
- return true;
- }
-
- /**
- * Re-enable connectivity to a network after a {@link #teardown()}.
- */
- public boolean reconnect() {
- mTeardownRequested.set(false);
- mWifiManager.startWifi();
- return true;
- }
-
- @Override
- public void captivePortalCheckCompleted(boolean isCaptivePortal) {
- // not implemented
- }
-
- /**
- * Turn the wireless radio off for a network.
- * @param turnOn {@code true} to turn the radio on, {@code false}
- */
- public boolean setRadio(boolean turnOn) {
- mWifiManager.setWifiEnabled(turnOn);
- return true;
- }
-
- /**
- * Wi-Fi is considered available as long as we have a connection to the
- * supplicant daemon and there is at least one enabled network. If a teardown
- * was explicitly requested, then Wi-Fi can be restarted with a reconnect
- * request, so it is considered available. If the driver has been stopped
- * for any reason other than a teardown request, Wi-Fi is considered
- * unavailable.
- * @return {@code true} if Wi-Fi connections are possible
- */
- public boolean isAvailable() {
- return mNetworkInfo.isAvailable();
- }
-
- @Override
- public void setUserDataEnable(boolean enabled) {
- Slog.w(TAG, "ignoring setUserDataEnable(" + enabled + ")");
- }
-
- @Override
- public void setPolicyDataEnable(boolean enabled) {
- // ignored
- }
-
- /**
- * Check if private DNS route is set for the network
- */
- public boolean isPrivateDnsRouteSet() {
- return mPrivateDnsRouteSet.get();
- }
-
- /**
- * Set a flag indicating private DNS route is set
- */
- public void privateDnsRouteSet(boolean enabled) {
- mPrivateDnsRouteSet.set(enabled);
- }
-
- /**
- * Fetch NetworkInfo for the network
- */
- @Override
- public NetworkInfo getNetworkInfo() {
- return new NetworkInfo(mNetworkInfo);
- }
-
- /**
- * Fetch LinkProperties for the network
- */
- @Override
- public LinkProperties getLinkProperties() {
- return new LinkProperties(mLinkProperties);
- }
-
- /**
- * A capability is an Integer/String pair, the capabilities
- * are defined in the class LinkSocket#Key.
- *
- * @return a copy of this connections capabilities, may be empty but never null.
- */
- @Override
- public LinkCapabilities getLinkCapabilities() {
- return new LinkCapabilities(mLinkCapabilities);
- }
-
- /**
- * Return link info
- * @return an object of type WifiLinkQualityInfo
- */
- @Override
- public LinkQualityInfo getLinkQualityInfo() {
- if (mNetworkInfo == null) {
- // no data available yet; just return
- return null;
- }
-
- WifiLinkQualityInfo li = new WifiLinkQualityInfo();
- li.setNetworkType(mNetworkInfo.getType());
-
- synchronized(mSamplingDataTracker.mSamplingDataLock) {
- mSamplingDataTracker.setCommonLinkQualityInfoFields(li);
- li.setTxGood(mSamplingDataTracker.getSampledTxPacketCount());
- li.setTxBad(mSamplingDataTracker.getSampledTxPacketErrorCount());
- }
-
- // li.setTheoreticalRxBandwidth(??);
- // li.setTheoreticalTxBandwidth(??);
-
- if (mWifiInfo != null) {
- li.setBssid(mWifiInfo.getBSSID());
-
- int rssi = mWifiInfo.getRssi();
- li.setRssi(rssi);
-
- li.setNormalizedSignalStrength(mWifiManager.calculateSignalLevel(rssi,
- LinkQualityInfo.NORMALIZED_SIGNAL_STRENGTH_RANGE));
- }
-
- return li;
- }
-
- /**
- * Check if default route is set
- */
- public boolean isDefaultRouteSet() {
- return mDefaultRouteSet.get();
- }
-
- /**
- * Set a flag indicating default route is set for the network
- */
- public void defaultRouteSet(boolean enabled) {
- mDefaultRouteSet.set(enabled);
- }
-
- /**
- * Return the system properties name associated with the tcp buffer sizes
- * for this network.
- */
- public String getTcpBufferSizesPropName() {
- return "net.tcp.buffersize.wifi";
- }
-
- private class WifiStateReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
-
- if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
- mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
- WifiManager.EXTRA_NETWORK_INFO);
-
- mLinkProperties = intent.getParcelableExtra(
- WifiManager.EXTRA_LINK_PROPERTIES);
- if (mLinkProperties == null) {
- mLinkProperties = new LinkProperties();
- }
- mLinkCapabilities = intent.getParcelableExtra(
- WifiManager.EXTRA_LINK_CAPABILITIES);
- if (mLinkCapabilities == null) {
- mLinkCapabilities = new LinkCapabilities();
- }
-
- mWifiInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
- // don't want to send redundant state messages
- // but send portal check detailed state notice
- NetworkInfo.State state = mNetworkInfo.getState();
- if (mLastState == state &&
- mNetworkInfo.getDetailedState() != DetailedState.CAPTIVE_PORTAL_CHECK) {
- return;
- } else {
- mLastState = state;
- /* lets not sample traffic data across state changes */
- mSamplingDataTracker.resetSamplingData();
- }
-
- Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED,
- new NetworkInfo(mNetworkInfo));
- msg.sendToTarget();
- } else if (intent.getAction().equals(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION)) {
- mLinkProperties = intent.getParcelableExtra(WifiManager.EXTRA_LINK_PROPERTIES);
- Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
- msg.sendToTarget();
- }
- }
- }
-
- public void setDependencyMet(boolean met) {
- // not supported on this network
- }
-
- @Override
- public void addStackedLink(LinkProperties link) {
- mLinkProperties.addStackedLink(link);
- }
-
- @Override
- public void removeStackedLink(LinkProperties link) {
- mLinkProperties.removeStackedLink(link);
- }
-
- @Override
- public void supplyMessenger(Messenger messenger) {
- // not supported on this network
- }
-
- @Override
- public void startSampling(SamplingDataTracker.SamplingSnapshot s) {
- mSamplingDataTracker.startSampling(s);
- }
-
- @Override
- public void stopSampling(SamplingDataTracker.SamplingSnapshot s) {
- mSamplingDataTracker.stopSampling(s);
- }
-}
-