Merge "Avoid caching shadow properties in Java & HWUI."
diff --git a/Android.mk b/Android.mk
index 232f5bf..99d73fa 100644
--- a/Android.mk
+++ b/Android.mk
@@ -76,7 +76,8 @@
core/java/android/app/ISearchManagerCallback.aidl \
core/java/android/app/IServiceConnection.aidl \
core/java/android/app/IStopUserCallback.aidl \
- core/java/android/app/IThumbnailReceiver.aidl \
+ core/java/android/app/task/ITaskCallback.aidl \
+ core/java/android/app/task/ITaskService.aidl \
core/java/android/app/IThumbnailRetriever.aidl \
core/java/android/app/ITransientNotification.aidl \
core/java/android/app/IUiAutomationConnection.aidl \
@@ -155,6 +156,7 @@
core/java/android/net/INetworkManagementEventObserver.aidl \
core/java/android/net/INetworkPolicyListener.aidl \
core/java/android/net/INetworkPolicyManager.aidl \
+ core/java/android/net/INetworkScoreCache.aidl \
core/java/android/net/INetworkScoreService.aidl \
core/java/android/net/INetworkStatsService.aidl \
core/java/android/net/INetworkStatsSession.aidl \
@@ -197,6 +199,8 @@
core/java/android/service/dreams/IDozeHardware.aidl \
core/java/android/service/dreams/IDreamManager.aidl \
core/java/android/service/dreams/IDreamService.aidl \
+ core/java/android/service/fingerprint/IFingerprintService.aidl \
+ core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl \
core/java/android/service/trust/ITrustAgentService.aidl \
core/java/android/service/trust/ITrustAgentServiceCallback.aidl \
core/java/android/service/voice/IVoiceInteractionService.aidl \
@@ -316,6 +320,7 @@
wifi/java/android/net/wifi/IWifiManager.aidl \
wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl \
wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
+ wifi/java/android/net/wifi/IWifiScanner.aidl \
packages/services/PacProcessor/com/android/net/IProxyService.aidl \
packages/services/Proxy/com/android/net/IProxyCallback.aidl \
packages/services/Proxy/com/android/net/IProxyPortListener.aidl \
@@ -716,8 +721,9 @@
$(full_target): $(framework_built) $(gen)
# Run this for checkbuild
-.PHONY: checkbuild
checkbuild: doc-comment-check-docs
+# Check comment when you are updating the API
+update-api: doc-comment-check-docs
# ==== static html in the sdk ==================================
include $(CLEAR_VARS)
diff --git a/CleanSpec.mk b/CleanSpec.mk
index c6f6a62..c841338 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -190,6 +190,7 @@
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/view/IMagnificationCallbacks*)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/tv/)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/media/java/android/media/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/api/current.txt b/api/current.txt
index 7615d4f..302e77e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -267,6 +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 = 16843857; // 0x1010451
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,6 +314,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 = 16843859; // 0x1010453
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
@@ -462,6 +464,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 = 16843858; // 0x1010452
field public static final int drawSelectorOnTop = 16843004; // 0x10100fc
field public static final int drawable = 16843161; // 0x1010199
field public static final int drawableBottom = 16843118; // 0x101016e
@@ -491,7 +494,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 = 16843852; // 0x101044c
+ field public static final int elevation = 16843853; // 0x101044d
field public static final int ellipsize = 16842923; // 0x10100ab
field public static final int ems = 16843096; // 0x1010158
field public static final int enabled = 16842766; // 0x101000e
@@ -501,9 +504,9 @@
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 = 16843854; // 0x101044e
+ field public static final int excludeClass = 16843855; // 0x101044f
field public static final int excludeFromRecents = 16842775; // 0x1010017
- field public static final int excludeId = 16843853; // 0x101044d
+ field public static final int excludeId = 16843854; // 0x101044e
field public static final int exitFadeDuration = 16843533; // 0x101030d
field public static final int expandableListPreferredChildIndicatorLeft = 16842834; // 0x1010052
field public static final int expandableListPreferredChildIndicatorRight = 16842835; // 0x1010053
@@ -598,6 +601,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 = 16843856; // 0x1010450
field public static final int hint = 16843088; // 0x1010150
field public static final int homeAsUpIndicator = 16843531; // 0x101030b
field public static final int homeLayout = 16843549; // 0x101031d
@@ -1051,11 +1055,13 @@
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 = 16843851; // 0x101044b
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 = 16843860; // 0x1010454
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
@@ -1108,7 +1114,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 = 16843851; // 0x101044b
+ field public static final int switchStyle = 16843852; // 0x101044c
field public static final int switchTextAppearance = 16843630; // 0x101036e
field public static final int switchTextOff = 16843628; // 0x101036c
field public static final int switchTextOn = 16843627; // 0x101036b
@@ -1855,52 +1861,52 @@
field public static final int TextAppearance_Large_Inverse = 16973891; // 0x1030043
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 = 16974346; // 0x103020a
- field public static final int TextAppearance_Quantum_Body1 = 16974538; // 0x10302ca
- field public static final int TextAppearance_Quantum_Body2 = 16974537; // 0x10302c9
- field public static final int TextAppearance_Quantum_Button = 16974541; // 0x10302cd
- field public static final int TextAppearance_Quantum_Caption = 16974539; // 0x10302cb
- field public static final int TextAppearance_Quantum_DialogWindowTitle = 16974347; // 0x103020b
- field public static final int TextAppearance_Quantum_Display1 = 16974533; // 0x10302c5
- field public static final int TextAppearance_Quantum_Display2 = 16974532; // 0x10302c4
- field public static final int TextAppearance_Quantum_Display3 = 16974531; // 0x10302c3
- field public static final int TextAppearance_Quantum_Display4 = 16974530; // 0x10302c2
- field public static final int TextAppearance_Quantum_Headline = 16974534; // 0x10302c6
- field public static final int TextAppearance_Quantum_Inverse = 16974348; // 0x103020c
- field public static final int TextAppearance_Quantum_Large = 16974349; // 0x103020d
- field public static final int TextAppearance_Quantum_Large_Inverse = 16974350; // 0x103020e
- field public static final int TextAppearance_Quantum_Medium = 16974351; // 0x103020f
- field public static final int TextAppearance_Quantum_Medium_Inverse = 16974352; // 0x1030210
- field public static final int TextAppearance_Quantum_Menu = 16974540; // 0x10302cc
- field public static final int TextAppearance_Quantum_SearchResult_Subtitle = 16974353; // 0x1030211
- field public static final int TextAppearance_Quantum_SearchResult_Title = 16974354; // 0x1030212
- field public static final int TextAppearance_Quantum_Small = 16974355; // 0x1030213
- field public static final int TextAppearance_Quantum_Small_Inverse = 16974356; // 0x1030214
- field public static final int TextAppearance_Quantum_Subhead = 16974536; // 0x10302c8
- field public static final int TextAppearance_Quantum_Title = 16974535; // 0x10302c7
- field public static final int TextAppearance_Quantum_Widget = 16974358; // 0x1030216
- field public static final int TextAppearance_Quantum_Widget_ActionBar_Menu = 16974359; // 0x1030217
- field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle = 16974360; // 0x1030218
- field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle_Inverse = 16974361; // 0x1030219
- field public static final int TextAppearance_Quantum_Widget_ActionBar_Title = 16974362; // 0x103021a
- field public static final int TextAppearance_Quantum_Widget_ActionBar_Title_Inverse = 16974363; // 0x103021b
- field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle = 16974364; // 0x103021c
- field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle_Inverse = 16974365; // 0x103021d
- field public static final int TextAppearance_Quantum_Widget_ActionMode_Title = 16974366; // 0x103021e
- field public static final int TextAppearance_Quantum_Widget_ActionMode_Title_Inverse = 16974367; // 0x103021f
- field public static final int TextAppearance_Quantum_Widget_Button = 16974368; // 0x1030220
- field public static final int TextAppearance_Quantum_Widget_DropDownHint = 16974369; // 0x1030221
- field public static final int TextAppearance_Quantum_Widget_DropDownItem = 16974370; // 0x1030222
- field public static final int TextAppearance_Quantum_Widget_EditText = 16974371; // 0x1030223
- field public static final int TextAppearance_Quantum_Widget_IconMenu_Item = 16974372; // 0x1030224
- field public static final int TextAppearance_Quantum_Widget_PopupMenu = 16974373; // 0x1030225
- field public static final int TextAppearance_Quantum_Widget_PopupMenu_Large = 16974374; // 0x1030226
- field public static final int TextAppearance_Quantum_Widget_PopupMenu_Small = 16974375; // 0x1030227
- field public static final int TextAppearance_Quantum_Widget_TabWidget = 16974376; // 0x1030228
- field public static final int TextAppearance_Quantum_Widget_TextView = 16974377; // 0x1030229
- field public static final int TextAppearance_Quantum_Widget_TextView_PopupMenu = 16974378; // 0x103022a
- field public static final int TextAppearance_Quantum_Widget_TextView_SpinnerItem = 16974379; // 0x103022b
- field public static final int TextAppearance_Quantum_WindowTitle = 16974357; // 0x1030215
+ 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_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_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_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_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
+ field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle_Inverse = 16974367; // 0x103021f
+ field public static final int TextAppearance_Quantum_Widget_ActionBar_Title = 16974368; // 0x1030220
+ field public static final int TextAppearance_Quantum_Widget_ActionBar_Title_Inverse = 16974369; // 0x1030221
+ field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle = 16974370; // 0x1030222
+ field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle_Inverse = 16974371; // 0x1030223
+ field public static final int TextAppearance_Quantum_Widget_ActionMode_Title = 16974372; // 0x1030224
+ field public static final int TextAppearance_Quantum_Widget_ActionMode_Title_Inverse = 16974373; // 0x1030225
+ field public static final int TextAppearance_Quantum_Widget_Button = 16974374; // 0x1030226
+ field public static final int TextAppearance_Quantum_Widget_DropDownHint = 16974375; // 0x1030227
+ field public static final int TextAppearance_Quantum_Widget_DropDownItem = 16974376; // 0x1030228
+ field public static final int TextAppearance_Quantum_Widget_EditText = 16974377; // 0x1030229
+ field public static final int TextAppearance_Quantum_Widget_IconMenu_Item = 16974378; // 0x103022a
+ field public static final int TextAppearance_Quantum_Widget_PopupMenu = 16974379; // 0x103022b
+ field public static final int TextAppearance_Quantum_Widget_PopupMenu_Large = 16974380; // 0x103022c
+ field public static final int TextAppearance_Quantum_Widget_PopupMenu_Small = 16974381; // 0x103022d
+ field public static final int TextAppearance_Quantum_Widget_TabWidget = 16974382; // 0x103022e
+ field public static final int TextAppearance_Quantum_Widget_TextView = 16974383; // 0x103022f
+ field public static final int TextAppearance_Quantum_Widget_TextView_PopupMenu = 16974384; // 0x1030230
+ field public static final int TextAppearance_Quantum_Widget_TextView_SpinnerItem = 16974385; // 0x1030231
+ field public static final int TextAppearance_Quantum_WindowTitle = 16974363; // 0x103021b
field public static final int TextAppearance_Small = 16973894; // 0x1030046
field public static final int TextAppearance_Small_Inverse = 16973895; // 0x1030047
field public static final int TextAppearance_StatusBar_EventContent = 16973927; // 0x1030067
@@ -1995,34 +2001,34 @@
field public static final int Theme_NoTitleBar_Fullscreen = 16973831; // 0x1030007
field public static final int Theme_NoTitleBar_OverlayActionModes = 16973930; // 0x103006a
field public static final int Theme_Panel = 16973913; // 0x1030059
- field public static final int Theme_Quantum = 16974380; // 0x103022c
- field public static final int Theme_Quantum_Dialog = 16974381; // 0x103022d
- field public static final int Theme_Quantum_DialogWhenLarge = 16974385; // 0x1030231
- field public static final int Theme_Quantum_DialogWhenLarge_NoActionBar = 16974386; // 0x1030232
- field public static final int Theme_Quantum_Dialog_MinWidth = 16974382; // 0x103022e
- field public static final int Theme_Quantum_Dialog_NoActionBar = 16974383; // 0x103022f
- field public static final int Theme_Quantum_Dialog_NoActionBar_MinWidth = 16974384; // 0x1030230
- field public static final int Theme_Quantum_InputMethod = 16974387; // 0x1030233
- field public static final int Theme_Quantum_Light = 16974395; // 0x103023b
- field public static final int Theme_Quantum_Light_DarkActionBar = 16974396; // 0x103023c
- field public static final int Theme_Quantum_Light_Dialog = 16974397; // 0x103023d
- field public static final int Theme_Quantum_Light_DialogWhenLarge = 16974401; // 0x1030241
- field public static final int Theme_Quantum_Light_DialogWhenLarge_NoActionBar = 16974402; // 0x1030242
- field public static final int Theme_Quantum_Light_Dialog_MinWidth = 16974398; // 0x103023e
- field public static final int Theme_Quantum_Light_Dialog_NoActionBar = 16974399; // 0x103023f
- field public static final int Theme_Quantum_Light_Dialog_NoActionBar_MinWidth = 16974400; // 0x1030240
- field public static final int Theme_Quantum_Light_NoActionBar = 16974403; // 0x1030243
- field public static final int Theme_Quantum_Light_NoActionBar_Fullscreen = 16974404; // 0x1030244
- field public static final int Theme_Quantum_Light_NoActionBar_Overscan = 16974405; // 0x1030245
- field public static final int Theme_Quantum_Light_NoActionBar_TranslucentDecor = 16974406; // 0x1030246
- field public static final int Theme_Quantum_Light_Panel = 16974407; // 0x1030247
- field public static final int Theme_Quantum_NoActionBar = 16974388; // 0x1030234
- field public static final int Theme_Quantum_NoActionBar_Fullscreen = 16974389; // 0x1030235
- field public static final int Theme_Quantum_NoActionBar_Overscan = 16974390; // 0x1030236
- field public static final int Theme_Quantum_NoActionBar_TranslucentDecor = 16974391; // 0x1030237
- field public static final int Theme_Quantum_Panel = 16974392; // 0x1030238
- field public static final int Theme_Quantum_Wallpaper = 16974393; // 0x1030239
- field public static final int Theme_Quantum_Wallpaper_NoTitleBar = 16974394; // 0x103023a
+ field public static final int Theme_Quantum = 16974386; // 0x1030232
+ field public static final int Theme_Quantum_Dialog = 16974387; // 0x1030233
+ field public static final int Theme_Quantum_DialogWhenLarge = 16974391; // 0x1030237
+ field public static final int Theme_Quantum_DialogWhenLarge_NoActionBar = 16974392; // 0x1030238
+ field public static final int Theme_Quantum_Dialog_MinWidth = 16974388; // 0x1030234
+ field public static final int Theme_Quantum_Dialog_NoActionBar = 16974389; // 0x1030235
+ field public static final int Theme_Quantum_Dialog_NoActionBar_MinWidth = 16974390; // 0x1030236
+ field public static final int Theme_Quantum_InputMethod = 16974393; // 0x1030239
+ field public static final int Theme_Quantum_Light = 16974401; // 0x1030241
+ field public static final int Theme_Quantum_Light_DarkActionBar = 16974402; // 0x1030242
+ field public static final int Theme_Quantum_Light_Dialog = 16974403; // 0x1030243
+ field public static final int Theme_Quantum_Light_DialogWhenLarge = 16974407; // 0x1030247
+ field public static final int Theme_Quantum_Light_DialogWhenLarge_NoActionBar = 16974408; // 0x1030248
+ field public static final int Theme_Quantum_Light_Dialog_MinWidth = 16974404; // 0x1030244
+ field public static final int Theme_Quantum_Light_Dialog_NoActionBar = 16974405; // 0x1030245
+ field public static final int Theme_Quantum_Light_Dialog_NoActionBar_MinWidth = 16974406; // 0x1030246
+ field public static final int Theme_Quantum_Light_NoActionBar = 16974409; // 0x1030249
+ field public static final int Theme_Quantum_Light_NoActionBar_Fullscreen = 16974410; // 0x103024a
+ field public static final int Theme_Quantum_Light_NoActionBar_Overscan = 16974411; // 0x103024b
+ field public static final int Theme_Quantum_Light_NoActionBar_TranslucentDecor = 16974412; // 0x103024c
+ field public static final int Theme_Quantum_Light_Panel = 16974413; // 0x103024d
+ field public static final int Theme_Quantum_NoActionBar = 16974394; // 0x103023a
+ field public static final int Theme_Quantum_NoActionBar_Fullscreen = 16974395; // 0x103023b
+ field public static final int Theme_Quantum_NoActionBar_Overscan = 16974396; // 0x103023c
+ field public static final int Theme_Quantum_NoActionBar_TranslucentDecor = 16974397; // 0x103023d
+ field public static final int Theme_Quantum_Panel = 16974398; // 0x103023e
+ field public static final int Theme_Quantum_Wallpaper = 16974399; // 0x103023f
+ field public static final int Theme_Quantum_Wallpaper_NoTitleBar = 16974400; // 0x1030240
field public static final int Theme_Translucent = 16973839; // 0x103000f
field public static final int Theme_Translucent_NoTitleBar = 16973840; // 0x1030010
field public static final int Theme_Translucent_NoTitleBar_Fullscreen = 16973841; // 0x1030011
@@ -2079,8 +2085,8 @@
field public static final int Widget_DeviceDefault_DropDownItem_Spinner = 16974178; // 0x1030162
field public static final int Widget_DeviceDefault_EditText = 16974154; // 0x103014a
field public static final int Widget_DeviceDefault_ExpandableListView = 16974155; // 0x103014b
- field public static final int Widget_DeviceDefault_FastScroll = 16974344; // 0x1030208
- field public static final int Widget_DeviceDefault_FragmentBreadCrumbs = 16974339; // 0x1030203
+ field public static final int Widget_DeviceDefault_FastScroll = 16974346; // 0x103020a
+ field public static final int Widget_DeviceDefault_FragmentBreadCrumbs = 16974347; // 0x103020b
field public static final int Widget_DeviceDefault_GridView = 16974156; // 0x103014c
field public static final int Widget_DeviceDefault_HorizontalScrollView = 16974171; // 0x103015b
field public static final int Widget_DeviceDefault_ImageButton = 16974157; // 0x103014d
@@ -2114,8 +2120,8 @@
field public static final int Widget_DeviceDefault_Light_DropDownItem_Spinner = 16974233; // 0x1030199
field public static final int Widget_DeviceDefault_Light_EditText = 16974206; // 0x103017e
field public static final int Widget_DeviceDefault_Light_ExpandableListView = 16974207; // 0x103017f
- field public static final int Widget_DeviceDefault_Light_FastScroll = 16974345; // 0x1030209
- field public static final int Widget_DeviceDefault_Light_FragmentBreadCrumbs = 16974340; // 0x1030204
+ field public static final int Widget_DeviceDefault_Light_FastScroll = 16974349; // 0x103020d
+ field public static final int Widget_DeviceDefault_Light_FragmentBreadCrumbs = 16974350; // 0x103020e
field public static final int Widget_DeviceDefault_Light_GridView = 16974208; // 0x1030180
field public static final int Widget_DeviceDefault_Light_HorizontalScrollView = 16974226; // 0x1030192
field public static final int Widget_DeviceDefault_Light_ImageButton = 16974209; // 0x1030181
@@ -2139,6 +2145,7 @@
field public static final int Widget_DeviceDefault_Light_ScrollView = 16974225; // 0x1030191
field public static final int Widget_DeviceDefault_Light_SeekBar = 16974220; // 0x103018c
field public static final int Widget_DeviceDefault_Light_Spinner = 16974227; // 0x1030193
+ field public static final int Widget_DeviceDefault_Light_StackView = 16974351; // 0x103020f
field public static final int Widget_DeviceDefault_Light_Tab = 16974237; // 0x103019d
field public static final int Widget_DeviceDefault_Light_TabWidget = 16974229; // 0x1030195
field public static final int Widget_DeviceDefault_Light_TextView = 16974202; // 0x103017a
@@ -2162,6 +2169,7 @@
field public static final int Widget_DeviceDefault_ScrollView = 16974170; // 0x103015a
field public static final int Widget_DeviceDefault_SeekBar = 16974165; // 0x1030155
field public static final int Widget_DeviceDefault_Spinner = 16974172; // 0x103015c
+ field public static final int Widget_DeviceDefault_StackView = 16974348; // 0x103020c
field public static final int Widget_DeviceDefault_Tab = 16974189; // 0x103016d
field public static final int Widget_DeviceDefault_TabWidget = 16974174; // 0x103015e
field public static final int Widget_DeviceDefault_TextView = 16974150; // 0x1030146
@@ -2172,7 +2180,7 @@
field public static final int Widget_DropDownItem_Spinner = 16973868; // 0x103002c
field public static final int Widget_EditText = 16973859; // 0x1030023
field public static final int Widget_ExpandableListView = 16973860; // 0x1030024
- field public static final int Widget_FastScroll = 16974341; // 0x1030205
+ field public static final int Widget_FastScroll = 16974337; // 0x1030201
field public static final int Widget_FragmentBreadCrumbs = 16973961; // 0x1030089
field public static final int Widget_Gallery = 16973877; // 0x1030035
field public static final int Widget_GridView = 16973874; // 0x1030032
@@ -2204,8 +2212,8 @@
field public static final int Widget_Holo_DropDownItem_Spinner = 16973995; // 0x10300ab
field public static final int Widget_Holo_EditText = 16973971; // 0x1030093
field public static final int Widget_Holo_ExpandableListView = 16973972; // 0x1030094
- field public static final int Widget_Holo_FastScroll = 16974342; // 0x1030206
- field public static final int Widget_Holo_FragmentBreadCrumbs = 16974337; // 0x1030201
+ field public static final int Widget_Holo_FastScroll = 16974339; // 0x1030203
+ field public static final int Widget_Holo_FragmentBreadCrumbs = 16974340; // 0x1030204
field public static final int Widget_Holo_GridView = 16973973; // 0x1030095
field public static final int Widget_Holo_HorizontalScrollView = 16973988; // 0x10300a4
field public static final int Widget_Holo_ImageButton = 16973974; // 0x1030096
@@ -2226,7 +2234,7 @@
field public static final int Widget_Holo_Light_ActionMode_Inverse = 16974119; // 0x1030127
field public static final int Widget_Holo_Light_AutoCompleteTextView = 16974011; // 0x10300bb
field public static final int Widget_Holo_Light_Button = 16974006; // 0x10300b6
- field public static final int Widget_Holo_Light_Button_Borderless = 16974542; // 0x10302ce
+ field public static final int Widget_Holo_Light_Button_Borderless = 16974342; // 0x1030206
field public static final int Widget_Holo_Light_Button_Borderless_Small = 16974107; // 0x103011b
field public static final int Widget_Holo_Light_Button_Inset = 16974008; // 0x10300b8
field public static final int Widget_Holo_Light_Button_Small = 16974007; // 0x10300b7
@@ -2241,7 +2249,7 @@
field public static final int Widget_Holo_Light_EditText = 16974014; // 0x10300be
field public static final int Widget_Holo_Light_ExpandableListView = 16974015; // 0x10300bf
field public static final int Widget_Holo_Light_FastScroll = 16974343; // 0x1030207
- field public static final int Widget_Holo_Light_FragmentBreadCrumbs = 16974338; // 0x1030202
+ field public static final int Widget_Holo_Light_FragmentBreadCrumbs = 16974344; // 0x1030208
field public static final int Widget_Holo_Light_GridView = 16974016; // 0x10300c0
field public static final int Widget_Holo_Light_HorizontalScrollView = 16974034; // 0x10300d2
field public static final int Widget_Holo_Light_ImageButton = 16974017; // 0x10300c1
@@ -2265,6 +2273,7 @@
field public static final int Widget_Holo_Light_ScrollView = 16974033; // 0x10300d1
field public static final int Widget_Holo_Light_SeekBar = 16974028; // 0x10300cc
field public static final int Widget_Holo_Light_Spinner = 16974035; // 0x10300d3
+ field public static final int Widget_Holo_Light_StackView = 16974345; // 0x1030209
field public static final int Widget_Holo_Light_Tab = 16974052; // 0x10300e4
field public static final int Widget_Holo_Light_TabWidget = 16974037; // 0x10300d5
field public static final int Widget_Holo_Light_TextView = 16974010; // 0x10300ba
@@ -2288,6 +2297,7 @@
field public static final int Widget_Holo_ScrollView = 16973987; // 0x10300a3
field public static final int Widget_Holo_SeekBar = 16973982; // 0x103009e
field public static final int Widget_Holo_Spinner = 16973989; // 0x10300a5
+ field public static final int Widget_Holo_StackView = 16974341; // 0x1030205
field public static final int Widget_Holo_Tab = 16974051; // 0x10300e3
field public static final int Widget_Holo_TabWidget = 16973991; // 0x10300a7
field public static final int Widget_Holo_TextView = 16973967; // 0x103008f
@@ -2311,133 +2321,134 @@
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 = 16974408; // 0x1030248
- field public static final int Widget_Quantum_ActionBar = 16974409; // 0x1030249
- field public static final int Widget_Quantum_ActionBar_Solid = 16974410; // 0x103024a
- field public static final int Widget_Quantum_ActionBar_TabBar = 16974411; // 0x103024b
- field public static final int Widget_Quantum_ActionBar_TabText = 16974412; // 0x103024c
- field public static final int Widget_Quantum_ActionBar_TabView = 16974413; // 0x103024d
- field public static final int Widget_Quantum_ActionButton = 16974414; // 0x103024e
- field public static final int Widget_Quantum_ActionButton_CloseMode = 16974415; // 0x103024f
- field public static final int Widget_Quantum_ActionButton_Overflow = 16974416; // 0x1030250
- field public static final int Widget_Quantum_ActionButton_TextButton = 16974417; // 0x1030251
- field public static final int Widget_Quantum_ActionMode = 16974418; // 0x1030252
- field public static final int Widget_Quantum_AutoCompleteTextView = 16974419; // 0x1030253
- field public static final int Widget_Quantum_Button = 16974420; // 0x1030254
- field public static final int Widget_Quantum_ButtonBar = 16974426; // 0x103025a
- field public static final int Widget_Quantum_ButtonBar_AlertDialog = 16974427; // 0x103025b
- field public static final int Widget_Quantum_Button_Borderless = 16974421; // 0x1030255
- field public static final int Widget_Quantum_Button_Borderless_Small = 16974422; // 0x1030256
- field public static final int Widget_Quantum_Button_Inset = 16974423; // 0x1030257
- field public static final int Widget_Quantum_Button_Paper = 16974526; // 0x10302be
- field public static final int Widget_Quantum_Button_Paper_Color = 16974527; // 0x10302bf
- field public static final int Widget_Quantum_Button_Small = 16974424; // 0x1030258
- field public static final int Widget_Quantum_Button_Toggle = 16974425; // 0x1030259
- field public static final int Widget_Quantum_CalendarView = 16974428; // 0x103025c
- field public static final int Widget_Quantum_CheckedTextView = 16974429; // 0x103025d
- field public static final int Widget_Quantum_CompoundButton_CheckBox = 16974430; // 0x103025e
- field public static final int Widget_Quantum_CompoundButton_RadioButton = 16974431; // 0x103025f
- field public static final int Widget_Quantum_CompoundButton_Star = 16974432; // 0x1030260
- field public static final int Widget_Quantum_DatePicker = 16974433; // 0x1030261
- field public static final int Widget_Quantum_DropDownItem = 16974434; // 0x1030262
- field public static final int Widget_Quantum_DropDownItem_Spinner = 16974435; // 0x1030263
- field public static final int Widget_Quantum_EditText = 16974436; // 0x1030264
- field public static final int Widget_Quantum_ExpandableListView = 16974437; // 0x1030265
- field public static final int Widget_Quantum_FastScroll = 16974438; // 0x1030266
- field public static final int Widget_Quantum_FragmentBreadCrumbs = 16974439; // 0x1030267
- field public static final int Widget_Quantum_GridView = 16974440; // 0x1030268
- field public static final int Widget_Quantum_HorizontalScrollView = 16974441; // 0x1030269
- field public static final int Widget_Quantum_ImageButton = 16974442; // 0x103026a
- field public static final int Widget_Quantum_Light = 16974467; // 0x1030283
- field public static final int Widget_Quantum_Light_ActionBar = 16974468; // 0x1030284
- field public static final int Widget_Quantum_Light_ActionBar_Solid = 16974469; // 0x1030285
- field public static final int Widget_Quantum_Light_ActionBar_TabBar = 16974470; // 0x1030286
- field public static final int Widget_Quantum_Light_ActionBar_TabText = 16974471; // 0x1030287
- field public static final int Widget_Quantum_Light_ActionBar_TabView = 16974472; // 0x1030288
- field public static final int Widget_Quantum_Light_ActionButton = 16974473; // 0x1030289
- field public static final int Widget_Quantum_Light_ActionButton_CloseMode = 16974474; // 0x103028a
- field public static final int Widget_Quantum_Light_ActionButton_Overflow = 16974475; // 0x103028b
- field public static final int Widget_Quantum_Light_ActionMode = 16974476; // 0x103028c
- field public static final int Widget_Quantum_Light_AutoCompleteTextView = 16974477; // 0x103028d
- field public static final int Widget_Quantum_Light_Button = 16974478; // 0x103028e
- field public static final int Widget_Quantum_Light_ButtonBar = 16974483; // 0x1030293
- field public static final int Widget_Quantum_Light_ButtonBar_AlertDialog = 16974484; // 0x1030294
- field public static final int Widget_Quantum_Light_Button_Borderless_Small = 16974479; // 0x103028f
- field public static final int Widget_Quantum_Light_Button_Inset = 16974480; // 0x1030290
- field public static final int Widget_Quantum_Light_Button_Paper = 16974528; // 0x10302c0
- field public static final int Widget_Quantum_Light_Button_Paper_Color = 16974529; // 0x10302c1
- field public static final int Widget_Quantum_Light_Button_Small = 16974481; // 0x1030291
- field public static final int Widget_Quantum_Light_Button_Toggle = 16974482; // 0x1030292
- field public static final int Widget_Quantum_Light_CalendarView = 16974485; // 0x1030295
- field public static final int Widget_Quantum_Light_CheckedTextView = 16974486; // 0x1030296
- field public static final int Widget_Quantum_Light_CompoundButton_CheckBox = 16974487; // 0x1030297
- field public static final int Widget_Quantum_Light_CompoundButton_RadioButton = 16974488; // 0x1030298
- field public static final int Widget_Quantum_Light_CompoundButton_Star = 16974489; // 0x1030299
- field public static final int Widget_Quantum_Light_DropDownItem = 16974490; // 0x103029a
- field public static final int Widget_Quantum_Light_DropDownItem_Spinner = 16974491; // 0x103029b
- field public static final int Widget_Quantum_Light_EditText = 16974492; // 0x103029c
- field public static final int Widget_Quantum_Light_ExpandableListView = 16974493; // 0x103029d
- field public static final int Widget_Quantum_Light_FastScroll = 16974494; // 0x103029e
- field public static final int Widget_Quantum_Light_FragmentBreadCrumbs = 16974495; // 0x103029f
- field public static final int Widget_Quantum_Light_GridView = 16974496; // 0x10302a0
- field public static final int Widget_Quantum_Light_HorizontalScrollView = 16974497; // 0x10302a1
- field public static final int Widget_Quantum_Light_ImageButton = 16974498; // 0x10302a2
- field public static final int Widget_Quantum_Light_ListPopupWindow = 16974499; // 0x10302a3
- field public static final int Widget_Quantum_Light_ListView = 16974500; // 0x10302a4
- field public static final int Widget_Quantum_Light_ListView_DropDown = 16974501; // 0x10302a5
- field public static final int Widget_Quantum_Light_MediaRouteButton = 16974502; // 0x10302a6
- field public static final int Widget_Quantum_Light_PopupMenu = 16974503; // 0x10302a7
- field public static final int Widget_Quantum_Light_PopupWindow = 16974504; // 0x10302a8
- field public static final int Widget_Quantum_Light_ProgressBar = 16974505; // 0x10302a9
- field public static final int Widget_Quantum_Light_ProgressBar_Horizontal = 16974506; // 0x10302aa
- field public static final int Widget_Quantum_Light_ProgressBar_Inverse = 16974507; // 0x10302ab
- field public static final int Widget_Quantum_Light_ProgressBar_Large = 16974508; // 0x10302ac
- field public static final int Widget_Quantum_Light_ProgressBar_Large_Inverse = 16974509; // 0x10302ad
- field public static final int Widget_Quantum_Light_ProgressBar_Small = 16974510; // 0x10302ae
- field public static final int Widget_Quantum_Light_ProgressBar_Small_Inverse = 16974511; // 0x10302af
- field public static final int Widget_Quantum_Light_ProgressBar_Small_Title = 16974512; // 0x10302b0
- field public static final int Widget_Quantum_Light_RatingBar = 16974513; // 0x10302b1
- field public static final int Widget_Quantum_Light_RatingBar_Indicator = 16974514; // 0x10302b2
- field public static final int Widget_Quantum_Light_RatingBar_Small = 16974515; // 0x10302b3
- field public static final int Widget_Quantum_Light_ScrollView = 16974516; // 0x10302b4
- field public static final int Widget_Quantum_Light_SeekBar = 16974517; // 0x10302b5
- field public static final int Widget_Quantum_Light_SegmentedButton = 16974518; // 0x10302b6
- field public static final int Widget_Quantum_Light_Spinner = 16974519; // 0x10302b7
- field public static final int Widget_Quantum_Light_Tab = 16974520; // 0x10302b8
- field public static final int Widget_Quantum_Light_TabWidget = 16974521; // 0x10302b9
- field public static final int Widget_Quantum_Light_TextView = 16974522; // 0x10302ba
- field public static final int Widget_Quantum_Light_TextView_SpinnerItem = 16974523; // 0x10302bb
- field public static final int Widget_Quantum_Light_WebTextView = 16974524; // 0x10302bc
- field public static final int Widget_Quantum_Light_WebView = 16974525; // 0x10302bd
- field public static final int Widget_Quantum_ListPopupWindow = 16974443; // 0x103026b
- field public static final int Widget_Quantum_ListView = 16974444; // 0x103026c
- field public static final int Widget_Quantum_ListView_DropDown = 16974445; // 0x103026d
- field public static final int Widget_Quantum_MediaRouteButton = 16974446; // 0x103026e
- field public static final int Widget_Quantum_PopupMenu = 16974447; // 0x103026f
- field public static final int Widget_Quantum_PopupWindow = 16974448; // 0x1030270
- field public static final int Widget_Quantum_ProgressBar = 16974449; // 0x1030271
- field public static final int Widget_Quantum_ProgressBar_Horizontal = 16974450; // 0x1030272
- field public static final int Widget_Quantum_ProgressBar_Large = 16974451; // 0x1030273
- field public static final int Widget_Quantum_ProgressBar_Small = 16974452; // 0x1030274
- field public static final int Widget_Quantum_ProgressBar_Small_Title = 16974453; // 0x1030275
- field public static final int Widget_Quantum_RatingBar = 16974454; // 0x1030276
- field public static final int Widget_Quantum_RatingBar_Indicator = 16974455; // 0x1030277
- field public static final int Widget_Quantum_RatingBar_Small = 16974456; // 0x1030278
- field public static final int Widget_Quantum_ScrollView = 16974457; // 0x1030279
- field public static final int Widget_Quantum_SeekBar = 16974458; // 0x103027a
- field public static final int Widget_Quantum_SegmentedButton = 16974459; // 0x103027b
- field public static final int Widget_Quantum_Spinner = 16974460; // 0x103027c
- field public static final int Widget_Quantum_Tab = 16974461; // 0x103027d
- field public static final int Widget_Quantum_TabWidget = 16974462; // 0x103027e
- field public static final int Widget_Quantum_TextView = 16974463; // 0x103027f
- field public static final int Widget_Quantum_TextView_SpinnerItem = 16974464; // 0x1030280
- field public static final int Widget_Quantum_WebTextView = 16974465; // 0x1030281
- field public static final int Widget_Quantum_WebView = 16974466; // 0x1030282
+ 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_RatingBar = 16973857; // 0x1030021
field public static final int Widget_ScrollView = 16973869; // 0x103002d
field public static final int Widget_SeekBar = 16973856; // 0x1030020
field public static final int Widget_Spinner = 16973864; // 0x1030028
field public static final int Widget_Spinner_DropDown = 16973955; // 0x1030083
+ field public static final int Widget_StackView = 16974338; // 0x1030202
field public static final int Widget_TabWidget = 16973876; // 0x1030034
field public static final int Widget_TextView = 16973858; // 0x1030022
field public static final int Widget_TextView_PopupMenu = 16973865; // 0x1030029
@@ -2778,6 +2789,7 @@
public class AnimatorInflater {
ctor public AnimatorInflater();
method public static android.animation.Animator loadAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
+ method public static android.animation.StateListAnimator loadStateListAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
}
public abstract class AnimatorListenerAdapter implements android.animation.Animator.AnimatorListener android.animation.Animator.AnimatorPauseListener {
@@ -2974,6 +2986,12 @@
method public android.graphics.Rect evaluate(float, android.graphics.Rect, android.graphics.Rect);
}
+ public class StateListAnimator {
+ ctor public StateListAnimator();
+ method public void addState(int[], android.animation.Animator);
+ method public void jumpToCurrentState();
+ }
+
public class TimeAnimator extends android.animation.ValueAnimator {
ctor public TimeAnimator();
method public void setTimeListener(android.animation.TimeAnimator.TimeListener);
@@ -3064,6 +3082,7 @@
method public abstract android.view.View getCustomView();
method public abstract int getDisplayOptions();
method public abstract int getHeight();
+ method public int getHideOffset();
method public abstract deprecated int getNavigationItemCount();
method public abstract deprecated int getNavigationMode();
method public abstract deprecated int getSelectedNavigationIndex();
@@ -3074,6 +3093,7 @@
method public android.content.Context getThemedContext();
method public abstract java.lang.CharSequence getTitle();
method public abstract void hide();
+ method public boolean isHideOnContentScrollEnabled();
method public abstract boolean isShowing();
method public abstract deprecated android.app.ActionBar.Tab newTab();
method public abstract deprecated void removeAllTabs();
@@ -3092,6 +3112,8 @@
method public abstract void setDisplayShowHomeEnabled(boolean);
method public abstract void setDisplayShowTitleEnabled(boolean);
method public abstract void setDisplayUseLogoEnabled(boolean);
+ method public void setHideOffset(int);
+ method public void setHideOnContentScrollEnabled(boolean);
method public void setHomeActionContentDescription(java.lang.CharSequence);
method public void setHomeActionContentDescription(int);
method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
@@ -3294,7 +3316,6 @@
method public void onUserInteraction();
method protected void onUserLeaveHint();
method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
- method public void onWindowDismissed();
method public void onWindowFocusChanged(boolean);
method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
method public void openContextMenu(android.view.View);
@@ -3307,7 +3328,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 setActivityLabelAndIcon(java.lang.CharSequence, android.graphics.Bitmap);
method public void setActivityTransitionListener(android.app.ActivityOptions.ActivityTransitionListener);
method public void setContentTransitionManager(android.transition.TransitionManager);
method public void setContentView(int);
@@ -3325,6 +3345,7 @@
method public final void setProgressBarIndeterminate(boolean);
method public final void setProgressBarIndeterminateVisibility(boolean);
method public final void setProgressBarVisibility(boolean);
+ method public void setRecentsActivityValues(android.app.ActivityManager.RecentsActivityValues);
method public void setRequestedOrientation(int);
method public final void setResult(int);
method public final void setResult(int, android.content.Intent);
@@ -3350,10 +3371,12 @@
method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+ method public void startLockTask();
method public deprecated void startManagingCursor(android.database.Cursor);
method public boolean startNextMatchingActivity(android.content.Intent);
method public boolean startNextMatchingActivity(android.content.Intent, android.os.Bundle);
method public void startSearch(java.lang.String, boolean, android.os.Bundle, boolean);
+ method public void stopLockTask();
method public deprecated void stopManagingCursor(android.database.Cursor);
method public void takeKeyEvents(boolean);
method public void triggerSearch(java.lang.String, android.os.Bundle);
@@ -3445,8 +3468,7 @@
method public void readFromParcel(android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
- field public android.graphics.Bitmap activityIcon;
- field public java.lang.CharSequence activityLabel;
+ field public android.app.ActivityManager.RecentsActivityValues activityValues;
field public android.content.Intent baseIntent;
field public java.lang.CharSequence description;
field public int id;
@@ -3454,6 +3476,21 @@
field public int persistentId;
}
+ public static class ActivityManager.RecentsActivityValues implements android.os.Parcelable {
+ ctor public ActivityManager.RecentsActivityValues(android.app.ActivityManager.RecentsActivityValues);
+ ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence, android.graphics.Bitmap, int);
+ ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence, android.graphics.Bitmap);
+ ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence);
+ ctor public ActivityManager.RecentsActivityValues();
+ method public int describeContents();
+ method public void readFromParcel(android.os.Parcel);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public int colorPrimary;
+ field public android.graphics.Bitmap icon;
+ field public java.lang.CharSequence label;
+ }
+
public static class ActivityManager.RunningAppProcessInfo implements android.os.Parcelable {
ctor public ActivityManager.RunningAppProcessInfo();
ctor public ActivityManager.RunningAppProcessInfo(java.lang.String, int, java.lang.String[]);
@@ -3836,7 +3873,6 @@
method public boolean onTouchEvent(android.view.MotionEvent);
method public boolean onTrackballEvent(android.view.MotionEvent);
method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
- method public void onWindowDismissed();
method public void onWindowFocusChanged(boolean);
method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
method public void openContextMenu(android.view.View);
@@ -4402,6 +4438,7 @@
field public static final java.lang.String CATEGORY_STATUS = "status";
field public static final java.lang.String CATEGORY_SYSTEM = "sys";
field public static final java.lang.String CATEGORY_TRANSPORT = "transport";
+ field public static final int COLOR_DEFAULT = 0; // 0x0
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int DEFAULT_ALL = -1; // 0xffffffff
field public static final int DEFAULT_LIGHTS = 4; // 0x4
@@ -4447,6 +4484,7 @@
field public int audioStreamType;
field public android.widget.RemoteViews bigContentView;
field public java.lang.String category;
+ field public int color;
field public android.app.PendingIntent contentIntent;
field public android.widget.RemoteViews contentView;
field public int defaults;
@@ -4509,6 +4547,7 @@
method public deprecated android.app.Notification getNotification();
method public android.app.Notification.Builder setAutoCancel(boolean);
method public android.app.Notification.Builder setCategory(java.lang.String);
+ method public android.app.Notification.Builder setColor(int);
method public android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
@@ -4983,12 +5022,15 @@
}
public class DevicePolicyManager {
+ method public void addForwardingIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
method public void addUserRestriction(android.content.ComponentName, java.lang.String);
method public void clearForwardingIntentFilters(android.content.ComponentName);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
- method public void forwardMatchingIntents(android.content.ComponentName, android.content.IntentFilter, int);
+ method public void enableSystemApp(android.content.ComponentName, java.lang.String);
+ method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
+ method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
method public boolean getCameraDisabled(android.content.ComponentName);
@@ -5018,6 +5060,7 @@
method public void lockNow();
method public void removeActiveAdmin(android.content.ComponentName);
method public boolean resetPassword(java.lang.String, int);
+ method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
method public void setCameraDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
@@ -5166,6 +5209,27 @@
}
+package android.app.task {
+
+ public class TaskParams implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.Bundle getExtras();
+ method public int getTaskId();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public abstract class TaskService extends android.app.Service {
+ ctor public TaskService();
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public abstract void onStartTask(android.app.task.TaskParams);
+ method public abstract boolean onStopTask(android.app.task.TaskParams);
+ method public final void taskFinished(android.app.task.TaskParams, boolean);
+ field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_TASK_SERVICE";
+ }
+
+}
+
package android.appwidget {
public class AppWidgetHost {
@@ -5265,6 +5329,7 @@
field public static final int RESIZE_VERTICAL = 2; // 0x2
field public static final int WIDGET_CATEGORY_HOME_SCREEN = 1; // 0x1
field public static final int WIDGET_CATEGORY_KEYGUARD = 2; // 0x2
+ field public static final int WIDGET_CATEGORY_RECENTS = 4; // 0x4
field public int autoAdvanceViewId;
field public android.content.ComponentName configure;
field public int icon;
@@ -6568,6 +6633,7 @@
field public static final java.lang.String DISPLAY_SERVICE = "display";
field public static final java.lang.String DOWNLOAD_SERVICE = "download";
field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
+ field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
field public static final java.lang.String HDMI_CEC_SERVICE = "hdmi_cec";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
@@ -7103,6 +7169,7 @@
field public static final int FILL_IN_PACKAGE = 16; // 0x10
field public static final int FILL_IN_SELECTOR = 64; // 0x40
field public static final int FILL_IN_SOURCE_BOUNDS = 32; // 0x20
+ field public static final int FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
field public static final int FLAG_ACTIVITY_BROUGHT_TO_FRONT = 4194304; // 0x400000
field public static final int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000
field public static final int FLAG_ACTIVITY_CLEAR_TOP = 67108864; // 0x4000000
@@ -7528,6 +7595,55 @@
method public abstract void onStatusChanged(int);
}
+ public class Task implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getBackoffPolicy();
+ method public android.os.Bundle getExtras();
+ method public long getInitialBackoffMillis();
+ method public long getIntervalMillis();
+ method public long getMaxExecutionDelayMillis();
+ method public long getMinLatencyMillis();
+ method public int getNetworkCapabilities();
+ method public java.lang.String getServiceClassName();
+ method public int getTaskId();
+ method public boolean isPeriodic();
+ method public boolean isRequireCharging();
+ method public boolean isRequireDeviceIdle();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public static abstract interface Task.BackoffPolicy {
+ field public static final int EXPONENTIAL = 1; // 0x1
+ field public static final int LINEAR = 0; // 0x0
+ }
+
+ public final class Task.Builder {
+ ctor public Task.Builder(int, java.lang.Class<android.app.task.TaskService>);
+ 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);
+ method public android.content.Task.Builder setMinimumLatency(long);
+ method public android.content.Task.Builder setOverrideDeadline(long);
+ method public android.content.Task.Builder setPeriodic(long);
+ method public android.content.Task.Builder setRequiredNetworkCapabilities(int);
+ method public android.content.Task.Builder setRequiresCharging(boolean);
+ method public android.content.Task.Builder setRequiresDeviceIdle(boolean);
+ }
+
+ public static abstract interface Task.NetworkType {
+ field public static final int ANY = 0; // 0x0
+ field public static final int UNMETERED = 1; // 0x1
+ }
+
+ public abstract class TaskManager {
+ ctor public TaskManager();
+ method public abstract void cancel(int);
+ method public abstract void cancelAll();
+ method public abstract java.util.List<android.content.Task> getAllPendingTasks();
+ method public abstract int schedule(android.content.Task);
+ }
+
public class UriMatcher {
ctor public UriMatcher(int);
method public void addURI(java.lang.String, java.lang.String, int);
@@ -7572,8 +7688,12 @@
field public static final int CONFIG_TOUCHSCREEN = 8; // 0x8
field public static final int CONFIG_UI_MODE = 512; // 0x200
field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int DOCUMENT_LAUNCH_ALWAYS = 2; // 0x2
+ field public static final int DOCUMENT_LAUNCH_INTO_EXISTING = 1; // 0x1
+ field public static final int DOCUMENT_LAUNCH_NONE = 0; // 0x0
field public static final int FLAG_ALLOW_TASK_REPARENTING = 64; // 0x40
field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8
+ field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
field public static final int FLAG_CLEAR_TASK_ON_LAUNCH = 4; // 0x4
field public static final int FLAG_EXCLUDE_FROM_RECENTS = 32; // 0x20
field public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 256; // 0x100
@@ -7582,6 +7702,7 @@
field public static final int FLAG_IMMERSIVE = 2048; // 0x800
field public static final int FLAG_MULTIPROCESS = 1; // 0x1
field public static final int FLAG_NO_HISTORY = 128; // 0x80
+ field public static final int FLAG_PERSISTABLE = 4096; // 0x1000
field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
field public static final int FLAG_STATE_NOT_NEEDED = 16; // 0x10
field public static final int LAUNCH_MULTIPLE = 0; // 0x0
@@ -7606,6 +7727,7 @@
field public static final int SCREEN_ORIENTATION_USER_PORTRAIT = 12; // 0xc
field public static final int UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = 1; // 0x1
field public int configChanges;
+ field public int documentLaunchMode;
field public int flags;
field public int launchMode;
field public java.lang.String parentActivityName;
@@ -7956,6 +8078,7 @@
field public static final java.lang.String FEATURE_SENSOR_BAROMETER = "android.hardware.sensor.barometer";
field public static final java.lang.String FEATURE_SENSOR_COMPASS = "android.hardware.sensor.compass";
field public static final java.lang.String FEATURE_SENSOR_GYROSCOPE = "android.hardware.sensor.gyroscope";
+ field public static final java.lang.String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate";
field public static final java.lang.String FEATURE_SENSOR_LIGHT = "android.hardware.sensor.light";
field public static final java.lang.String FEATURE_SENSOR_PROXIMITY = "android.hardware.sensor.proximity";
field public static final java.lang.String FEATURE_SENSOR_STEP_COUNTER = "android.hardware.sensor.stepcounter";
@@ -10639,6 +10762,7 @@
method public void releaseTexImage();
method public void setDefaultBufferSize(int, int);
method public void setOnFrameAvailableListener(android.graphics.SurfaceTexture.OnFrameAvailableListener);
+ method public void setOnFrameAvailableListener(android.graphics.SurfaceTexture.OnFrameAvailableListener, android.os.Handler);
method public void updateTexImage();
}
@@ -11134,19 +11258,11 @@
public class VectorDrawable extends android.graphics.drawable.Drawable {
ctor public VectorDrawable();
method public void draw(android.graphics.Canvas);
- method public float geAnimationFraction();
method public int getOpacity();
- method public int getRepeatCount();
method public void setAlpha(int);
- method public void setAnimationFraction(float);
method public void setColorFilter(android.graphics.ColorFilter);
- method public void setDuration(long);
method public void setPadding(android.graphics.Rect);
method public void setPadding(int, int, int, int);
- method public void setRepeatCount(int);
- method public void setRepeatMode(int);
- method public void start();
- method public void stop();
}
}
@@ -11751,7 +11867,6 @@
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_WHITE_LEVEL;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_MAX_ANALOG_SENSITIVITY;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_ORIENTATION;
- field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_REFERENCE_ILLUMINANT1;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_REFERENCE_ILLUMINANT2;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
@@ -11909,6 +12024,8 @@
field public static final int CONTROL_SCENE_MODE_STEADYPHOTO = 11; // 0xb
field public static final int CONTROL_SCENE_MODE_SUNSET = 10; // 0xa
field public static final int CONTROL_SCENE_MODE_THEATRE = 7; // 0x7
+ field public static final int CONTROL_VIDEO_STABILIZATION_MODE_OFF = 0; // 0x0
+ field public static final int CONTROL_VIDEO_STABILIZATION_MODE_ON = 1; // 0x1
field public static final int EDGE_MODE_FAST = 1; // 0x1
field public static final int EDGE_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int EDGE_MODE_OFF = 0; // 0x0
@@ -12082,17 +12199,29 @@
method public int getSequenceId();
field public static final android.hardware.camera2.CameraMetadata.Key BLACK_LEVEL_LOCK;
field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_GAINS;
+ field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key COLOR_CORRECTION_TRANSFORM;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_ANTIBANDING_MODE;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_EXPOSURE_COMPENSATION;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_LOCK;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_MODE;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_PRECAPTURE_TRIGGER;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_REGIONS;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_STATE;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AE_TARGET_FPS_RANGE;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_REGIONS;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_STATE;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AF_TRIGGER;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_LOCK;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_REGIONS;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_STATE;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_CAPTURE_INTENT;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_EFFECT_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_MODE;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_SCENE_MODE;
+ field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_VIDEO_STABILIZATION_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key EDGE_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key FLASH_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key FLASH_STATE;
@@ -12119,10 +12248,9 @@
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FRAME_DURATION;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_GREEN_SPLIT;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_NEUTRAL_COLOR_POINT;
- field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_HUE_SAT_MAP;
- field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_TONE_CURVE;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEMPERATURE;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_DATA;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TIMESTAMP;
field public static final android.hardware.camera2.CameraMetadata.Key SHADING_MODE;
@@ -12131,6 +12259,7 @@
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_HOT_PIXEL_MAP;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_HOT_PIXEL_MAP_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP;
+ field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP_MODE;
field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_SCENE_FLICKER;
field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_BLUE;
field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_GREEN;
@@ -12138,6 +12267,14 @@
field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE;
}
+ public final class ColorSpaceTransform {
+ ctor public ColorSpaceTransform(android.hardware.camera2.Rational[]);
+ ctor public ColorSpaceTransform(int[]);
+ method public void copyElements(android.hardware.camera2.Rational[], int);
+ method public void copyElements(int[], int);
+ method public android.hardware.camera2.Rational getElement(int, int);
+ }
+
public final class Face {
method public android.graphics.Rect getBounds();
method public int getId();
@@ -12150,18 +12287,83 @@
field public static final int SCORE_MIN = 1; // 0x1
}
+ public final class LensShadingMap {
+ method public void copyGainFactors(float[], int);
+ method public int getColumnCount();
+ method public float getGainFactor(int, int, int);
+ method public int getGainFactorCount();
+ method public android.hardware.camera2.RggbChannelVector getGainFactorVector(int, int);
+ method public int getRowCount();
+ field public static final float MINIMUM_GAIN_FACTOR = 1.0f;
+ }
+
+ public final class MeteringRectangle {
+ ctor public MeteringRectangle(int, int, int, int, int);
+ ctor public MeteringRectangle(android.graphics.Point, android.util.Size, int);
+ ctor public MeteringRectangle(android.graphics.Rect, int);
+ method public boolean equals(android.hardware.camera2.MeteringRectangle);
+ method public int getHeight();
+ method public int getMeteringWeight();
+ method public android.graphics.Rect getRect();
+ method public android.util.Size getSize();
+ method public android.graphics.Point getUpperLeftPoint();
+ method public int getWidth();
+ method public int getX();
+ method public int getY();
+ }
+
public final class Rational {
ctor public Rational(int, int);
method public int getDenominator();
method public int getNumerator();
}
+ public final class RggbChannelVector {
+ ctor public RggbChannelVector(float, float, float, float);
+ method public void copyTo(float[], int);
+ method public float getBlue();
+ method public float getComponent(int);
+ method public float getGreenEven();
+ method public float getGreenOdd();
+ method public final float getRed();
+ field public static final int BLUE = 3; // 0x3
+ field public static final int COUNT = 4; // 0x4
+ field public static final int GREEN_EVEN = 1; // 0x1
+ field public static final int GREEN_ODD = 2; // 0x2
+ field public static final int RED = 0; // 0x0
+ }
+
public final class Size {
ctor public Size(int, int);
method public final int getHeight();
method public final int getWidth();
}
+ public final class StreamConfigurationMap {
+ method public final int[] getOutputFormats();
+ method public long getOutputMinFrameDuration(int, android.util.Size);
+ method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
+ method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
+ method public android.util.Size[] getOutputSizes(int);
+ method public long getOutputStallDuration(int, android.util.Size);
+ method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
+ method public boolean isOutputSupportedFor(int);
+ method public static boolean isOutputSupportedFor(java.lang.Class<T>);
+ 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 {
@@ -12204,7 +12406,6 @@
method public static boolean isValidType(int);
field public static final int ADDR_AUDIO_SYSTEM = 5; // 0x5
field public static final int ADDR_BROADCAST = 15; // 0xf
- field public static final int ADDR_FREE_USE = 14; // 0xe
field public static final int ADDR_INVALID = -1; // 0xffffffff
field public static final int ADDR_PLAYBACK_1 = 4; // 0x4
field public static final int ADDR_PLAYBACK_2 = 8; // 0x8
@@ -12214,6 +12415,7 @@
field public static final int ADDR_RECORDER_3 = 9; // 0x9
field public static final int ADDR_RESERVED_1 = 12; // 0xc
field public static final int ADDR_RESERVED_2 = 13; // 0xd
+ field public static final int ADDR_SPECIFIC_USE = 14; // 0xe
field public static final int ADDR_TUNER_1 = 3; // 0x3
field public static final int ADDR_TUNER_2 = 6; // 0x6
field public static final int ADDR_TUNER_3 = 7; // 0x7
@@ -12294,6 +12496,7 @@
field public static final int POWER_STATUS_UNKNOWN = -1; // 0xffffffff
field public static final int POWER_TRANSIENT_TO_ON = 2; // 0x2
field public static final int POWER_TRANSIENT_TO_STANDBY = 3; // 0x3
+ field public static final int UNKNOWN_VENDOR_ID = 16777215; // 0xffffff
}
public final class HdmiCecClient {
@@ -12311,6 +12514,17 @@
method public void onMessageReceived(android.hardware.hdmi.HdmiCecMessage);
}
+ public final class HdmiCecDeviceInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getDeviceType();
+ method public java.lang.String getDisplayName();
+ method public int getLogicalAddress();
+ method public int getPhysicalAddress();
+ method public int getVendorId();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
public final class HdmiCecManager {
method public android.hardware.hdmi.HdmiCecClient getClient(int, android.hardware.hdmi.HdmiCecClient.Listener);
}
@@ -12324,6 +12538,7 @@
method public int getSource();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final byte[] EMPTY_PARAM;
}
}
@@ -15103,11 +15318,13 @@
package android.media.session {
public final class MediaMetadata implements android.os.Parcelable {
+ method public boolean containsKey(java.lang.String);
method public int describeContents();
method public android.graphics.Bitmap getBitmap(java.lang.String);
method public long getLong(java.lang.String);
method public android.media.Rating getRating(java.lang.String);
method public java.lang.String getString(java.lang.String);
+ method public int size();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
@@ -15118,6 +15335,7 @@
field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+ field public static final java.lang.String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE";
field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
@@ -15150,25 +15368,25 @@
method public long getBufferPosition();
method public java.lang.String getErrorMessage();
method public long getPosition();
- method public float getSpeed();
+ method public float getRate();
method public int getState();
method public void setActions(long);
method public void setBufferPosition(long);
method public void setErrorMessage(java.lang.String);
- method public void setPosition(long);
- method public void setSpeed(float);
- method public void setState(int);
+ method public void setState(int, long, float);
method public void writeToParcel(android.os.Parcel, int);
field public static final long ACTION_FASTFORWARD = 64L; // 0x40L
field public static final long ACTION_NEXT_ITEM = 32L; // 0x20L
field public static final long ACTION_PAUSE = 2L; // 0x2L
field public static final long ACTION_PLAY = 4L; // 0x4L
+ field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
field public static final long ACTION_PREVIOUS_ITEM = 16L; // 0x10L
field public static final long ACTION_RATING = 128L; // 0x80L
field public static final long ACTION_REWIND = 8L; // 0x8L
field public static final long ACTION_SEEK_TO = 256L; // 0x100L
field public static final long ACTION_STOP = 1L; // 0x1L
field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
field public static final int PLAYSTATE_BUFFERING = 6; // 0x6
field public static final int PLAYSTATE_CONNECTING = 8; // 0x8
field public static final int PLAYSTATE_ERROR = 7; // 0x7
@@ -15177,6 +15395,8 @@
field public static final int PLAYSTATE_PAUSED = 2; // 0x2
field public static final int PLAYSTATE_PLAYING = 3; // 0x3
field public static final int PLAYSTATE_REWINDING = 5; // 0x5
+ field public static final int PLAYSTATE_SKIPPING_BACKWARDS = 9; // 0x9
+ field public static final int PLAYSTATE_SKIPPING_FORWARDS = 10; // 0xa
field public static final int PLAYSTATE_STOPPED = 1; // 0x1
}
@@ -15268,12 +15488,15 @@
method public void disconnect(android.media.session.RouteInfo);
method public android.media.session.SessionToken getSessionToken();
method public android.media.session.TransportPerformer getTransportPerformer();
- method public void publish();
+ method public boolean isActive();
method public void release();
method public void removeCallback(android.media.session.Session.Callback);
method public void sendEvent(java.lang.String, android.os.Bundle);
+ method public void setActive(boolean);
+ method public void setFlags(int);
method public void setRouteOptions(java.util.List<android.media.session.RouteOptions>);
- method public android.media.session.TransportPerformer setTransportPerformerEnabled();
+ field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+ field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
public static abstract class Session.Callback {
@@ -15312,7 +15535,7 @@
public final class SessionManager {
method public android.media.session.Session createSession(java.lang.String);
- method public java.util.List<android.media.session.SessionController> getActiveSessions();
+ method public java.util.List<android.media.session.SessionController> getActiveSessions(android.content.ComponentName);
}
public class SessionToken implements android.os.Parcelable {
@@ -15502,6 +15725,7 @@
method public android.net.NetworkInfo getActiveNetworkInfo();
method public android.net.NetworkInfo[] getAllNetworkInfo();
method public deprecated boolean getBackgroundDataSetting();
+ method public android.net.ProxyInfo getGlobalProxy();
method public android.net.NetworkInfo getNetworkInfo(int);
method public int getNetworkPreference();
method public boolean isActiveNetworkMetered();
@@ -15509,6 +15733,7 @@
method public static boolean isNetworkTypeValid(int);
method public void registerNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
method public boolean requestRouteToHost(int, int);
+ method public void setGlobalProxy(android.net.ProxyInfo);
method public void setNetworkPreference(int);
method public int startUsingNetworkFeature(int, java.lang.String);
method public int stopUsingNetworkFeature(int, java.lang.String);
@@ -15684,9 +15909,22 @@
method public static final deprecated int getDefaultPort();
method public static final deprecated java.lang.String getHost(android.content.Context);
method public static final deprecated int getPort(android.content.Context);
+ field public static final java.lang.String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
field public static final java.lang.String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
}
+ public class ProxyInfo implements android.os.Parcelable {
+ method public static android.net.ProxyInfo buildDirectProxy(java.lang.String, int);
+ method public static android.net.ProxyInfo buildDirectProxy(java.lang.String, int, java.util.List<java.lang.String>);
+ method public static android.net.ProxyInfo buildPacProxy(android.net.Uri);
+ method public int describeContents();
+ method public java.lang.String[] getExclusionList();
+ method public java.lang.String getHost();
+ method public android.net.Uri getPacFileUrl();
+ method public int getPort();
+ method public void writeToParcel(android.os.Parcel, int);
+ }
+
public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
ctor public deprecated SSLCertificateSocketFactory(int);
method public java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException;
@@ -20310,9 +20548,17 @@
method public void setUserRestriction(java.lang.String, boolean);
method public void setUserRestrictions(android.os.Bundle);
method public void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
+ field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
+ field public static final java.lang.String DISALLOW_CONFIG_APPS = "no_config_apps";
field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
+ field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
field public static final java.lang.String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
+ field public static final java.lang.String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
+ field public static final java.lang.String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
+ field public static final java.lang.String DISALLOW_CONFIG_VPN = "no_config_vpn";
field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi";
+ field public static final java.lang.String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
+ field public static final java.lang.String DISALLOW_FACTORY_RESET = "no_factory_reset";
field public static final java.lang.String DISALLOW_INSTALL_APPS = "no_install_apps";
field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
@@ -20320,6 +20566,7 @@
field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
+ field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
}
public abstract class Vibrator {
@@ -24342,6 +24589,7 @@
method public void contextDump();
method public static android.renderscript.RenderScript create(android.content.Context);
method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType);
+ method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType, long);
method public void destroy();
method public void finish();
method public final android.content.Context getApplicationContext();
@@ -24351,6 +24599,9 @@
method public void setErrorHandler(android.renderscript.RenderScript.RSErrorHandler);
method public void setMessageHandler(android.renderscript.RenderScript.RSMessageHandler);
method public void setPriority(android.renderscript.RenderScript.Priority);
+ field public static final long CREATE_FLAG_LOW_LATENCY = 1L; // 0x1L
+ field public static final long CREATE_FLAG_LOW_POWER = 2L; // 0x2L
+ field public static final long CREATE_FLAG_NONE = 0L; // 0x0L
}
public static final class RenderScript.ContextType extends java.lang.Enum {
@@ -24850,7 +25101,6 @@
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
method public boolean onSearchRequested();
method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
- method public void onWindowDismissed();
method public void onWindowFocusChanged(boolean);
method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
method public void setContentView(int);
@@ -24865,6 +25115,36 @@
}
+package android.service.fingerprint {
+
+ public class FingerprintManager {
+ ctor public FingerprintManager(android.content.Context);
+ method public void enroll(long);
+ method public void remove(int);
+ method public void startListening(android.service.fingerprint.FingerprintManagerReceiver);
+ method public void stopListening();
+ field protected static final boolean DEBUG = true;
+ field public static final int FINGERPRINT_ERROR = -1; // 0xffffffff
+ field public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2; // 0x2
+ field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
+ field public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10; // 0xfffffff6
+ field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
+ field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
+ field public static final int FINGERPRINT_SCANNED = 1; // 0x1
+ field public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2; // 0x2
+ field public static final int FINGERPRINT_TEMPLATE_REMOVED = 4; // 0x4
+ }
+
+ public class FingerprintManagerReceiver {
+ ctor public FingerprintManagerReceiver();
+ method public void onEnrollResult(int, int);
+ method public void onError(int);
+ method public void onRemoved(int);
+ method public void onScanned(int, int);
+ }
+
+}
+
package android.service.notification {
public abstract class NotificationListenerService extends android.app.Service {
@@ -24946,23 +25226,53 @@
public class VoiceInteractionService extends android.app.Service {
ctor public VoiceInteractionService();
method public android.os.IBinder onBind(android.content.Intent);
- method public void startVoiceActivity(android.content.Intent, android.os.Bundle);
+ method public void startSession(android.os.Bundle);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
}
- public abstract class VoiceInteractionSession {
+ public abstract class VoiceInteractionSession implements android.view.KeyEvent.Callback {
ctor public VoiceInteractionSession(android.content.Context);
ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
+ method public void finish();
+ method public android.view.LayoutInflater getLayoutInflater();
+ method public android.app.Dialog getWindow();
+ method public void hideWindow();
+ method public void onBackPressed();
method public abstract void onCancel(android.service.voice.VoiceInteractionSession.Request);
+ method public void onCloseSystemDialogs();
method public abstract void onCommand(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
+ method public void onComputeInsets(android.service.voice.VoiceInteractionSession.Insets);
method public abstract void onConfirm(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
+ method public void onCreate(android.os.Bundle);
+ method public android.view.View onCreateContentView();
+ method public void onDestroy();
method public abstract boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
+ method public boolean onKeyDown(int, android.view.KeyEvent);
+ method public boolean onKeyLongPress(int, android.view.KeyEvent);
+ method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
+ method public boolean onKeyUp(int, android.view.KeyEvent);
+ method public void onTaskFinished(android.content.Intent, int);
+ method public void onTaskStarted(android.content.Intent, int);
+ method public void setContentView(android.view.View);
+ method public void setTheme(int);
+ method public void showWindow();
+ method public void startVoiceActivity(android.content.Intent);
}
public static class VoiceInteractionSession.Caller {
}
+ public static final class VoiceInteractionSession.Insets {
+ ctor public VoiceInteractionSession.Insets();
+ field public static final int TOUCHABLE_INSETS_CONTENT = 1; // 0x1
+ field public static final int TOUCHABLE_INSETS_FRAME = 0; // 0x0
+ field public static final int TOUCHABLE_INSETS_REGION = 3; // 0x3
+ field public int contentTopInsets;
+ field public int touchableInsets;
+ field public final android.graphics.Region touchableRegion;
+ }
+
public static class VoiceInteractionSession.Request {
method public void sendCancelResult();
method public void sendCommandResult(boolean, android.os.Bundle);
@@ -28614,6 +28924,25 @@
method public void set(T, V);
}
+ public final class Range {
+ ctor public Range(T, T);
+ method public static android.util.Range<T> create(T, T);
+ method public T getLower();
+ method public T getUpper();
+ }
+
+ public final class Size {
+ ctor public Size(int, int);
+ method public int getHeight();
+ method public int getWidth();
+ }
+
+ public final class SizeF {
+ ctor public SizeF(float, float);
+ method public float getHeight();
+ method public float getWidth();
+ }
+
public class SparseArray implements java.lang.Cloneable {
ctor public SparseArray();
ctor public SparseArray(int);
@@ -30111,7 +30440,7 @@
method public boolean dispatchKeyEvent(android.view.KeyEvent);
method public boolean dispatchKeyEventPreIme(android.view.KeyEvent);
method public boolean dispatchKeyShortcutEvent(android.view.KeyEvent);
- method public boolean dispatchNestedFling(float, float);
+ method public boolean dispatchNestedFling(float, float, boolean);
method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
method public boolean dispatchNestedScroll(int, int, int, int, int[]);
method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
@@ -30233,6 +30562,7 @@
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();
method protected int getSuggestedMinimumWidth();
method public int getSystemUiVisibility();
@@ -30497,6 +30827,7 @@
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);
method public void setTag(java.lang.Object);
method public void setTag(int, java.lang.Object);
@@ -30749,7 +31080,7 @@
method public static int getDoubleTapTimeout();
method public static deprecated int getEdgeSlop();
method public static deprecated int getFadingEdgeLength();
- method public static long getGlobalActionKeyTimeout();
+ method public static deprecated long getGlobalActionKeyTimeout();
method public static int getJumpTapTimeout();
method public static int getKeyRepeatDelay();
method public static int getKeyRepeatTimeout();
@@ -30904,7 +31235,7 @@
method public boolean onInterceptHoverEvent(android.view.MotionEvent);
method public boolean onInterceptTouchEvent(android.view.MotionEvent);
method protected abstract void onLayout(boolean, int, int, int, int);
- method public boolean onNestedFling(android.view.View, float, float);
+ method public boolean onNestedFling(android.view.View, float, float, boolean);
method public void onNestedPreScroll(android.view.View, int, int, int[]);
method public void onNestedScroll(android.view.View, int, int, int, int);
method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
@@ -31042,7 +31373,7 @@
method public abstract boolean isTextAlignmentResolved();
method public abstract boolean isTextDirectionResolved();
method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
- method public abstract boolean onNestedFling(android.view.View, float, float);
+ method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
method public abstract void onNestedPreScroll(android.view.View, int, int, int[]);
method public abstract void onNestedScroll(android.view.View, int, int, int, int);
method public abstract void onNestedScrollAccepted(android.view.View, android.view.View, int);
@@ -31320,7 +31651,6 @@
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
method public abstract boolean onSearchRequested();
method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
- method public abstract void onWindowDismissed();
method public abstract void onWindowFocusChanged(boolean);
method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
}
@@ -31354,26 +31684,17 @@
method public abstract void onFocusLost(android.view.WindowId);
}
- public class WindowInsets {
+ public final class WindowInsets {
ctor public WindowInsets(android.view.WindowInsets);
- method public android.view.WindowInsets cloneWithSystemWindowInsets(int, int, int, int);
- method public android.view.WindowInsets cloneWithSystemWindowInsetsConsumed();
- method public android.view.WindowInsets cloneWithSystemWindowInsetsConsumed(boolean, boolean, boolean, boolean);
- method public android.view.WindowInsets cloneWithWindowDecorInsets(int, int, int, int);
- method public android.view.WindowInsets cloneWithWindowDecorInsetsConsumed();
- method public android.view.WindowInsets cloneWithWindowDecorInsetsConsumed(boolean, boolean, boolean, boolean);
+ method public android.view.WindowInsets consumeSystemWindowInsets();
method public int getSystemWindowInsetBottom();
method public int getSystemWindowInsetLeft();
method public int getSystemWindowInsetRight();
method public int getSystemWindowInsetTop();
- method public int getWindowDecorInsetBottom();
- method public int getWindowDecorInsetLeft();
- method public int getWindowDecorInsetRight();
- method public int getWindowDecorInsetTop();
method public boolean hasInsets();
method public boolean hasSystemWindowInsets();
- method public boolean hasWindowDecorInsets();
method public boolean isRound();
+ method public android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
}
public abstract interface WindowManager implements android.view.ViewManager {
@@ -32597,6 +32918,16 @@
package android.webkit {
+ public abstract interface ClientCertRequest {
+ method public abstract void cancel();
+ method public abstract java.lang.String getHost();
+ method public abstract java.lang.String[] getKeyTypes();
+ method public abstract int getPort();
+ method public abstract java.security.Principal[] getPrincipals();
+ method public abstract void ignore();
+ method public abstract void proceed(java.security.PrivateKey, java.security.cert.X509Certificate[]);
+ }
+
public class ConsoleMessage {
ctor public ConsoleMessage(java.lang.String, java.lang.String, int, android.webkit.ConsoleMessage.MessageLevel);
method public int lineNumber();
@@ -32690,6 +33021,16 @@
method public boolean hasMimeType(java.lang.String);
}
+ public abstract interface PermissionRequest {
+ method public abstract void deny();
+ method public abstract android.net.Uri getOrigin();
+ method public abstract long getResources();
+ method public abstract void grant(long);
+ field public static final long RESOURCE_AUDIO_CAPTURE = 4L; // 0x4L
+ field public static final long RESOURCE_GEOLOCATION = 1L; // 0x1L
+ field public static final long RESOURCE_VIDEO_CAPTURE = 2L; // 0x2L
+ }
+
public abstract interface PluginStub {
method public abstract android.view.View getEmbeddedView(int, android.content.Context);
method public abstract android.view.View getFullScreenView(int, android.content.Context);
@@ -32749,6 +33090,8 @@
method public boolean onJsConfirm(android.webkit.WebView, java.lang.String, java.lang.String, android.webkit.JsResult);
method public boolean onJsPrompt(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String, android.webkit.JsPromptResult);
method public deprecated boolean onJsTimeout();
+ method public void onPermissionRequest(android.webkit.PermissionRequest);
+ method public void onPermissionRequestCanceled(android.webkit.PermissionRequest);
method public void onProgressChanged(android.webkit.WebView, int);
method public deprecated void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
method public void onReceivedIcon(android.webkit.WebView, android.graphics.Bitmap);
@@ -32825,6 +33168,7 @@
method public boolean getMediaPlaybackRequiresUserGesture();
method public synchronized int getMinimumFontSize();
method public synchronized int getMinimumLogicalFontSize();
+ method public abstract int getMixedContentMode();
method public deprecated synchronized android.webkit.WebSettings.PluginState getPluginState();
method public synchronized java.lang.String getSansSerifFontFamily();
method public boolean getSaveFormData();
@@ -32869,6 +33213,7 @@
method public void setMediaPlaybackRequiresUserGesture(boolean);
method public synchronized void setMinimumFontSize(int);
method public synchronized void setMinimumLogicalFontSize(int);
+ method public abstract void setMixedContentMode(int);
method public void setNeedInitialFocus(boolean);
method public deprecated synchronized void setPluginState(android.webkit.WebSettings.PluginState);
method public deprecated synchronized void setRenderPriority(android.webkit.WebSettings.RenderPriority);
@@ -32890,6 +33235,9 @@
field public static final int LOAD_DEFAULT = -1; // 0xffffffff
field public static final deprecated int LOAD_NORMAL = 0; // 0x0
field public static final int LOAD_NO_CACHE = 2; // 0x2
+ field public static final int MIXED_CONTENT_ALWAYS_ALLOW = 0; // 0x0
+ field public static final int MIXED_CONTENT_COMPATIBILITY_MODE = 2; // 0x2
+ field public static final int MIXED_CONTENT_NEVER_ALLOW = 1; // 0x1
}
public static final class WebSettings.LayoutAlgorithm extends java.lang.Enum {
@@ -32982,6 +33330,7 @@
method public deprecated boolean canZoomOut();
method public deprecated android.graphics.Picture capturePicture();
method public void clearCache(boolean);
+ method public static void clearClientCertPreferences(java.lang.Runnable);
method public void clearFormData();
method public void clearHistory();
method public void clearMatches();
@@ -33030,6 +33379,7 @@
method public boolean pageUp(boolean);
method public void pauseTimers();
method public void postUrl(java.lang.String, byte[]);
+ method public void preauthorizePermission(android.net.Uri, long);
method public void reload();
method public void removeJavascriptInterface(java.lang.String);
method public void requestFocusNodeHref(android.os.Message);
@@ -33098,13 +33448,15 @@
method public void onLoadResource(android.webkit.WebView, java.lang.String);
method public void onPageFinished(android.webkit.WebView, java.lang.String);
method public void onPageStarted(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
+ method public void onReceivedClientCertRequest(android.webkit.WebView, android.webkit.ClientCertRequest);
method public void onReceivedError(android.webkit.WebView, int, java.lang.String, java.lang.String);
method public void onReceivedHttpAuthRequest(android.webkit.WebView, android.webkit.HttpAuthHandler, java.lang.String, java.lang.String);
method public void onReceivedLoginRequest(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String);
method public void onReceivedSslError(android.webkit.WebView, android.webkit.SslErrorHandler, android.net.http.SslError);
method public void onScaleChanged(android.webkit.WebView, float, float);
method public deprecated void onTooManyRedirects(android.webkit.WebView, android.os.Message, android.os.Message);
- method public void onUnhandledKeyEvent(android.webkit.WebView, android.view.KeyEvent);
+ method public void onUnhandledInputEvent(android.webkit.WebView, android.view.InputEvent);
+ method public deprecated void onUnhandledKeyEvent(android.webkit.WebView, android.view.KeyEvent);
method public android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebView, java.lang.String);
method public boolean shouldOverrideKeyEvent(android.webkit.WebView, android.view.KeyEvent);
method public boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String);
@@ -39480,11 +39832,13 @@
method public java.lang.String getValue();
method public int getVersion();
method public boolean hasExpired();
+ method public boolean isHttpOnly();
method public static java.util.List<java.net.HttpCookie> parse(java.lang.String);
method public void setComment(java.lang.String);
method public void setCommentURL(java.lang.String);
method public void setDiscard(boolean);
method public void setDomain(java.lang.String);
+ method public void setHttpOnly(boolean);
method public void setMaxAge(long);
method public void setPath(java.lang.String);
method public void setPortlist(java.lang.String);
@@ -40437,7 +40791,7 @@
ctor public ConnectionPendingException();
}
- public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel {
+ public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.MulticastChannel java.nio.channels.ScatteringByteChannel {
ctor protected DatagramChannel(java.nio.channels.spi.SelectorProvider);
method public java.nio.channels.DatagramChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.nio.channels.DatagramChannel connect(java.net.SocketAddress) throws java.io.IOException;
@@ -40445,6 +40799,8 @@
method public java.net.SocketAddress getLocalAddress() throws java.io.IOException;
method public T getOption(java.net.SocketOption<T>) throws java.io.IOException;
method public abstract boolean isConnected();
+ method public java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
+ method public java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
method public static java.nio.channels.DatagramChannel open() throws java.io.IOException;
method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
@@ -40492,6 +40848,7 @@
public abstract class FileLock implements java.lang.AutoCloseable {
ctor protected FileLock(java.nio.channels.FileChannel, long, long, boolean);
+ method public java.nio.channels.Channel acquiredBy();
method public final java.nio.channels.FileChannel channel();
method public final void close() throws java.io.IOException;
method public final boolean isShared();
@@ -40524,6 +40881,24 @@
method public abstract void close() throws java.io.IOException;
}
+ public abstract class MembershipKey {
+ ctor protected MembershipKey();
+ method public abstract java.nio.channels.MembershipKey block(java.net.InetAddress) throws java.io.IOException;
+ method public abstract java.nio.channels.MulticastChannel channel();
+ method public abstract void drop();
+ method public abstract java.net.InetAddress group();
+ method public abstract boolean isValid();
+ method public abstract java.net.NetworkInterface networkInterface();
+ method public abstract java.net.InetAddress sourceAddress();
+ method public abstract java.nio.channels.MembershipKey unblock(java.net.InetAddress);
+ }
+
+ public abstract interface MulticastChannel implements java.nio.channels.NetworkChannel {
+ method public abstract void close() throws java.io.IOException;
+ method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
+ method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
+ }
+
public abstract interface NetworkChannel implements java.lang.AutoCloseable java.nio.channels.Channel java.io.Closeable {
method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
@@ -44629,6 +45004,7 @@
method public java.lang.String getDisplayName(java.util.Locale);
method public static java.util.Currency getInstance(java.lang.String);
method public static java.util.Currency getInstance(java.util.Locale);
+ method public int getNumericCode();
method public java.lang.String getSymbol();
method public java.lang.String getSymbol(java.util.Locale);
}
@@ -47711,8 +48087,10 @@
public class ZipFile implements java.io.Closeable {
ctor public ZipFile(java.io.File) throws java.io.IOException, java.util.zip.ZipException;
+ ctor public ZipFile(java.io.File, java.nio.charset.Charset) throws java.io.IOException, java.util.zip.ZipException;
ctor public ZipFile(java.lang.String) throws java.io.IOException;
ctor public ZipFile(java.io.File, int) throws java.io.IOException;
+ ctor public ZipFile(java.io.File, int, java.nio.charset.Charset) throws java.io.IOException;
method public void close() throws java.io.IOException;
method public java.util.Enumeration<? extends java.util.zip.ZipEntry> entries();
method public java.lang.String getComment();
@@ -47766,6 +48144,7 @@
public class ZipInputStream extends java.util.zip.InflaterInputStream {
ctor public ZipInputStream(java.io.InputStream);
+ ctor public ZipInputStream(java.io.InputStream, java.nio.charset.Charset);
method public void closeEntry() throws java.io.IOException;
method protected java.util.zip.ZipEntry createZipEntry(java.lang.String);
method public java.util.zip.ZipEntry getNextEntry() throws java.io.IOException;
@@ -47813,6 +48192,7 @@
public class ZipOutputStream extends java.util.zip.DeflaterOutputStream {
ctor public ZipOutputStream(java.io.OutputStream);
+ ctor public ZipOutputStream(java.io.OutputStream, java.nio.charset.Charset);
method public void closeEntry() throws java.io.IOException;
method public void putNextEntry(java.util.zip.ZipEntry) throws java.io.IOException;
method public void setComment(java.lang.String);
@@ -49311,6 +49691,7 @@
method public abstract boolean getEnableSessionCreation();
method public abstract java.lang.String[] getEnabledCipherSuites();
method public abstract java.lang.String[] getEnabledProtocols();
+ method public javax.net.ssl.SSLSession getHandshakeSession();
method public abstract javax.net.ssl.SSLEngineResult.HandshakeStatus getHandshakeStatus();
method public abstract boolean getNeedClientAuth();
method public java.lang.String getPeerHost();
@@ -49384,10 +49765,12 @@
ctor public SSLParameters(java.lang.String[]);
ctor public SSLParameters(java.lang.String[], java.lang.String[]);
method public java.lang.String[] getCipherSuites();
+ method public java.lang.String getEndpointIdentificationAlgorithm();
method public boolean getNeedClientAuth();
method public java.lang.String[] getProtocols();
method public boolean getWantClientAuth();
method public void setCipherSuites(java.lang.String[]);
+ method public void setEndpointIdentificationAlgorithm(java.lang.String);
method public void setNeedClientAuth(boolean);
method public void setProtocols(java.lang.String[]);
method public void setWantClientAuth(boolean);
@@ -49488,6 +49871,7 @@
method public abstract boolean getEnableSessionCreation();
method public abstract java.lang.String[] getEnabledCipherSuites();
method public abstract java.lang.String[] getEnabledProtocols();
+ method public javax.net.ssl.SSLSession getHandshakeSession();
method public abstract boolean getNeedClientAuth();
method public javax.net.ssl.SSLParameters getSSLParameters();
method public abstract javax.net.ssl.SSLSession getSession();
@@ -49543,6 +49927,14 @@
method public java.lang.String chooseEngineServerAlias(java.lang.String, java.security.Principal[], javax.net.ssl.SSLEngine);
}
+ public abstract class X509ExtendedTrustManager implements javax.net.ssl.X509TrustManager {
+ ctor public X509ExtendedTrustManager();
+ method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String, java.net.Socket) throws java.security.cert.CertificateException;
+ method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
+ method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, java.net.Socket) throws java.security.cert.CertificateException;
+ method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
+ }
+
public abstract interface X509KeyManager implements javax.net.ssl.KeyManager {
method public abstract java.lang.String chooseClientAlias(java.lang.String[], java.security.Principal[], java.net.Socket);
method public abstract java.lang.String chooseServerAlias(java.lang.String, java.security.Principal[], java.net.Socket);
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 20236aa..933135d 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -21,6 +21,7 @@
import android.content.res.XmlResourceParser;
import android.content.res.Resources.NotFoundException;
import android.util.AttributeSet;
+import android.util.StateSet;
import android.util.TypedValue;
import android.util.Xml;
import android.view.animation.AnimationUtils;
@@ -87,9 +88,86 @@
}
}
+ public static StateListAnimator loadStateListAnimator(Context context, int id)
+ throws NotFoundException {
+ XmlResourceParser parser = null;
+ try {
+ parser = context.getResources().getAnimation(id);
+ return createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
+ } catch (XmlPullParserException ex) {
+ Resources.NotFoundException rnf =
+ new Resources.NotFoundException(
+ "Can't load state list animator resource ID #0x" +
+ Integer.toHexString(id)
+ );
+ rnf.initCause(ex);
+ throw rnf;
+ } catch (IOException ex) {
+ Resources.NotFoundException rnf =
+ new Resources.NotFoundException(
+ "Can't load state list animator resource ID #0x" +
+ Integer.toHexString(id)
+ );
+ rnf.initCause(ex);
+ throw rnf;
+ } finally {
+ if (parser != null) {
+ parser.close();
+ }
+ }
+ }
+
+ private static StateListAnimator createStateListAnimatorFromXml(Context context,
+ XmlPullParser parser, AttributeSet attributeSet)
+ throws IOException, XmlPullParserException {
+ int type;
+ StateListAnimator stateListAnimator = new StateListAnimator();
+
+ while (true) {
+ type = parser.next();
+ switch (type) {
+ case XmlPullParser.END_DOCUMENT:
+ case XmlPullParser.END_TAG:
+ return stateListAnimator;
+
+ case XmlPullParser.START_TAG:
+ // parse item
+ Animator animator = null;
+ if ("item".equals(parser.getName())) {
+ int attributeCount = parser.getAttributeCount();
+ int[] states = new int[attributeCount];
+ int stateIndex = 0;
+ for (int i = 0; i < attributeCount; i++) {
+ int attrName = attributeSet.getAttributeNameResource(i);
+ if (attrName == com.android.internal.R.attr.animation) {
+ animator = loadAnimator(context,
+ attributeSet.getAttributeResourceValue(i, 0));
+ } else {
+ states[stateIndex++] =
+ attributeSet.getAttributeBooleanValue(i, false) ?
+ attrName : -attrName;
+ }
+
+ }
+ if (animator == null) {
+ animator = createAnimatorFromXml(context, parser);
+ }
+
+ if (animator == null) {
+ throw new Resources.NotFoundException(
+ "animation state item must have a valid animation");
+ }
+ stateListAnimator
+ .addState(StateSet.trimStateSet(states, stateIndex), animator);
+
+ }
+ break;
+ }
+ }
+ }
+
private static Animator createAnimatorFromXml(Context c, XmlPullParser parser)
throws XmlPullParserException, IOException {
-
return createAnimatorFromXml(c, parser, Xml.asAttributeSet(parser), null, 0);
}
diff --git a/core/java/android/animation/StateListAnimator.java b/core/java/android/animation/StateListAnimator.java
new file mode 100644
index 0000000..bc4843d
--- /dev/null
+++ b/core/java/android/animation/StateListAnimator.java
@@ -0,0 +1,209 @@
+/*
+ * 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.animation;
+
+import android.util.StateSet;
+import android.view.View;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+/**
+ * Lets you define a number of Animators that will run on the attached View depending on the View's
+ * drawable state.
+ * <p>
+ * It can be defined in an XML file with the <code><selector></code> element.
+ * Each State Animator is defined in a nested <code><item></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
+ * @attr ref android.R.styleable#StateListAnimatorItem_animation
+ */
+public class StateListAnimator {
+
+ private final ArrayList<Tuple> mTuples = new ArrayList<Tuple>();
+
+ private Tuple mLastMatch = null;
+
+ private Animator mRunningAnimator = null;
+
+ private WeakReference<View> mViewRef;
+
+ private AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mRunningAnimator == animation) {
+ mRunningAnimator = null;
+ }
+ }
+ };
+
+ /**
+ * Associates the given animator with the provided drawable state specs so that it will be run
+ * when the View's drawable state matches the specs.
+ *
+ * @param specs The drawable state specs to match against
+ * @param animator The animator to run when the specs match
+ */
+ public void addState(int[] specs, Animator animator) {
+ Tuple tuple = new Tuple(specs, animator);
+ tuple.mAnimator.addListener(mAnimatorListener);
+ mTuples.add(tuple);
+ }
+
+ /**
+ * Returns the current {@link android.animation.Animator} which is started because of a state
+ * change.
+ *
+ * @return The currently running Animator or null if no Animator is running
+ * @hide
+ */
+ public Animator getRunningAnimator() {
+ return mRunningAnimator;
+ }
+
+ /**
+ * @hide
+ */
+ public View getTarget() {
+ return mViewRef == null ? null : mViewRef.get();
+ }
+
+ /**
+ * Called by View
+ * @hide
+ */
+ public void setTarget(View view) {
+ final View current = getTarget();
+ if (current == view) {
+ return;
+ }
+ if (current != null) {
+ clearTarget();
+ }
+ if (view != null) {
+ mViewRef = new WeakReference<View>(view);
+ }
+
+ }
+
+ private void clearTarget() {
+ final int size = mTuples.size();
+ for (int i = 0; i < size; i++) {
+ mTuples.get(i).mAnimator.setTarget(null);
+ }
+
+ mViewRef = null;
+ mLastMatch = null;
+ mRunningAnimator = null;
+ }
+
+ /**
+ * Called by View
+ * @hide
+ */
+ public void setState(int[] state) {
+ Tuple match = null;
+ final int count = mTuples.size();
+ for (int i = 0; i < count; i++) {
+ final Tuple tuple = mTuples.get(i);
+ if (StateSet.stateSetMatches(tuple.mSpecs, state)) {
+ match = tuple;
+ break;
+ }
+ }
+ if (match == mLastMatch) {
+ return;
+ }
+ if (mLastMatch != null) {
+ cancel(mLastMatch);
+ }
+ mLastMatch = match;
+ if (match != null) {
+ start(match);
+ }
+ }
+
+ private void start(Tuple match) {
+ match.mAnimator.setTarget(getTarget());
+ mRunningAnimator = match.mAnimator;
+ match.mAnimator.start();
+ }
+
+ private void cancel(Tuple lastMatch) {
+ lastMatch.mAnimator.cancel();
+ lastMatch.mAnimator.setTarget(null);
+ }
+
+ /**
+ * @hide
+ */
+ public ArrayList<Tuple> getTuples() {
+ return mTuples;
+ }
+
+ /**
+ * If there is an animation running for a recent state change, ends it.
+ * <p>
+ * This causes the animation to assign the end value(s) to the View.
+ */
+ public void jumpToCurrentState() {
+ if (mRunningAnimator != null) {
+ mRunningAnimator.end();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static class Tuple {
+
+ final int[] mSpecs;
+
+ final Animator mAnimator;
+
+ private Tuple(int[] specs, Animator animator) {
+ mSpecs = specs;
+ mAnimator = animator;
+ }
+
+ /**
+ * @hide
+ */
+ public int[] getSpecs() {
+ return mSpecs;
+ }
+
+ /**
+ * @hide
+ */
+ public Animator getAnimator() {
+ return mAnimator;
+ }
+ }
+}
diff --git a/core/java/android/animation/TypeEvaluator.java b/core/java/android/animation/TypeEvaluator.java
index 2640457..429c435 100644
--- a/core/java/android/animation/TypeEvaluator.java
+++ b/core/java/android/animation/TypeEvaluator.java
@@ -29,7 +29,7 @@
/**
* This function returns the result of linearly interpolating the start and end values, with
* <code>fraction</code> representing the proportion between the start and end values. The
- * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
+ * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
* and <code>t</code> is <code>fraction</code>.
*
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 04f62e3..3c3df01 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -932,6 +932,66 @@
*/
public void setHomeActionContentDescription(int resId) { }
+ /**
+ * Enable hiding the action bar on content scroll.
+ *
+ * <p>If enabled, the action bar will scroll out of sight along with a
+ * {@link View#setNestedScrollingEnabled(boolean) nested scrolling child} view's content.
+ * The action bar must be in {@link Window#FEATURE_ACTION_BAR_OVERLAY overlay mode}
+ * to enable hiding on content scroll.</p>
+ *
+ * <p>When partially scrolled off screen the action bar is considered
+ * {@link #hide() hidden}. A call to {@link #show() show} will cause it to return to full view.
+ * </p>
+ * @param hideOnContentScroll true to enable hiding on content scroll.
+ */
+ public void setHideOnContentScrollEnabled(boolean hideOnContentScroll) {
+ if (hideOnContentScroll) {
+ throw new UnsupportedOperationException("Hide on content scroll is not supported in " +
+ "this action bar configuration.");
+ }
+ }
+
+ /**
+ * Return whether the action bar is configured to scroll out of sight along with
+ * a {@link View#setNestedScrollingEnabled(boolean) nested scrolling child}.
+ *
+ * @return true if hide-on-content-scroll is enabled
+ * @see #setHideOnContentScrollEnabled(boolean)
+ */
+ public boolean isHideOnContentScrollEnabled() {
+ return false;
+ }
+
+ /**
+ * Return the current vertical offset of the action bar.
+ *
+ * <p>The action bar's current hide offset is the distance that the action bar is currently
+ * scrolled offscreen in pixels. The valid range is 0 (fully visible) to the action bar's
+ * current measured {@link #getHeight() height} (fully invisible).</p>
+ *
+ * @return The action bar's offset toward its fully hidden state in pixels
+ */
+ public int getHideOffset() {
+ return 0;
+ }
+
+ /**
+ * Set the current hide offset of the action bar.
+ *
+ * <p>The action bar's current hide offset is the distance that the action bar is currently
+ * scrolled offscreen in pixels. The valid range is 0 (fully visible) to the action bar's
+ * current measured {@link #getHeight() height} (fully invisible).</p>
+ *
+ * @param offset The action bar's offset toward its fully hidden state in pixels.
+ */
+ public void setHideOffset(int offset) {
+ if (offset != 0) {
+ throw new UnsupportedOperationException("Setting an explicit action bar hide offset " +
+ "is not supported in this action bar configuration.");
+ }
+ }
+
/** @hide */
public void setDefaultDisplayHomeAsUpEnabled(boolean enabled) {
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8981c88..36f9f4b 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -29,6 +29,7 @@
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;
@@ -655,7 +656,8 @@
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
- OnCreateContextMenuListener, ComponentCallbacks2 {
+ OnCreateContextMenuListener, ComponentCallbacks2,
+ Window.OnWindowDismissedCallback {
private static final String TAG = "Activity";
private static final boolean DEBUG_LIFECYCLE = false;
@@ -2519,7 +2521,9 @@
/**
* Called when the main window associated with the activity has been dismissed.
+ * @hide
*/
+ @Override
public void onWindowDismissed() {
finish();
}
@@ -3493,6 +3497,16 @@
}
theme.applyStyle(resid, false);
}
+
+ // 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);
+ }
}
/**
@@ -4779,31 +4793,26 @@
}
/**
- * Set a label and icon to be used in the Recents task display. When {@link
- * ActivityManager#getRecentTasks} is called, the activities of each task are
- * traversed in order from the topmost activity to the bottommost. As soon as one activity is
- * found with either a non-null label or a non-null icon set by this call the traversal is
- * ended. For each task those values will be returned in {@link
- * ActivityManager.RecentTaskInfo#activityLabel} and {@link
- * ActivityManager.RecentTaskInfo#activityIcon}.
+ * Sets information describing this Activity for presentation inside the Recents System UI. When
+ * {@link ActivityManager#getRecentTasks} is called, the activities of each task are
+ * traversed in order from the topmost activity to the bottommost. The traversal continues for
+ * each property until a suitable value is found. For each task those values will be returned in
+ * {@link android.app.ActivityManager.RecentsActivityValues}.
*
* @see ActivityManager#getRecentTasks
- * @see ActivityManager.RecentTaskInfo
+ * @see android.app.ActivityManager.RecentsActivityValues
*
- * @param activityLabel The label to use in the RecentTaskInfo.
- * @param activityIcon The Bitmap to use in the RecentTaskInfo.
+ * @param values The Recents values that describe this activity.
*/
- public void setActivityLabelAndIcon(CharSequence activityLabel, Bitmap activityIcon) {
- final Bitmap scaledIcon;
- if (activityIcon != null) {
+ public void setRecentsActivityValues(ActivityManager.RecentsActivityValues values) {
+ ActivityManager.RecentsActivityValues activityValues =
+ new ActivityManager.RecentsActivityValues(values);
+ if (values.icon != null) {
final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
- scaledIcon = Bitmap.createScaledBitmap(activityIcon, size, size, true);
- } else {
- scaledIcon = null;
+ activityValues.icon = Bitmap.createScaledBitmap(values.icon, size, size, true);
}
try {
- ActivityManagerNative.getDefault().setActivityLabelAndIcon(mToken, activityLabel,
- scaledIcon);
+ ActivityManagerNative.getDefault().setRecentsActivityValues(mToken, activityValues);
} catch (RemoteException e) {
}
}
@@ -5432,6 +5441,7 @@
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
+ mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
@@ -5680,7 +5690,16 @@
}
}
- /** @hide */
+ /**
+ * Put this Activity in a mode where the user is locked to the
+ * current task.
+ *
+ * This will prevent the user from launching other apps, going to settings,
+ * or reaching the home screen.
+ *
+ * Lock task mode will only start if the activity has been whitelisted by the
+ * Device Owner through DevicePolicyManager#setLockTaskComponents.
+ */
public void startLockTask() {
try {
ActivityManagerNative.getDefault().startLockTaskMode(mToken);
@@ -5688,7 +5707,15 @@
}
}
- /** @hide */
+ /**
+ * Allow the user to switch away from the current task.
+ *
+ * Called to end the mode started by {@link Activity#startLockTask}. This
+ * can only be called by activities that have successfully called
+ * startLockTask previously.
+ *
+ * This will allow the user to exit this app and move onto other activities.
+ */
public void stopLockTask() {
try {
ActivityManagerNative.getDefault().stopLockTaskMode();
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 9239faf..5d809d8 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -475,6 +475,111 @@
}
/**
+ * Information you can set and retrieve about the current activity within Recents.
+ */
+ public static class RecentsActivityValues implements Parcelable {
+ public CharSequence label;
+ public Bitmap icon;
+ public int colorPrimary;
+
+ public RecentsActivityValues(RecentsActivityValues values) {
+ copyFrom(values);
+ }
+
+ /**
+ * Creates the RecentsActivityValues to the specified values.
+ *
+ * @param label A label and description of the current state of this activity.
+ * @param icon An icon that represents the current state of this activity.
+ * @param color A color to override the theme's primary color.
+ */
+ public RecentsActivityValues(CharSequence label, Bitmap icon, int color) {
+ this.label = label;
+ this.icon = icon;
+ this.colorPrimary = color;
+ }
+
+ /**
+ * Creates the RecentsActivityValues to the specified values.
+ *
+ * @param label A label and description of the current state of this activity.
+ * @param icon An icon that represents the current state of this activity.
+ */
+ public RecentsActivityValues(CharSequence label, Bitmap icon) {
+ this(label, icon, 0);
+ }
+
+ /**
+ * Creates the RecentsActivityValues to the specified values.
+ *
+ * @param label A label and description of the current state of this activity.
+ */
+ public RecentsActivityValues(CharSequence label) {
+ this(label, null, 0);
+ }
+
+ public RecentsActivityValues() {
+ this(null, null, 0);
+ }
+
+ private RecentsActivityValues(Parcel source) {
+ readFromParcel(source);
+ }
+
+ /**
+ * Do a shallow copy of another set of activity values.
+ * @hide
+ */
+ public void copyFrom(RecentsActivityValues v) {
+ if (v != null) {
+ label = v.label;
+ icon = v.icon;
+ colorPrimary = v.colorPrimary;
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ TextUtils.writeToParcel(label, dest,
+ Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ if (icon == null) {
+ dest.writeInt(0);
+ } else {
+ dest.writeInt(1);
+ icon.writeToParcel(dest, 0);
+ }
+ dest.writeInt(colorPrimary);
+ }
+
+ public void readFromParcel(Parcel source) {
+ label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+ icon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
+ colorPrimary = source.readInt();
+ }
+
+ public static final Creator<RecentsActivityValues> CREATOR
+ = new Creator<RecentsActivityValues>() {
+ public RecentsActivityValues createFromParcel(Parcel source) {
+ return new RecentsActivityValues(source);
+ }
+ public RecentsActivityValues[] newArray(int size) {
+ return new RecentsActivityValues[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return "RecentsActivityValues Label: " + label + " Icon: " + icon +
+ " colorPrimary: " + colorPrimary;
+ }
+ }
+
+ /**
* Information you can retrieve about tasks that the user has most recently
* started or visited.
*/
@@ -523,16 +628,10 @@
public int userId;
/**
- * The label of the highest activity in the task stack to have set a label using
- * {@link Activity#setActivityLabelAndIcon(CharSequence, android.graphics.Bitmap)}.
+ * The recent activity values for the highest activity in the stack to have set the values.
+ * {@link Activity#setRecentsActivityValues(android.app.ActivityManager.RecentsActivityValues)}.
*/
- public CharSequence activityLabel;
-
- /**
- * The Bitmap icon of the highest activity in the task stack to set a Bitmap using
- * {@link Activity#setActivityLabelAndIcon(CharSequence, android.graphics.Bitmap)}.
- */
- public Bitmap activityIcon;
+ public RecentsActivityValues activityValues;
public RecentTaskInfo() {
}
@@ -555,13 +654,11 @@
ComponentName.writeToParcel(origActivity, dest);
TextUtils.writeToParcel(description, dest,
Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
- TextUtils.writeToParcel(activityLabel, dest,
- Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
- if (activityIcon == null) {
- dest.writeInt(0);
- } else {
+ if (activityValues != null) {
dest.writeInt(1);
- activityIcon.writeToParcel(dest, 0);
+ activityValues.writeToParcel(dest, 0);
+ } else {
+ dest.writeInt(0);
}
dest.writeInt(stackId);
dest.writeInt(userId);
@@ -573,8 +670,8 @@
baseIntent = source.readInt() > 0 ? Intent.CREATOR.createFromParcel(source) : null;
origActivity = ComponentName.readFromParcel(source);
description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
- activityLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
- activityIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
+ activityValues = source.readInt() > 0 ?
+ RecentsActivityValues.CREATOR.createFromParcel(source) : null;
stackId = source.readInt();
userId = source.readInt();
}
@@ -791,42 +888,6 @@
* activity -- the task may have been frozen by the system, so that it
* can be restarted in its previous state when next brought to the
* foreground.
- *
- * @param maxNum The maximum number of entries to return in the list. The
- * actual number returned may be smaller, depending on how many tasks the
- * user has started.
- *
- * @param flags Optional flags
- * @param receiver Optional receiver for delayed thumbnails
- *
- * @return Returns a list of RunningTaskInfo records describing each of
- * the running tasks.
- *
- * Some thumbnails may not be available at the time of this call. The optional
- * receiver may be used to receive those thumbnails.
- *
- * @throws SecurityException Throws SecurityException if the caller does
- * not hold the {@link android.Manifest.permission#GET_TASKS} permission.
- *
- * @hide
- */
- public List<RunningTaskInfo> getRunningTasks(int maxNum, int flags, IThumbnailReceiver receiver)
- throws SecurityException {
- try {
- return ActivityManagerNative.getDefault().getTasks(maxNum, flags, receiver);
- } catch (RemoteException e) {
- // System dead, we will be dead too soon!
- return null;
- }
- }
-
- /**
- * Return a list of the tasks that are currently running, with
- * the most recent being first and older ones after in order. Note that
- * "running" does not mean any of the task's code is currently loaded or
- * activity -- the task may have been frozen by the system, so that it
- * can be restarted in its previous state when next brought to the
- * foreground.
*
* <p><b>Note: this method is only intended for debugging and presenting
* task management user interfaces</b>. This should never be used for
@@ -849,7 +910,12 @@
*/
public List<RunningTaskInfo> getRunningTasks(int maxNum)
throws SecurityException {
- return getRunningTasks(maxNum, 0, null);
+ try {
+ return ActivityManagerNative.getDefault().getTasks(maxNum, 0);
+ } catch (RemoteException e) {
+ // System dead, we will be dead too soon!
+ return null;
+ }
}
/**
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b1c37de..57da21e 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -509,11 +509,7 @@
data.enforceInterface(IActivityManager.descriptor);
int maxNum = data.readInt();
int fl = data.readInt();
- IBinder receiverBinder = data.readStrongBinder();
- IThumbnailReceiver receiver = receiverBinder != null
- ? IThumbnailReceiver.Stub.asInterface(receiverBinder)
- : null;
- List<ActivityManager.RunningTaskInfo> list = getTasks(maxNum, fl, receiver);
+ List<ActivityManager.RunningTaskInfo> list = getTasks(maxNum, fl);
reply.writeNoException();
int N = list != null ? list.size() : -1;
reply.writeInt(N);
@@ -712,17 +708,6 @@
return true;
}
- case REPORT_THUMBNAIL_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- IBinder token = data.readStrongBinder();
- Bitmap thumbnail = data.readInt() != 0
- ? Bitmap.CREATOR.createFromParcel(data) : null;
- CharSequence description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
- reportThumbnail(token, thumbnail, description);
- reply.writeNoException();
- return true;
- }
-
case GET_CONTENT_PROVIDER_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
@@ -2134,13 +2119,12 @@
return true;
}
- case SET_ACTIVITY_LABEL_ICON_TRANSACTION: {
+ case SET_RECENTS_ACTIVITY_VALUES_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
- CharSequence activityLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
- Bitmap activityIcon = data.readInt() > 0
- ? Bitmap.CREATOR.createFromParcel(data) : null;
- setActivityLabelAndIcon(token, activityLabel, activityIcon);
+ ActivityManager.RecentsActivityValues values =
+ ActivityManager.RecentsActivityValues.CREATOR.createFromParcel(data);
+ setRecentsActivityValues(token, values);
reply.writeNoException();
return true;
}
@@ -2678,14 +2662,12 @@
reply.recycle();
return res;
}
- public List getTasks(int maxNum, int flags,
- IThumbnailReceiver receiver) throws RemoteException {
+ public List getTasks(int maxNum, int flags) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(maxNum);
data.writeInt(flags);
- data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
mRemote.transact(GET_TASKS_TRANSACTION, data, reply, 0);
reply.readException();
ArrayList list = null;
@@ -2964,25 +2946,6 @@
reply.recycle();
return res;
}
- public void reportThumbnail(IBinder token,
- Bitmap thumbnail, CharSequence description) throws RemoteException
- {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(token);
- if (thumbnail != null) {
- data.writeInt(1);
- thumbnail.writeToParcel(data, 0);
- } else {
- data.writeInt(0);
- }
- TextUtils.writeToParcel(description, data, 0);
- mRemote.transact(REPORT_THUMBNAIL_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
- reply.readException();
- data.recycle();
- reply.recycle();
- }
public ContentProviderHolder getContentProvider(IApplicationThread caller,
String name, int userId, boolean stable) throws RemoteException {
Parcel data = Parcel.obtain();
@@ -4919,21 +4882,14 @@
}
@Override
- public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
- Bitmap activityIcon) throws RemoteException
- {
+ public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues values)
+ throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
- TextUtils.writeToParcel(activityLabel, data, 0);
- if (activityIcon != null) {
- data.writeInt(1);
- activityIcon.writeToParcel(data, 0);
- } else {
- data.writeInt(0);
- }
- mRemote.transact(SET_ACTIVITY_LABEL_ICON_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+ values.writeToParcel(data, 0);
+ mRemote.transact(SET_RECENTS_ACTIVITY_VALUES_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
reply.readException();
data.recycle();
reply.recycle();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7dc21b4..b606088 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -46,7 +46,7 @@
import android.hardware.display.DisplayManagerGlobal;
import android.net.IConnectivityManager;
import android.net.Proxy;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
import android.opengl.GLUtils;
import android.os.AsyncTask;
import android.os.Binder;
@@ -821,10 +821,6 @@
sendMessage(H.SUICIDE, null);
}
- public void requestThumbnail(IBinder token) {
- sendMessage(H.REQUEST_THUMBNAIL, token);
- }
-
public void scheduleConfigurationChanged(Configuration config) {
updatePendingConfiguration(config);
sendMessage(H.CONFIGURATION_CHANGED, config);
@@ -1168,7 +1164,7 @@
public static final int CREATE_SERVICE = 114;
public static final int SERVICE_ARGS = 115;
public static final int STOP_SERVICE = 116;
- public static final int REQUEST_THUMBNAIL = 117;
+
public static final int CONFIGURATION_CHANGED = 118;
public static final int CLEAN_UP_CONTEXT = 119;
public static final int GC_WHEN_IDLE = 120;
@@ -1218,7 +1214,6 @@
case CREATE_SERVICE: return "CREATE_SERVICE";
case SERVICE_ARGS: return "SERVICE_ARGS";
case STOP_SERVICE: return "STOP_SERVICE";
- case REQUEST_THUMBNAIL: return "REQUEST_THUMBNAIL";
case CONFIGURATION_CHANGED: return "CONFIGURATION_CHANGED";
case CLEAN_UP_CONTEXT: return "CLEAN_UP_CONTEXT";
case GC_WHEN_IDLE: return "GC_WHEN_IDLE";
@@ -1367,11 +1362,6 @@
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
- case REQUEST_THUMBNAIL:
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "requestThumbnail");
- handleRequestThumbnail((IBinder)msg.obj);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- break;
case CONFIGURATION_CHANGED:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged");
mCurDefaultDisplayDpi = ((Configuration)msg.obj).densityDpi;
@@ -3817,28 +3807,6 @@
handleLaunchActivity(r, currentIntent);
}
- private void handleRequestThumbnail(IBinder token) {
- ActivityClientRecord r = mActivities.get(token);
- Bitmap thumbnail = createThumbnailBitmap(r);
- CharSequence description = null;
- try {
- description = r.activity.onCreateDescription();
- } catch (Exception e) {
- if (!mInstrumentation.onException(r.activity, e)) {
- throw new RuntimeException(
- "Unable to create description of activity "
- + r.intent.getComponent().toShortString()
- + ": " + e.toString(), e);
- }
- }
- //System.out.println("Reporting top thumbnail " + thumbnail);
- try {
- ActivityManagerNative.getDefault().reportThumbnail(
- token, thumbnail, description);
- } catch (RemoteException ex) {
- }
- }
-
ArrayList<ComponentCallbacks2> collectComponentCallbacks(
boolean allActivities, Configuration newConfig) {
ArrayList<ComponentCallbacks2> callbacks
@@ -4326,8 +4294,8 @@
// crash if we can't get it.
IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
try {
- ProxyProperties proxyProperties = service.getProxy();
- Proxy.setHttpProxySystemProperty(proxyProperties);
+ ProxyInfo proxyInfo = service.getProxy();
+ Proxy.setHttpProxySystemProperty(proxyInfo);
} catch (RemoteException e) {}
}
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 3c1455b..3eb2fea 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -21,6 +21,7 @@
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;
@@ -30,6 +31,7 @@
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;
@@ -138,6 +140,10 @@
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";
+
+ private static final ImageView.ScaleType[] SCALE_TYPE_VALUES = ImageView.ScaleType.values();
/**
* Sent by the exiting coordinator (either EnterTransitionCoordinator
@@ -322,7 +328,8 @@
final ArrayList<View> accepted = new ArrayList<View>();
final ArrayList<View> rejected = new ArrayList<View>();
createSharedElementImages(accepted, rejected, sharedElementNames, state);
- setSharedElementState(state, accepted);
+ ArrayMap<ImageView, Pair<ImageView.ScaleType, Matrix>> originalImageViewState =
+ setSharedElementState(state, accepted);
handleRejected(rejected);
if (getViewsTransition() != null) {
@@ -331,6 +338,7 @@
setViewVisibility(mSharedElements, View.VISIBLE);
Transition transition = beginTransition(mEnteringViews, true, allowOverlappingTransitions(),
true);
+ setOriginalImageViewState(originalImageViewState);
if (allowOverlappingTransitions()) {
onStartEnterTransition(transition, mEnteringViews);
@@ -568,15 +576,22 @@
mEpicenterCallback.setEpicenter(epicenter);
}
- private void setSharedElementState(Bundle sharedElementState,
- final ArrayList<View> acceptedOverlayViews) {
+ 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);
- String name = mTargetSharedNames.get(i);
setSharedElementState(sharedElement, name, sharedElementState, tempLoc);
sharedElement.requestLayout();
}
@@ -596,6 +611,29 @@
}
}
);
+ 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);
}
/**
@@ -614,6 +652,21 @@
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);
@@ -666,6 +719,17 @@
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);
}
@@ -829,6 +893,25 @@
}
}
+ 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);
+ }
+ }
+
+ 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;
+ }
+
private static class FixedEpicenterCallback extends Transition.EpicenterCallback {
private Rect mEpicenter;
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index a810134..097c64e 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -33,6 +33,7 @@
import android.view.Surface;
import android.view.TextureView;
import android.view.TextureView.SurfaceTextureListener;
+import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import dalvik.system.CloseGuard;
@@ -51,6 +52,7 @@
private int mWidth;
private int mHeight;
private Surface mSurface;
+ private int mLastVisibility;
// Only one IIntentSender or Intent may be queued at a time. Most recent one wins.
IIntentSender mQueuedPendingIntent;
@@ -95,6 +97,8 @@
mMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(mMetrics);
+ mLastVisibility = getVisibility();
+
if (DEBUG) Log.v(TAG, "ctor()");
}
@@ -103,6 +107,26 @@
mTextureView.layout(0, 0, r - l, b - t);
}
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+
+ if (mSurface != null) {
+ try {
+ if (visibility == View.GONE) {
+ mActivityContainer.setSurface(null, mWidth, mHeight, mMetrics.densityDpi);
+ } else if (mLastVisibility == View.GONE) {
+ // Don't change surface when going between View.VISIBLE and View.INVISIBLE.
+ mActivityContainer.setSurface(mSurface, mWidth, mHeight, mMetrics.densityDpi);
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException(
+ "ActivityView: Unable to set surface of ActivityContainer. " + e);
+ }
+ }
+ mLastVisibility = visibility;
+ }
+
private boolean injectInputEvent(InputEvent event) {
return mActivityContainer != null && mActivityContainer.injectEvent(event);
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index ab62427..efd3d86 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1440,6 +1440,31 @@
return null;
}
+ /**
+ * @hide
+ */
+ @Override
+ public void addForwardingIntentFilter(IntentFilter filter, boolean removable, int userIdOrig,
+ int userIdDest) {
+ try {
+ mPM.addForwardingIntentFilter(filter, removable, userIdOrig, userIdDest);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void clearForwardingIntentFilters(int userIdOrig) {
+ try {
+ mPM.clearForwardingIntentFilters(userIdOrig);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
private final ContextImpl mContext;
private final IPackageManager mPM;
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index fcc7f8e..7f2fb59 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -312,14 +312,6 @@
return true;
}
- case REQUEST_THUMBNAIL_TRANSACTION:
- {
- data.enforceInterface(IApplicationThread.descriptor);
- IBinder b = data.readStrongBinder();
- requestThumbnail(b);
- return true;
- }
-
case SCHEDULE_CONFIGURATION_CHANGED_TRANSACTION:
{
data.enforceInterface(IApplicationThread.descriptor);
@@ -986,16 +978,6 @@
data.recycle();
}
- public final void requestThumbnail(IBinder token)
- throws RemoteException {
- Parcel data = Parcel.obtain();
- data.writeInterfaceToken(IApplicationThread.descriptor);
- data.writeStrongBinder(token);
- mRemote.transact(REQUEST_THUMBNAIL_TRANSACTION, data, null,
- IBinder.FLAG_ONEWAY);
- data.recycle();
- }
-
public final void scheduleConfigurationChanged(Configuration config)
throws RemoteException {
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index fe532bf..5ed5030 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -16,6 +16,8 @@
package android.app;
+import android.net.wifi.IWifiScanner;
+import android.net.wifi.WifiScanner;
import android.os.Build;
import com.android.internal.policy.PolicyManager;
@@ -106,6 +108,9 @@
import android.os.storage.StorageManager;
import android.print.IPrintManager;
import android.print.PrintManager;
+import android.service.fingerprint.FingerprintManager;
+import android.service.fingerprint.FingerprintManagerReceiver;
+import android.service.fingerprint.FingerprintService;
import android.telephony.TelephonyManager;
import android.tv.ITvInputManager;
import android.tv.TvInputManager;
@@ -451,6 +456,11 @@
return new KeyguardManager();
}});
+ registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new FingerprintManager(ctx);
+ }});
+
registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
@@ -581,6 +591,13 @@
return new WifiP2pManager(service);
}});
+ registerService(WIFI_SCANNING_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(WIFI_SCANNING_SERVICE);
+ IWifiScanner service = IWifiScanner.Stub.asInterface(b);
+ return new WifiScanner(ctx.getOuterContext(), service);
+ }});
+
registerService(WINDOW_SERVICE, new ServiceFetcher() {
Display mDefaultDisplay;
public Object getService(ContextImpl ctx) {
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 07583fd..12d4513 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -79,7 +79,7 @@
* </div>
*/
public class Dialog implements DialogInterface, Window.Callback,
- KeyEvent.Callback, OnCreateContextMenuListener {
+ KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback {
private static final String TAG = "Dialog";
private Activity mOwnerActivity;
@@ -165,6 +165,7 @@
Window w = PolicyManager.makeNewWindow(mContext);
mWindow = w;
w.setCallback(this);
+ w.setOnWindowDismissedCallback(this);
w.setWindowManager(mWindowManager, null, null);
w.setGravity(Gravity.CENTER);
mListenersHandler = new ListenersHandler(this);
@@ -708,6 +709,8 @@
public void onDetachedFromWindow() {
}
+ /** @hide */
+ @Override
public void onWindowDismissed() {
dismiss();
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 6b94c4e..2e9cdf3b7 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -111,8 +111,7 @@
public void activityDestroyed(IBinder token) throws RemoteException;
public String getCallingPackage(IBinder token) throws RemoteException;
public ComponentName getCallingActivity(IBinder token) throws RemoteException;
- public List<RunningTaskInfo> getTasks(int maxNum, int flags,
- IThumbnailReceiver receiver) 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;
public ActivityManager.TaskThumbnails getTaskThumbnails(int taskId) throws RemoteException;
@@ -131,9 +130,6 @@
public boolean isInHomeStack(int taskId) throws RemoteException;
public void setFocusedStack(int stackId) throws RemoteException;
public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException;
- /* oneway */
- public void reportThumbnail(IBinder token,
- Bitmap thumbnail, CharSequence description) throws RemoteException;
public ContentProviderHolder getContentProvider(IApplicationThread caller,
String name, int userId, boolean stable) throws RemoteException;
public ContentProviderHolder getContentProviderExternal(String name, int userId, IBinder token)
@@ -439,8 +435,8 @@
public boolean isInLockTaskMode() throws RemoteException;
/** @hide */
- public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
- Bitmap activityBitmap) throws RemoteException;
+ public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues values)
+ throws RemoteException;
/*
* Private non-Binder interfaces
@@ -571,7 +567,7 @@
int MOVE_TASK_TO_BACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+24;
int MOVE_TASK_BACKWARDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+25;
int GET_TASK_FOR_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+26;
- int REPORT_THUMBNAIL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+27;
+
int GET_CONTENT_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+28;
int PUBLISH_CONTENT_PROVIDERS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+29;
int REF_CONTENT_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30;
@@ -738,6 +734,6 @@
int START_LOCK_TASK_BY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+214;
int STOP_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+215;
int IS_IN_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+216;
- int SET_ACTIVITY_LABEL_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
+ int SET_RECENTS_ACTIVITY_VALUES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
int START_VOICE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index f290e94..fefba8a 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -101,7 +101,6 @@
Bundle coreSettings) throws RemoteException;
void scheduleExit() throws RemoteException;
void scheduleSuicide() throws RemoteException;
- void requestThumbnail(IBinder token) throws RemoteException;
void scheduleConfigurationChanged(Configuration config) throws RemoteException;
void updateTimeZone() throws RemoteException;
void clearDnsCache() throws RemoteException;
@@ -159,7 +158,7 @@
int SCHEDULE_STOP_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+11;
int BIND_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+12;
int SCHEDULE_EXIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+13;
- int REQUEST_THUMBNAIL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+14;
+
int SCHEDULE_CONFIGURATION_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+15;
int SCHEDULE_SERVICE_ARGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+16;
int UPDATE_TIME_ZONE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+17;
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index ad4027d..b917263 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -58,6 +58,8 @@
ZenModeConfig getZenModeConfig();
boolean setZenModeConfig(in ZenModeConfig config);
oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions);
- oneway void requestZenModeConditions(in IConditionListener callback, boolean requested);
+ oneway void requestZenModeConditions(in IConditionListener callback, int relevance);
oneway void setZenModeCondition(in Uri conditionId);
+ oneway void setAutomaticZenModeConditions(in Uri[] conditionIds);
+ Condition[] getAutomaticZenModeConditions();
}
\ No newline at end of file
diff --git a/core/java/android/app/IThumbnailReceiver.aidl b/core/java/android/app/IThumbnailReceiver.aidl
deleted file mode 100644
index 7943f2c..0000000
--- a/core/java/android/app/IThumbnailReceiver.aidl
+++ /dev/null
@@ -1,30 +0,0 @@
-/* //device/java/android/android/app/IThumbnailReceiver.aidl
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES 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.graphics.Bitmap;
-
-/**
- * System private API for receiving updated thumbnails from a checkpoint.
- *
- * {@hide}
- */
-oneway interface IThumbnailReceiver {
- void newThumbnail(int id, in Bitmap thumbnail, CharSequence description);
- void finished();
-}
-
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 25a1493..bba6caf 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -17,7 +17,7 @@
package android.app;
import com.android.internal.R;
-import com.android.internal.util.LegacyNotificationUtil;
+import com.android.internal.util.NotificationColorUtil;
import android.annotation.IntDef;
import android.content.Context;
@@ -28,6 +28,7 @@
import android.media.AudioManager;
import android.net.Uri;
import android.os.BadParcelableException;
+import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -420,6 +421,21 @@
@Priority
public int priority;
+ /**
+ * Accent color (an ARGB integer like the constants in {@link android.graphics.Color})
+ * to be applied by the standard Style templates when presenting this notification.
+ *
+ * The current template design constructs a colorful header image by overlaying the
+ * {@link #icon} image (stenciled in white) atop a field of this color. Alpha components are
+ * ignored.
+ */
+ public int color = COLOR_DEFAULT;
+
+ /**
+ * Special value of {@link #color} telling the system not to decorate this notification with
+ * any special color but instead use default colors when presenting this notification.
+ */
+ public static final int COLOR_DEFAULT = 0; // AKA Color.TRANSPARENT
/**
* Sphere of visibility of this notification, which affects how and when the SystemUI reveals
@@ -877,6 +893,8 @@
if (parcel.readInt() != 0) {
publicVersion = Notification.CREATOR.createFromParcel(parcel);
}
+
+ color = parcel.readInt();
}
@Override
@@ -968,6 +986,8 @@
this.publicVersion.cloneInto(that.publicVersion, heavy);
}
+ that.color = this.color;
+
if (!heavy) {
that.lightenPayload(); // will clean out extras
}
@@ -1110,6 +1130,8 @@
} else {
parcel.writeInt(0);
}
+
+ parcel.writeInt(color);
}
/**
@@ -1218,6 +1240,7 @@
sb.append(Integer.toHexString(this.defaults));
sb.append(" flags=0x");
sb.append(Integer.toHexString(this.flags));
+ sb.append(String.format(" color=0x%08x", this.color));
sb.append(" category="); sb.append(this.category);
if (actions != null) {
sb.append(" ");
@@ -1309,9 +1332,10 @@
private boolean mShowWhen = true;
private int mVisibility = VISIBILITY_PRIVATE;
private Notification mPublicVersion = null;
- private boolean mQuantumTheme;
- private final LegacyNotificationUtil mLegacyNotificationUtil;
+ private final NotificationColorUtil mColorUtil;
private ArrayList<String> mPeople;
+ private boolean mPreQuantum;
+ private int mColor = COLOR_DEFAULT;
/**
* Constructs a new Builder with the defaults:
@@ -1341,12 +1365,8 @@
mPriority = PRIORITY_DEFAULT;
mPeople = new ArrayList<String>();
- // TODO: Decide on targetSdk from calling app whether to use quantum theme.
- mQuantumTheme = true;
-
- // TODO: Decide on targetSdk from calling app whether to instantiate the processor at
- // all.
- mLegacyNotificationUtil = LegacyNotificationUtil.getInstance();
+ mPreQuantum = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.L;
+ mColorUtil = NotificationColorUtil.getInstance();
}
/**
@@ -1853,29 +1873,38 @@
}
}
+ /**
+ * Sets {@link Notification#color}.
+ *
+ * @param argb The accent color to use
+ *
+ * @return The same Builder.
+ */
+ public Builder setColor(int argb) {
+ mColor = argb;
+ return this;
+ }
+
private RemoteViews applyStandardTemplate(int resId, boolean fitIn1U) {
RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
boolean showLine3 = false;
boolean showLine2 = false;
int smallIconImageViewId = R.id.icon;
- if (!mQuantumTheme && mPriority < PRIORITY_LOW) {
- contentView.setInt(R.id.icon,
- "setBackgroundResource", R.drawable.notification_template_icon_low_bg);
- contentView.setInt(R.id.status_bar_latest_event_content,
- "setBackgroundResource", R.drawable.notification_bg_low);
+ if (mPriority < PRIORITY_LOW) {
+ // TODO: Low priority presentation
}
if (mLargeIcon != null) {
contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
- processLegacyLargeIcon(mLargeIcon, contentView);
+ processLargeIcon(mLargeIcon, contentView);
smallIconImageViewId = R.id.right_icon;
}
if (mSmallIcon != 0) {
contentView.setImageViewResource(smallIconImageViewId, mSmallIcon);
contentView.setViewVisibility(smallIconImageViewId, View.VISIBLE);
if (mLargeIcon != null) {
- processLegacySmallIcon(mSmallIcon, smallIconImageViewId, contentView);
+ processSmallRightIcon(mSmallIcon, smallIconImageViewId, contentView);
} else {
- processLegacyLargeIcon(mSmallIcon, contentView);
+ processSmallIconAsLarge(mSmallIcon, contentView);
}
} else {
@@ -2035,12 +2064,12 @@
* doesn't create quantum notifications by itself) app.
*/
private boolean isLegacy() {
- return mLegacyNotificationUtil != null;
+ return mColorUtil != null;
}
private void processLegacyAction(Action action, RemoteViews button) {
if (isLegacy()) {
- if (mLegacyNotificationUtil.isGrayscale(mContext, action.icon)) {
+ if (mColorUtil.isGrayscale(mContext, action.icon)) {
button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0,
mContext.getResources().getColor(
R.color.notification_action_legacy_color_filter),
@@ -2051,47 +2080,70 @@
private CharSequence processLegacyText(CharSequence charSequence) {
if (isLegacy()) {
- return mLegacyNotificationUtil.invertCharSequenceColors(charSequence);
+ return mColorUtil.invertCharSequenceColors(charSequence);
} else {
return charSequence;
}
}
- private void processLegacyLargeIcon(int largeIconId, RemoteViews contentView) {
- if (isLegacy()) {
- processLegacyLargeIcon(
- mLegacyNotificationUtil.isGrayscale(mContext, largeIconId),
- contentView);
+ /**
+ * Apply any necessary background to smallIcons being used in the largeIcon spot.
+ */
+ private void processSmallIconAsLarge(int largeIconId, RemoteViews contentView) {
+ if (!isLegacy() || mColorUtil.isGrayscale(mContext, largeIconId)) {
+ applyLargeIconBackground(contentView);
}
}
- private void processLegacyLargeIcon(Bitmap largeIcon, RemoteViews contentView) {
- if (isLegacy()) {
- processLegacyLargeIcon(
- mLegacyNotificationUtil.isGrayscale(largeIcon),
- contentView);
+ /**
+ * Apply any necessary background to a largeIcon if it's a fake smallIcon (that is,
+ * if it's grayscale).
+ */
+ // TODO: also check bounds, transparency, that sort of thing.
+ private void processLargeIcon(Bitmap largeIcon, RemoteViews contentView) {
+ if (!isLegacy() || mColorUtil.isGrayscale(largeIcon)) {
+ applyLargeIconBackground(contentView);
}
}
- private void processLegacyLargeIcon(boolean isGrayscale, RemoteViews contentView) {
- if (isLegacy() && isGrayscale) {
- contentView.setInt(R.id.icon, "setBackgroundResource",
- R.drawable.notification_icon_legacy_bg_inset);
- }
+ /**
+ * Add a colored circle behind the largeIcon slot.
+ */
+ private void applyLargeIconBackground(RemoteViews contentView) {
+ contentView.setInt(R.id.icon, "setBackgroundResource",
+ R.drawable.notification_icon_legacy_bg_inset);
+
+ contentView.setDrawableParameters(
+ R.id.icon,
+ true,
+ -1,
+ mColor,
+ PorterDuff.Mode.SRC_ATOP,
+ -1);
}
- private void processLegacySmallIcon(int smallIconDrawableId, int smallIconImageViewId,
+ /**
+ * Recolor small icons when used in the R.id.right_icon slot.
+ */
+ private void processSmallRightIcon(int smallIconDrawableId, int smallIconImageViewId,
RemoteViews contentView) {
- if (isLegacy()) {
- if (mLegacyNotificationUtil.isGrayscale(mContext, smallIconDrawableId)) {
- contentView.setDrawableParameters(smallIconImageViewId, false, -1,
- mContext.getResources().getColor(
- R.color.notification_action_legacy_color_filter),
- PorterDuff.Mode.MULTIPLY, -1);
- }
+ if (!isLegacy() || mColorUtil.isGrayscale(mContext, smallIconDrawableId)) {
+ contentView.setDrawableParameters(smallIconImageViewId, false, -1,
+ mContext.getResources().getColor(
+ R.color.notification_action_legacy_color_filter),
+ PorterDuff.Mode.MULTIPLY, -1);
}
}
+ private int resolveColor() {
+ if (mColor == COLOR_DEFAULT) {
+ mColor = mContext.getResources().getColor(R.color.notification_icon_bg_color);
+ } else {
+ mColor |= 0xFF000000; // no alpha for custom colors
+ }
+ return mColor;
+ }
+
/**
* Apply the unstyled operations and return a new {@link Notification} object.
* @hide
@@ -2102,6 +2154,9 @@
n.icon = mSmallIcon;
n.iconLevel = mSmallIconLevel;
n.number = mNumber;
+
+ n.color = resolveColor();
+
n.contentView = makeContentView();
n.contentIntent = mContentIntent;
n.deleteIntent = mDeleteIntent;
@@ -2207,45 +2262,31 @@
private int getBaseLayoutResource() {
- return mQuantumTheme
- ? R.layout.notification_template_quantum_base
- : R.layout.notification_template_base;
+ return R.layout.notification_template_quantum_base;
}
private int getBigBaseLayoutResource() {
- return mQuantumTheme
- ? R.layout.notification_template_quantum_big_base
- : R.layout.notification_template_big_base;
+ return R.layout.notification_template_quantum_big_base;
}
private int getBigPictureLayoutResource() {
- return mQuantumTheme
- ? R.layout.notification_template_quantum_big_picture
- : R.layout.notification_template_big_picture;
+ return R.layout.notification_template_quantum_big_picture;
}
private int getBigTextLayoutResource() {
- return mQuantumTheme
- ? R.layout.notification_template_quantum_big_text
- : R.layout.notification_template_big_text;
+ return R.layout.notification_template_quantum_big_text;
}
private int getInboxLayoutResource() {
- return mQuantumTheme
- ? R.layout.notification_template_quantum_inbox
- : R.layout.notification_template_inbox;
+ return R.layout.notification_template_quantum_inbox;
}
private int getActionLayoutResource() {
- return mQuantumTheme
- ? R.layout.notification_quantum_action
- : R.layout.notification_action;
+ return R.layout.notification_quantum_action;
}
private int getActionTombstoneLayoutResource() {
- return mQuantumTheme
- ? R.layout.notification_quantum_action_tombstone
- : R.layout.notification_action_tombstone;
+ return R.layout.notification_quantum_action_tombstone;
}
}
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 5cf61a8..ce5306f 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -60,6 +60,7 @@
| DISABLE_SEARCH;
public static final int NAVIGATION_HINT_BACK_ALT = 1 << 0;
+ public static final int NAVIGATION_HINT_IME_SHOWN = 1 << 1;
public static final int WINDOW_STATUS_BAR = 1;
public static final int WINDOW_NAVIGATION_BAR = 2;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 6f68dfb..61ff60a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -22,6 +22,7 @@
import android.annotation.SdkConstant.SdkConstantType;
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.PackageManager;
@@ -173,12 +174,12 @@
public static final String ACTION_SET_NEW_PASSWORD
= "android.app.action.SET_NEW_PASSWORD";
/**
- * Flag for {@link #forwardMatchingIntents}: the intents will forwarded to the primary user.
+ * Flag for {@link #addForwardingIntentFilter}: the intents will forwarded to the primary user.
*/
public static int FLAG_TO_PRIMARY_USER = 0x0001;
/**
- * Flag for {@link #forwardMatchingIntents}: the intents will be forwarded to the managed
+ * Flag for {@link #addForwardingIntentFilter}: the intents will be forwarded to the managed
* profile.
*/
public static int FLAG_TO_MANAGED_PROFILE = 0x0002;
@@ -1949,10 +1950,10 @@
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param filter if an intent matches this IntentFilter, then it can be forwarded.
*/
- public void forwardMatchingIntents(ComponentName admin, IntentFilter filter, int flags) {
+ public void addForwardingIntentFilter(ComponentName admin, IntentFilter filter, int flags) {
if (mService != null) {
try {
- mService.forwardMatchingIntents(admin, filter, flags);
+ mService.addForwardingIntentFilter(admin, filter, flags);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1960,7 +1961,7 @@
}
/**
- * Called by a profile owner to remove all the forwarding intent filters from the current user
+ * Called by a profile owner to remove the forwarding intent filters from the current user
* and from the owner.
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
*/
@@ -2041,4 +2042,87 @@
}
}
}
+
+ /**
+ * Called by profile or device owner to re-enable a system app that was 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.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param packageName The package to be re-enabled in the current profile.
+ */
+ public void enableSystemApp(ComponentName admin, String packageName) {
+ if (mService != null) {
+ try {
+ mService.enableSystemApp(admin, packageName);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to install package: " + packageName);
+ }
+ }
+ }
+
+ /**
+ * 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.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param intent An intent matching the app(s) to be installed. All apps that resolve for this
+ * intent will be re-enabled in the current profile.
+ * @return int The number of activities that matched the intent and were installed.
+ */
+ public int enableSystemApp(ComponentName admin, Intent intent) {
+ if (mService != null) {
+ try {
+ return mService.enableSystemAppWithIntent(admin, intent);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to install packages matching filter: " + intent);
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Gets the array of accounts for which account management is disabled by the profile owner.
+ *
+ * <p> Account management can be disabled/enabled by calling
+ * {@link #setAccountManagementDisabled}.
+ *
+ * @return a list of account types for which account management has been disabled.
+ *
+ * @see #setAccountManagementDisabled
+ */
+ public String[] getAccountTypesWithManagementDisabled() {
+ if (mService != null) {
+ try {
+ return mService.getAccountTypesWithManagementDisabled();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+
+ return null;
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 495a5f9..0096580 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -18,6 +18,7 @@
package android.app.admin;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.RemoteCallback;
@@ -120,6 +121,12 @@
Bundle getApplicationRestrictions(in ComponentName who, in String packageName);
void setUserRestriction(in ComponentName who, in String key, boolean enable);
- void forwardMatchingIntents(in ComponentName admin, in IntentFilter filter, int flags);
+ void addForwardingIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
void clearForwardingIntentFilters(in ComponentName admin);
+
+ void enableSystemApp(in ComponentName admin, in String packageName);
+ int enableSystemAppWithIntent(in ComponentName admin, in Intent intent);
+
+ void setAccountManagementDisabled(in ComponentName who, in String accountType, in boolean disabled);
+ String[] getAccountTypesWithManagementDisabled();
}
diff --git a/core/java/android/app/task/ITaskCallback.aidl b/core/java/android/app/task/ITaskCallback.aidl
new file mode 100644
index 0000000..ffa57d1
--- /dev/null
+++ b/core/java/android/app/task/ITaskCallback.aidl
@@ -0,0 +1,53 @@
+/**
+ * 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.app.task;
+
+import android.app.task.ITaskService;
+import android.app.task.TaskParams;
+
+/**
+ * The server side of the TaskManager IPC protocols. The app-side implementation
+ * invokes on this interface to indicate completion of the (asynchronous) instructions
+ * issued by the server.
+ *
+ * In all cases, the 'who' parameter is the caller's service binder, used to track
+ * which Task Service instance is reporting.
+ *
+ * {@hide}
+ */
+interface ITaskCallback {
+ /**
+ * Immediate callback to the system after sending a start signal, used to quickly detect ANR.
+ *
+ * @param taskId Unique integer used to identify this task.
+ */
+ void acknowledgeStartMessage(int taskId);
+ /**
+ * Immediate callback to the system after sending a stop signal, used to quickly detect ANR.
+ *
+ * @param taskId Unique integer used to identify this task.
+ */
+ void acknowledgeStopMessage(int taskId);
+ /*
+ * Tell the task manager that the client is done with its execution, so that it can go on to
+ * the next one and stop attributing wakelock time to us etc.
+ *
+ * @param taskId Unique integer used to identify this task.
+ * @param reschedule Whether or not to reschedule this task.
+ */
+ void taskFinished(int taskId, boolean reschedule);
+}
diff --git a/core/java/android/app/task/ITaskService.aidl b/core/java/android/app/task/ITaskService.aidl
new file mode 100644
index 0000000..87b0191
--- /dev/null
+++ b/core/java/android/app/task/ITaskService.aidl
@@ -0,0 +1,35 @@
+/**
+ * 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.app.task;
+
+import android.app.task.ITaskCallback;
+import android.app.task.TaskParams;
+
+import android.os.Bundle;
+
+/**
+ * Interface that the framework uses to communicate with application code that implements a
+ * TaskService. End user code does not implement this interface directly; instead, the app's
+ * service implementation will extend android.app.task.TaskService.
+ * {@hide}
+ */
+oneway interface ITaskService {
+ /** Begin execution of application's task. */
+ void startTask(in TaskParams taskParams);
+ /** Stop execution of application's task. */
+ void stopTask(in TaskParams taskParams);
+}
diff --git a/core/res/res/drawable/stat_sys_adb.xml b/core/java/android/app/task/TaskParams.aidl
similarity index 67%
rename from core/res/res/drawable/stat_sys_adb.xml
rename to core/java/android/app/task/TaskParams.aidl
index dfc8563..9b25855 100644
--- a/core/res/res/drawable/stat_sys_adb.xml
+++ b/core/java/android/app/task/TaskParams.aidl
@@ -1,7 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 2013, The Android Open Source Project
+/**
+ * Copyright 2014, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,9 +13,7 @@
* 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/stat_sys_adb_am"
- android:autoMirrored="true">
-</bitmap>
+package android.app.task;
+
+parcelable TaskParams;
\ No newline at end of file
diff --git a/core/java/android/app/task/TaskParams.java b/core/java/android/app/task/TaskParams.java
new file mode 100644
index 0000000..e2eafd8
--- /dev/null
+++ b/core/java/android/app/task/TaskParams.java
@@ -0,0 +1,86 @@
+/*
+ * 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.task;
+
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Contains the parameters used to configure/identify your task. You do not create this object
+ * yourself, instead it is handed in to your application by the System.
+ */
+public class TaskParams implements Parcelable {
+
+ private final int taskId;
+ private final Bundle extras;
+ private final IBinder mCallback;
+
+ /**
+ * @return The unique id of this task, specified at creation time.
+ */
+ public int getTaskId() {
+ return taskId;
+ }
+
+ /**
+ * @return The extras you passed in when constructing this task with
+ * {@link android.content.Task.Builder#setExtras(android.os.Bundle)}. This will
+ * never be null. If you did not set any extras this will be an empty bundle.
+ */
+ public Bundle getExtras() {
+ return extras;
+ }
+
+ /**
+ * @hide
+ */
+ public ITaskCallback getCallback() {
+ return ITaskCallback.Stub.asInterface(mCallback);
+ }
+
+ private TaskParams(Parcel in) {
+ taskId = in.readInt();
+ extras = in.readBundle();
+ mCallback = in.readStrongBinder();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(taskId);
+ dest.writeBundle(extras);
+ dest.writeStrongBinder(mCallback);
+ }
+
+ public static final Creator<TaskParams> CREATOR = new Creator<TaskParams>() {
+ @Override
+ public TaskParams createFromParcel(Parcel in) {
+ return new TaskParams(in);
+ }
+
+ @Override
+ public TaskParams[] newArray(int size) {
+ return new TaskParams[size];
+ }
+ };
+}
diff --git a/core/java/android/app/task/TaskService.java b/core/java/android/app/task/TaskService.java
new file mode 100644
index 0000000..81333be
--- /dev/null
+++ b/core/java/android/app/task/TaskService.java
@@ -0,0 +1,260 @@
+/*
+ * 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.task;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * <p>Entry point for the callback from the {@link android.content.TaskManager}.</p>
+ * <p>This is the base class that handles asynchronous requests that were previously scheduled. You
+ * are responsible for overriding {@link TaskService#onStartTask(TaskParams)}, which is where
+ * you will implement your task logic.</p>
+ * <p>This service executes each incoming task on a {@link android.os.Handler} running on your
+ * application's main thread. This means that you <b>must</b> offload your execution logic to
+ * another thread/handler/{@link android.os.AsyncTask} of your choosing. Not doing so will result
+ * in blocking any future callbacks from the TaskManager - specifically
+ * {@link #onStopTask(android.app.task.TaskParams)}, which is meant to inform you that the
+ * scheduling requirements are no longer being met.</p>
+ */
+public abstract class TaskService extends Service {
+ private static final String TAG = "TaskService";
+
+ /**
+ * Task services must be protected with this permission:
+ *
+ * <pre class="prettyprint">
+ * <service android:name="MyTaskService"
+ * android:permission="android.permission.BIND_TASK_SERVICE" >
+ * ...
+ * </service>
+ * </pre>
+ *
+ * <p>If a task service is declared in the manifest but not protected with this
+ * permission, that service will be ignored by the OS.
+ */
+ public static final String PERMISSION_BIND =
+ "android.permission.BIND_TASK_SERVICE";
+
+ /**
+ * Identifier for a message that will result in a call to
+ * {@link #onStartTask(android.app.task.TaskParams)}.
+ */
+ private final int MSG_EXECUTE_TASK = 0;
+ /**
+ * Message that will result in a call to {@link #onStopTask(android.app.task.TaskParams)}.
+ */
+ private final int MSG_STOP_TASK = 1;
+ /**
+ * Message that the client has completed execution of this task.
+ */
+ private final int MSG_TASK_FINISHED = 2;
+
+ /** Lock object for {@link #mHandler}. */
+ private final Object mHandlerLock = new Object();
+
+ /**
+ * Handler we post tasks to. Responsible for calling into the client logic, and handling the
+ * callback to the system.
+ */
+ @GuardedBy("mHandlerLock")
+ TaskHandler mHandler;
+
+ /** Binder for this service. */
+ ITaskService mBinder = new ITaskService.Stub() {
+ @Override
+ public void startTask(TaskParams taskParams) {
+ ensureHandler();
+ Message m = Message.obtain(mHandler, MSG_EXECUTE_TASK, taskParams);
+ m.sendToTarget();
+ }
+ @Override
+ public void stopTask(TaskParams taskParams) {
+ ensureHandler();
+ Message m = Message.obtain(mHandler, MSG_STOP_TASK, taskParams);
+ m.sendToTarget();
+ }
+ };
+
+ /** @hide */
+ void ensureHandler() {
+ synchronized (mHandlerLock) {
+ if (mHandler == null) {
+ mHandler = new TaskHandler(getMainLooper());
+ }
+ }
+ }
+
+ /**
+ * Runs on application's main thread - callbacks are meant to offboard work to some other
+ * (app-specified) mechanism.
+ * @hide
+ */
+ class TaskHandler extends Handler {
+ TaskHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ final TaskParams params = (TaskParams) msg.obj;
+ switch (msg.what) {
+ case MSG_EXECUTE_TASK:
+ try {
+ TaskService.this.onStartTask(params);
+ } catch (Exception e) {
+ Log.e(TAG, "Error while executing task: " + params.getTaskId());
+ throw new RuntimeException(e);
+ } finally {
+ maybeAckMessageReceived(params, MSG_EXECUTE_TASK);
+ }
+ break;
+ case MSG_STOP_TASK:
+ try {
+ TaskService.this.onStopTask(params);
+ } catch (Exception e) {
+ Log.e(TAG, "Application unable to handle onStopTask.", e);
+ throw new RuntimeException(e);
+ } finally {
+ maybeAckMessageReceived(params, MSG_STOP_TASK);
+ }
+ break;
+ case MSG_TASK_FINISHED:
+ final boolean needsReschedule = (msg.arg2 == 1);
+ ITaskCallback callback = params.getCallback();
+ if (callback != null) {
+ try {
+ callback.taskFinished(params.getTaskId(), needsReschedule);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error reporting task finish to system: binder has gone" +
+ "away.");
+ }
+ } else {
+ Log.e(TAG, "finishTask() called for a nonexistent task id.");
+ }
+ break;
+ default:
+ Log.e(TAG, "Unrecognised message received.");
+ break;
+ }
+ }
+
+ /**
+ * Messages come in on the application's main thread, so rather than run the risk of
+ * waiting for an app that may be doing something foolhardy, we ack to the system after
+ * processing a message. This allows us to throw up an ANR dialogue as quickly as possible.
+ * @param params id of the task we're acking.
+ * @param state Information about what message we're acking.
+ */
+ private void maybeAckMessageReceived(TaskParams params, int state) {
+ final ITaskCallback callback = params.getCallback();
+ final int taskId = params.getTaskId();
+ if (callback != null) {
+ try {
+ if (state == MSG_EXECUTE_TASK) {
+ callback.acknowledgeStartMessage(taskId);
+ } else if (state == MSG_STOP_TASK) {
+ callback.acknowledgeStopMessage(taskId);
+ }
+ } catch(RemoteException e) {
+ Log.e(TAG, "System unreachable for starting task.");
+ }
+ } else {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, state + ": Attempting to ack a task that has already been" +
+ "processed.");
+ }
+ }
+ }
+ }
+
+ /** @hide */
+ public final IBinder onBind(Intent intent) {
+ return mBinder.asBinder();
+ }
+
+ /**
+ * Override this method with the callback logic for your task. Any such logic needs to be
+ * performed on a separate thread, as this function is executed on your application's main
+ * thread.
+ *
+ * @param params Parameters specifying info about this task, including the extras bundle you
+ * optionally provided at task-creation time.
+ */
+ public abstract void onStartTask(TaskParams params);
+
+ /**
+ * This method is called if your task should be stopped even before you've called
+ * {@link #taskFinished(TaskParams, boolean)}.
+ *
+ * <p>This will happen if the requirements specified at schedule time are no longer met. For
+ * example you may have requested WiFi with
+ * {@link android.content.Task.Builder#setRequiredNetworkCapabilities(int)}, yet while your
+ * task was executing the user toggled WiFi. Another example is if you had specified
+ * {@link android.content.Task.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
+ * idle maintenance window. You are solely responsible for the behaviour of your application
+ * upon receipt of this message; your app will likely start to misbehave if you ignore it. One
+ * repercussion is that the system will cease to hold a wakelock for you.</p>
+ *
+ * <p>After you've done your clean-up you are still expected to call
+ * {@link #taskFinished(TaskParams, boolean)} this will inform the TaskManager that all is well, and
+ * allow you to reschedule your task as it is probably uncompleted. Until you call
+ * taskFinished() you will not receive any newly scheduled tasks with the given task id as the
+ * TaskManager will consider the task to be in an error state.</p>
+ *
+ * @param params Parameters specifying info about this task.
+ * @return True to indicate to the TaskManager whether you'd like to reschedule this task based
+ * on the criteria provided at task creation-time. False to drop the task. Regardless of the
+ * value returned, your task must stop executing.
+ */
+ public abstract boolean onStopTask(TaskParams params);
+
+ /**
+ * Callback to inform the TaskManager you have completed execution. This can be called from any
+ * thread, as it will ultimately be run on your application's main thread. When the system
+ * receives this message it will release the wakelock being held.
+ * <p>
+ * You can specify post-execution behaviour to the scheduler here with <code>needsReschedule
+ * </code>. This will apply a back-off timer to your task based on the default, or what was
+ * set with {@link android.content.Task.Builder#setBackoffCriteria(long, int)}. The
+ * original requirements are always honoured even for a backed-off task.
+ * Note that a task running in idle mode will not be backed-off. Instead what will happen
+ * is the task will be re-added to the queue and re-executed within a future idle
+ * maintenance window.
+ * </p>
+ *
+ * @param params Parameters specifying system-provided info about this task, this was given to
+ * your application in {@link #onStartTask(TaskParams)}.
+ * @param needsReschedule True if this task is complete, false if you want the TaskManager to
+ * reschedule you.
+ */
+ public final void taskFinished(TaskParams params, boolean needsReschedule) {
+ ensureHandler();
+ Message m = Message.obtain(mHandler, MSG_TASK_FINISHED, params);
+ m.arg2 = needsReschedule ? 1 : 0;
+ m.sendToTarget();
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index dd3a871..d3e9089 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -181,7 +181,8 @@
* A bundle extra that hints to the AppWidgetProvider the category of host that owns this
* this widget. Can have the value {@link
* AppWidgetProviderInfo#WIDGET_CATEGORY_HOME_SCREEN} or {@link
- * AppWidgetProviderInfo#WIDGET_CATEGORY_KEYGUARD}.
+ * AppWidgetProviderInfo#WIDGET_CATEGORY_KEYGUARD} or {@link
+ * AppWidgetProviderInfo#WIDGET_CATEGORY_RECENTS}.
*/
public static final String OPTION_APPWIDGET_HOST_CATEGORY = "appWidgetCategory";
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 4b33799..8b9c7f0f 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -54,6 +54,11 @@
public static final int WIDGET_CATEGORY_KEYGUARD = 2;
/**
+ * Indicates that the widget can be displayed within recents.
+ */
+ public static final int WIDGET_CATEGORY_RECENTS = 4;
+
+ /**
* Identity of this AppWidget component. This component should be a {@link
* android.content.BroadcastReceiver}, and it will be sent the AppWidget intents
* {@link android.appwidget as described in the AppWidget package documentation}.
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index a396a05..7f8d0ab 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -512,6 +512,25 @@
*/
public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
+ /**
+ * No preferrence of physical transport for GATT connections to remote dual-mode devices
+ * @hide
+ */
+ public static final int TRANSPORT_AUTO = 0;
+
+ /**
+ * Prefer BR/EDR transport for GATT connections to remote dual-mode devices
+ * @hide
+ */
+ public static final int TRANSPORT_BREDR = 1;
+
+ /**
+ * Prefer LE transport for GATT connections to remote dual-mode devices
+ * @hide
+ */
+ public static final int TRANSPORT_LE = 2;
+
+
/**
* Lazy initialization. Guaranteed final after first object constructed, or
* getService() called.
@@ -1216,6 +1235,27 @@
*/
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback) {
+ return (connectGatt(context, autoConnect,callback, TRANSPORT_AUTO));
+ }
+
+ /**
+ * Connect to GATT Server hosted by this device. Caller acts as GATT client.
+ * The callback is used to deliver results to Caller, such as connection status as well
+ * as any further GATT client operations.
+ * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
+ * GATT client operations.
+ * @param callback GATT callback handler that will receive asynchronous callbacks.
+ * @param autoConnect Whether to directly connect to the remote device (false)
+ * or to automatically connect as soon as the remote
+ * device becomes available (true).
+ * @param transport preferred transport for GATT connections to remote dual-mode devices
+ * {@link BluetoothDevice#TRANSPORT_AUTO} or
+ * {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
+ * @throws IllegalArgumentException if callback is null
+ * @hide
+ */
+ public BluetoothGatt connectGatt(Context context, boolean autoConnect,
+ BluetoothGattCallback callback, int transport) {
// TODO(Bluetooth) check whether platform support BLE
// Do the check here or in GattServer?
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -1226,10 +1266,11 @@
// BLE is not supported
return null;
}
- BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this);
+ BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this, transport);
gatt.connect(autoConnect, callback);
return gatt;
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
+
}
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index ff3af7c..601d9ee 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -51,6 +51,7 @@
private int mConnState;
private final Object mStateLock = new Object();
private Boolean mDeviceBusy = false;
+ private int mTransport;
private static final int CONN_STATE_IDLE = 0;
private static final int CONN_STATE_CONNECTING = 1;
@@ -135,7 +136,7 @@
}
try {
mService.clientConnect(mClientIf, mDevice.getAddress(),
- !mAutoConnect); // autoConnect is inverse of "isDirect"
+ !mAutoConnect, mTransport); // autoConnect is inverse of "isDirect"
} catch (RemoteException e) {
Log.e(TAG,"",e);
}
@@ -600,10 +601,12 @@
}
};
- /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device) {
+ /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device,
+ int transport) {
mContext = context;
mService = iGatt;
mDevice = device;
+ mTransport = transport;
mServices = new ArrayList<BluetoothGattService>();
mConnState = CONN_STATE_IDLE;
@@ -759,7 +762,7 @@
public boolean connect() {
try {
mService.clientConnect(mClientIf, mDevice.getAddress(),
- false); // autoConnect is inverse of "isDirect"
+ false, mTransport); // autoConnect is inverse of "isDirect"
return true;
} catch (RemoteException e) {
Log.e(TAG,"",e);
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 0c00c06..34e8605 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -50,6 +50,7 @@
private Object mServerIfLock = new Object();
private int mServerIf;
+ private int mTransport;
private List<BluetoothGattService> mServices;
private static final int CALLBACK_REG_TIMEOUT = 10000;
@@ -269,12 +270,13 @@
/**
* Create a BluetoothGattServer proxy object.
*/
- /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt) {
+ /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt, int transport) {
mContext = context;
mService = iGatt;
mAdapter = BluetoothAdapter.getDefaultAdapter();
mCallback = null;
mServerIf = 0;
+ mTransport = transport;
mServices = new ArrayList<BluetoothGattService>();
}
@@ -401,7 +403,7 @@
try {
mService.serverConnect(mServerIf, device.getAddress(),
- autoConnect ? false : true); // autoConnect is inverse of "isDirect"
+ autoConnect ? false : true,mTransport); // autoConnect is inverse of "isDirect"
} catch (RemoteException e) {
Log.e(TAG,"",e);
return false;
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 172f3bc..b1618cf3 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -194,6 +194,26 @@
*/
public BluetoothGattServer openGattServer(Context context,
BluetoothGattServerCallback callback) {
+
+ return (openGattServer (context, callback, BluetoothDevice.TRANSPORT_AUTO));
+ }
+
+ /**
+ * Open a GATT Server
+ * The callback is used to deliver results to Caller, such as connection status as well
+ * as the results of any other GATT server operations.
+ * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer
+ * to conduct GATT server operations.
+ * @param context App context
+ * @param callback GATT server callback handler that will receive asynchronous callbacks.
+ * @param transport preferred transport for GATT connections to remote dual-mode devices
+ * {@link BluetoothDevice#TRANSPORT_AUTO} or
+ * {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
+ * @return BluetoothGattServer instance
+ * @hide
+ */
+ public BluetoothGattServer openGattServer(Context context,
+ BluetoothGattServerCallback callback,int transport) {
if (context == null || callback == null) {
throw new IllegalArgumentException("null parameter: " + context + " " + callback);
}
@@ -208,7 +228,7 @@
Log.e(TAG, "Fail to get GATT Server connection");
return null;
}
- BluetoothGattServer mGattServer = new BluetoothGattServer(context, iGatt);
+ BluetoothGattServer mGattServer = new BluetoothGattServer(context, iGatt,transport);
Boolean regStatus = mGattServer.registerCallback(callback);
return regStatus? mGattServer : null;
} catch (RemoteException e) {
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index f532f7c..00fd7ce 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -325,6 +325,7 @@
}
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ throw new IOException("unable to send RPC: " + e.getMessage());
}
}
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index 6dd551e..a0b603e 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -53,6 +53,9 @@
private static final boolean DBG = true;
private static final boolean VDBG = true;
+ // Event sent to the mBtdtHandler when DHCP fails so we can tear down the network.
+ private static final int EVENT_NETWORK_FAILED = 1;
+
private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
@@ -315,6 +318,7 @@
}
if (!success) {
Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
+ mBtdtHandler.obtainMessage(EVENT_NETWORK_FAILED).sendToTarget();
return;
}
mLinkProperties = dhcpResults.linkProperties;
@@ -407,6 +411,10 @@
if (VDBG) Log.d(TAG, "got EVENT_NETWORK_DISCONNECTED, " + linkProperties);
mBtdt.stopReverseTether();
break;
+ case EVENT_NETWORK_FAILED:
+ if (VDBG) Log.d(TAG, "got EVENT_NETWORK_FAILED");
+ mBtdt.teardown();
+ break;
}
}
}
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 4b28516..ab53fb0 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -18,6 +18,8 @@
import android.os.ParcelUuid;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.HashSet;
import java.util.UUID;
@@ -76,6 +78,12 @@
public static final ParcelUuid BASE_UUID =
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
+ /** Length of bytes for 16 bit UUID */
+ public static final int UUID_BYTES_16_BIT = 2;
+ /** Length of bytes for 32 bit UUID */
+ public static final int UUID_BYTES_32_BIT = 4;
+ /** Length of bytes for 128 bit UUID */
+ public static final int UUID_BYTES_128_BIT = 16;
public static final ParcelUuid[] RESERVED_UUIDS = {
AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
@@ -216,15 +224,60 @@
}
/**
+ * Parse UUID from bytes. The {@code uuidBytes} can represent a 16-bit, 32-bit or 128-bit UUID,
+ * but the returned UUID is always in 128-bit format.
+ * Note UUID is little endian in Bluetooth.
+ *
+ * @param uuidBytes Byte representation of uuid.
+ * @return {@link ParcelUuid} parsed from bytes.
+ * @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed.
+ */
+ public static ParcelUuid parseUuidFrom(byte[] uuidBytes) {
+ if (uuidBytes == null) {
+ throw new IllegalArgumentException("uuidBytes cannot be null");
+ }
+ int length = uuidBytes.length;
+ if (length != UUID_BYTES_16_BIT && length != UUID_BYTES_32_BIT &&
+ length != UUID_BYTES_128_BIT) {
+ throw new IllegalArgumentException("uuidBytes length invalid - " + length);
+ }
+
+ // Construct a 128 bit UUID.
+ if (length == UUID_BYTES_128_BIT) {
+ ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN);
+ long msb = buf.getLong(8);
+ long lsb = buf.getLong(0);
+ return new ParcelUuid(new UUID(msb, lsb));
+ }
+
+ // For 16 bit and 32 bit UUID we need to convert them to 128 bit value.
+ // 128_bit_value = uuid * 2^96 + BASE_UUID
+ long shortUuid;
+ if (length == UUID_BYTES_16_BIT) {
+ shortUuid = uuidBytes[0] & 0xFF;
+ shortUuid += (uuidBytes[1] & 0xFF) << 8;
+ } else {
+ shortUuid = uuidBytes[0] & 0xFF ;
+ shortUuid += (uuidBytes[1] & 0xFF) << 8;
+ shortUuid += (uuidBytes[2] & 0xFF) << 16;
+ shortUuid += (uuidBytes[3] & 0xFF) << 24;
+ }
+ long msb = BASE_UUID.getUuid().getMostSignificantBits() + (shortUuid << 32);
+ long lsb = BASE_UUID.getUuid().getLeastSignificantBits();
+ return new ParcelUuid(new UUID(msb, lsb));
+ }
+
+ /**
* Check whether the given parcelUuid can be converted to 16 bit bluetooth uuid.
+ *
* @param parcelUuid
* @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise.
*/
public static boolean isShortUuid(ParcelUuid parcelUuid) {
- UUID uuid = parcelUuid.getUuid();
- if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
- return false;
- }
- return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L);
+ UUID uuid = parcelUuid.getUuid();
+ if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
+ return false;
+ }
+ return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L);
}
}
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index c6b5c3d..49b156d 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -35,7 +35,7 @@
void registerClient(in ParcelUuid appId, in IBluetoothGattCallback callback);
void unregisterClient(in int clientIf);
- void clientConnect(in int clientIf, in String address, in boolean isDirect);
+ void clientConnect(in int clientIf, in String address, in boolean isDirect, in int transport);
void clientDisconnect(in int clientIf, in String address);
void startAdvertising(in int appIf);
void stopAdvertising();
@@ -77,7 +77,7 @@
void registerServer(in ParcelUuid appId, in IBluetoothGattServerCallback callback);
void unregisterServer(in int serverIf);
- void serverConnect(in int servertIf, in String address, in boolean isDirect);
+ void serverConnect(in int servertIf, in String address, in boolean isDirect, in int transport);
void serverDisconnect(in int serverIf, in String address);
void beginServiceDeclaration(in int serverIf, in int srvcType,
in int srvcInstanceId, in int minHandles,
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index de223a3..042ee28 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1982,6 +1982,7 @@
WIFI_SERVICE,
WIFI_HOTSPOT_SERVICE,
WIFI_P2P_SERVICE,
+ WIFI_SCANNING_SERVICE,
NSD_SERVICE,
AUDIO_SERVICE,
MEDIA_ROUTER_SERVICE,
@@ -2054,6 +2055,9 @@
* <dt> {@link #WIFI_SERVICE} ("wifi")
* <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of
* Wi-Fi connectivity.
+ * <dt> {@link #WIFI_P2P_SERVICE} ("wifip2p")
+ * <dd> A {@link android.net.wifi.p2p.WifiP2pManager WifiP2pManager} for management of
+ * Wi-Fi Direct connectivity.
* <dt> {@link #INPUT_METHOD_SERVICE} ("input_method")
* <dd> An {@link android.view.inputmethod.InputMethodManager InputMethodManager}
* for management of input methods.
@@ -2357,6 +2361,16 @@
/**
* Use with {@link #getSystemService} to retrieve a {@link
+ * android.net.wifi.WifiScanner} for scanning the wifi universe
+ *
+ * @see #getSystemService
+ * @see android.net.wifi.WifiScanner
+ * @hide
+ */
+ public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a {@link
* android.net.nsd.NsdManager} for handling management of network service
* discovery
*
@@ -2377,6 +2391,16 @@
/**
* Use with {@link #getSystemService} to retrieve a
+ * {@link android.service.fingerprint.FingerprintManager} for handling management
+ * of fingerprints.
+ *
+ * @see #getSystemService
+ * @see android.app.FingerprintManager
+ */
+ public static final String FINGERPRINT_SERVICE = "fingerprint";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
* {@link android.media.MediaRouter} for controlling and managing
* routing of media.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index ae5437b..3cfc56c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3736,7 +3736,8 @@
*
* <p>When set, the activity specified by this Intent will launch into a
* separate task rooted at that activity. The activity launched must be
- * defined with {@link android.R.attr#launchMode} "standard" or "singleTop".
+ * defined with {@link android.R.attr#launchMode} <code>standard</code>
+ * or <code>singleTop</code>.
*
* <p>If FLAG_ACTIVITY_NEW_DOCUMENT is used without
* {@link #FLAG_ACTIVITY_MULTIPLE_TASK} then the activity manager will
@@ -3751,6 +3752,8 @@
* always create a new task. Thus the same document may be made to appear
* more than one time in Recents.
*
+ * <p>This is equivalent to the attribute {@link android.R.attr#documentLaunchMode}.
+ *
* @see #FLAG_ACTIVITY_MULTIPLE_TASK
*/
public static final int FLAG_ACTIVITY_NEW_DOCUMENT =
@@ -3815,6 +3818,15 @@
*/
public static final int FLAG_ACTIVITY_TASK_ON_HOME = 0X00004000;
/**
+ * If set and the new activity is the root of a new task, then the task
+ * will remain in the list of recently launched tasks only until all of
+ * the activities in it are finished.
+ *
+ * <p>This is equivalent to the attribute
+ * {@link android.R.styleable#AndroidManifestActivity_autoRemoveFromRecents}.
+ */
+ public static final int FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS = 0x00002000;
+ /**
* If set, when sending a broadcast only registered receivers will be
* called -- no BroadcastReceiver components will be launched.
*/
@@ -4019,7 +4031,7 @@
/**
* Create an intent for a specific component with a specified action and data.
- * This is equivalent using {@link #Intent(String, android.net.Uri)} to
+ * This is equivalent to using {@link #Intent(String, android.net.Uri)} to
* construct the Intent and then calling {@link #setClass} to set its
* class.
*
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
index a9a62a7..9ba45ca 100644
--- a/core/java/android/content/SyncRequest.java
+++ b/core/java/android/content/SyncRequest.java
@@ -473,7 +473,7 @@
* SyncRequest.Builder builder =
* new SyncRequest.Builder()
* .setSyncAdapter(dummyAccount, dummyProvider)
- * .syncOnce(5 * MINUTES_IN_SECS);
+ * .syncOnce();
*
* for (String syncData : syncItems) {
* Bundle extras = new Bundle();
diff --git a/core/java/android/content/Task.java b/core/java/android/content/Task.java
new file mode 100644
index 0000000..ed5ed884
--- /dev/null
+++ b/core/java/android/content/Task.java
@@ -0,0 +1,400 @@
+/*
+ * 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;
+
+import android.app.task.TaskService;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Container of data passed to the {@link android.content.TaskManager} fully encapsulating the
+ * parameters required to schedule work against the calling application. These are constructed
+ * using the {@link Task.Builder}.
+ */
+public class Task implements Parcelable {
+
+ public interface NetworkType {
+ public final int ANY = 0;
+ public final int UNMETERED = 1;
+ }
+
+ /**
+ * Linear: retry_time(failure_time, t) = failure_time + initial_retry_delay * t, t >= 1
+ * Expon: retry_time(failure_time, t) = failure_time + initial_retry_delay ^ t, t >= 1
+ */
+ public interface BackoffPolicy {
+ public final int LINEAR = 0;
+ public final int EXPONENTIAL = 1;
+ }
+
+ /**
+ * Unique task id associated with this class. This is assigned to your task by the scheduler.
+ */
+ public int getTaskId() {
+ return taskId;
+ }
+
+ /**
+ * Bundle of extras which are returned to your application at execution time.
+ */
+ public Bundle getExtras() {
+ return extras;
+ }
+
+ /**
+ * Name of the service endpoint that will be called back into by the TaskManager.
+ */
+ public String getServiceClassName() {
+ return serviceClassName;
+ }
+
+ /**
+ * Whether this task needs the device to be plugged in.
+ */
+ public boolean isRequireCharging() {
+ return requireCharging;
+ }
+
+ /**
+ * Whether this task needs the device to be in an Idle maintenance window.
+ */
+ public boolean isRequireDeviceIdle() {
+ return requireDeviceIdle;
+ }
+
+ /**
+ * See {@link android.content.Task.NetworkType} for a description of this value.
+ */
+ public int getNetworkCapabilities() {
+ return networkCapabilities;
+ }
+
+ /**
+ * Set for a task that does not recur periodically, to specify a delay after which the task
+ * will be eligible for execution. This value is not set if the task recurs periodically.
+ */
+ public long getMinLatencyMillis() {
+ return minLatencyMillis;
+ }
+
+ /**
+ * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the task recurs
+ * periodically.
+ */
+ public long getMaxExecutionDelayMillis() {
+ return maxExecutionDelayMillis;
+ }
+
+ /**
+ * Track whether this task will repeat with a given period.
+ */
+ public boolean isPeriodic() {
+ return isPeriodic;
+ }
+
+ /**
+ * Set to the interval between occurrences of this task. This value is <b>not</b> set if the
+ * task does not recur periodically.
+ */
+ public long getIntervalMillis() {
+ return intervalMillis;
+ }
+
+ /**
+ * The amount of time the TaskManager will wait before rescheduling a failed task. This value
+ * will be increased depending on the backoff policy specified at task creation time. Defaults
+ * to 5 seconds.
+ */
+ public long getInitialBackoffMillis() {
+ return initialBackoffMillis;
+ }
+
+ /**
+ * See {@link android.content.Task.BackoffPolicy} for an explanation of the values this field
+ * can take. This defaults to exponential.
+ */
+ public int getBackoffPolicy() {
+ 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();
+ requireCharging = in.readInt() == 1;
+ requireDeviceIdle = in.readInt() == 1;
+ networkCapabilities = in.readInt();
+ minLatencyMillis = in.readLong();
+ maxExecutionDelayMillis = in.readLong();
+ isPeriodic = in.readInt() == 1;
+ intervalMillis = in.readLong();
+ initialBackoffMillis = in.readLong();
+ backoffPolicy = in.readInt();
+ }
+
+ private Task(Task.Builder b) {
+ taskId = b.mTaskId;
+ extras = new Bundle(b.mExtras);
+ serviceClassName = b.mTaskServiceClassName;
+ requireCharging = b.mRequiresCharging;
+ requireDeviceIdle = b.mRequiresDeviceIdle;
+ networkCapabilities = b.mNetworkCapabilities;
+ minLatencyMillis = b.mMinLatencyMillis;
+ maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
+ isPeriodic = b.mIsPeriodic;
+ intervalMillis = b.mIntervalMillis;
+ initialBackoffMillis = b.mInitialBackoffMillis;
+ backoffPolicy = b.mBackoffPolicy;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(taskId);
+ out.writeBundle(extras);
+ out.writeString(serviceClassName);
+ out.writeInt(requireCharging ? 1 : 0);
+ out.writeInt(requireDeviceIdle ? 1 : 0);
+ out.writeInt(networkCapabilities);
+ out.writeLong(minLatencyMillis);
+ out.writeLong(maxExecutionDelayMillis);
+ out.writeInt(isPeriodic ? 1 : 0);
+ out.writeLong(intervalMillis);
+ out.writeLong(initialBackoffMillis);
+ out.writeInt(backoffPolicy);
+ }
+
+ public static final Creator<Task> CREATOR = new Creator<Task>() {
+ @Override
+ public Task createFromParcel(Parcel in) {
+ return new Task(in);
+ }
+
+ @Override
+ public Task[] newArray(int size) {
+ return new Task[size];
+ }
+ };
+
+ /**
+ * Builder class for constructing {@link Task} objects.
+ */
+ public final class Builder {
+ private int mTaskId;
+ private Bundle mExtras;
+ private String mTaskServiceClassName;
+ // Requirements.
+ private boolean mRequiresCharging;
+ private boolean mRequiresDeviceIdle;
+ private int mNetworkCapabilities;
+ // One-off parameters.
+ private long mMinLatencyMillis;
+ private long mMaxExecutionDelayMillis;
+ // Periodic parameters.
+ private boolean mIsPeriodic;
+ private long mIntervalMillis;
+ // Back-off parameters.
+ private long mInitialBackoffMillis = 5000L;
+ private int mBackoffPolicy = BackoffPolicy.EXPONENTIAL;
+ /** Easy way to track whether the client has tried to set a back-off policy. */
+ private boolean mBackoffPolicySet = false;
+
+ /**
+ * @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
+ * TaskManager.
+ */
+ public Builder(int taskId, Class<TaskService> cls) {
+ mTaskServiceClassName = cls.getClass().getName();
+ mTaskId = taskId;
+ }
+
+ /**
+ * Set optional extras. This is persisted, so we only allow primitive types.
+ * @param extras Bundle containing extras you want the scheduler to hold on to for you.
+ */
+ public Builder setExtras(Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /**
+ * Set some description of the kind of network capabilities you would like to have. This
+ * will be a parameter defined in {@link android.content.Task.NetworkType}.
+ * Not calling this function means the network is not necessary.
+ * Bear in mind that calling this function defines network as a strict requirement for your
+ * task if the network requested is not available your task will never run. See
+ * {@link #setOverrideDeadline(long)} to change this behaviour.
+ */
+ public Builder setRequiredNetworkCapabilities(int networkCapabilities) {
+ mNetworkCapabilities = networkCapabilities;
+ return this;
+ }
+
+ /*
+ * Specify that to run this task, the device needs to be plugged in. This defaults to
+ * false.
+ * @param requireCharging Whether or not the device is plugged in.
+ */
+ public Builder setRequiresCharging(boolean requiresCharging) {
+ mRequiresCharging = requiresCharging;
+ return this;
+ }
+
+ /**
+ * Specify that to run, the task needs the device to be in idle mode. This defaults to
+ * false.
+ * <p>Idle mode is a loose definition provided by the system, which means that the device
+ * is not in use, and has not been in use for some time. As such, it is a good time to
+ * perform resource heavy tasks. Bear in mind that battery usage will still be attributed
+ * to your application, and surfaced to the user in battery stats.</p>
+ * @param requiresDeviceIdle Whether or not the device need be within an idle maintenance
+ * window.
+ */
+ public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
+ mRequiresDeviceIdle = requiresDeviceIdle;
+ return this;
+ }
+
+ /**
+ * Specify that this task should recur with the provided interval, not more than once per
+ * 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
+ * {@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.
+ * Setting this function on the builder with {@link #setMinimumLatency(long)} or
+ * {@link #setOverrideDeadline(long)} will result in an error.
+ * @param intervalMillis Millisecond interval for which this task will repeat.
+ */
+ public Builder setPeriodic(long intervalMillis) {
+ mIsPeriodic = true;
+ mIntervalMillis = intervalMillis;
+ return this;
+ }
+
+ /**
+ * Specify that this task should be delayed by the provided amount of time.
+ * Because it doesn't make sense setting this property on a periodic task, doing so will
+ * throw an {@link java.lang.IllegalArgumentException} when
+ * {@link android.content.Task.Builder#build()} is called.
+ * @param minLatencyMillis Milliseconds before which this task will not be considered for
+ * execution.
+ */
+ public Builder setMinimumLatency(long minLatencyMillis) {
+ mMinLatencyMillis = minLatencyMillis;
+ return this;
+ }
+
+ /**
+ * Set deadline which is the maximum scheduling latency. The task will be run by this
+ * deadline even if other requirements are not met. Because it doesn't make sense setting
+ * this property on a periodic task, doing so will throw an
+ * {@link java.lang.IllegalArgumentException} when
+ * {@link android.content.Task.Builder#build()} is called.
+ */
+ public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
+ mMaxExecutionDelayMillis = maxExecutionDelayMillis;
+ return this;
+ }
+
+ /**
+ * Set up the back-off/retry policy.
+ * This defaults to some respectable values: {5 seconds, Exponential}. We cap back-off at
+ * 1hr.
+ * Note that trying to set a backoff criteria for a task with
+ * {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
+ * This is because back-off typically does not make sense for these types of tasks. See
+ * {@link android.app.task.TaskService#taskFinished(android.app.task.TaskParams, boolean)}
+ * for more description of the return value for the case of a task executing while in idle
+ * mode.
+ * @param initialBackoffMillis Millisecond time interval to wait initially when task has
+ * failed.
+ * @param backoffPolicy is one of {@link BackoffPolicy}
+ */
+ public Builder setBackoffCriteria(long initialBackoffMillis, int backoffPolicy) {
+ mBackoffPolicySet = true;
+ mInitialBackoffMillis = initialBackoffMillis;
+ mBackoffPolicy = backoffPolicy;
+ return this;
+ }
+
+ /**
+ * @return The task object to hand to the TaskManager. This object is immutable.
+ */
+ public Task build() {
+ // Check that extras bundle only contains primitive types.
+ try {
+ for (String key : extras.keySet()) {
+ Object value = extras.get(key);
+ if (value == null) continue;
+ if (value instanceof Long) continue;
+ if (value instanceof Integer) continue;
+ if (value instanceof Boolean) continue;
+ if (value instanceof Float) continue;
+ if (value instanceof Double) continue;
+ if (value instanceof String) continue;
+ throw new IllegalArgumentException("Unexpected value type: "
+ + value.getClass().getName());
+ }
+ } catch (IllegalArgumentException e) {
+ throw e;
+ } catch (RuntimeException exc) {
+ throw new IllegalArgumentException("error unparcelling Bundle", exc);
+ }
+ // Check that a deadline was not set on a periodic task.
+ if (mIsPeriodic && (mMaxExecutionDelayMillis != 0L)) {
+ throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +
+ "periodic task.");
+ }
+ if (mIsPeriodic && (mMinLatencyMillis != 0L)) {
+ throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
+ "periodic task");
+ }
+ if (mBackoffPolicySet && mRequiresDeviceIdle) {
+ throw new IllegalArgumentException("An idle mode task will not respect any" +
+ " back-off policy, so calling setBackoffCriteria with" +
+ " setRequiresDeviceIdle is an error.");
+ }
+ return new Task(this);
+ }
+ }
+
+}
diff --git a/core/java/android/content/TaskManager.java b/core/java/android/content/TaskManager.java
new file mode 100644
index 0000000..d28d78a
--- /dev/null
+++ b/core/java/android/content/TaskManager.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 android.content;
+
+import java.util.List;
+
+/**
+ * Class for scheduling various types of tasks with the scheduling framework on the device.
+ *
+ * Get an instance of this class through {@link Context#getSystemService(String)}.
+ */
+public abstract class TaskManager {
+ /*
+ * Returned from {@link #schedule(Task)} when an invalid parameter was supplied. This can occur
+ * if the run-time for your task is too short, or perhaps the system can't resolve the
+ * requisite {@link TaskService} in your package.
+ */
+ static final int RESULT_INVALID_PARAMETERS = -1;
+ /**
+ * Returned from {@link #schedule(Task)} if this application has made too many requests for
+ * work over too short a time.
+ */
+ // TODO: Determine if this is necessary.
+ static final int RESULT_OVER_QUOTA = -2;
+
+ /*
+ * @param task The task you wish scheduled. See {@link Task#TaskBuilder} for more detail on
+ * the sorts of tasks you can schedule.
+ * @return If >0, this int corresponds to the taskId of the successfully scheduled task.
+ * Otherwise you have to compare the return value to the error codes defined in this class.
+ */
+ public abstract int schedule(Task task);
+
+ /**
+ * Cancel a task that is pending in the TaskManager.
+ * @param taskId unique identifier for this task. Obtain this value from the tasks returned by
+ * {@link #getAllPendingTasks()}.
+ * @return
+ */
+ public abstract void cancel(int taskId);
+
+ /**
+ * Cancel all tasks that have been registered with the TaskManager by this package.
+ */
+ public abstract void cancelAll();
+
+ /**
+ * @return a list of all the tasks registered by this package that have not yet been executed.
+ */
+ public abstract List<Task> getAllPendingTasks();
+
+}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index c53e545..c2fe3a2 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -67,7 +67,37 @@
* {@link #LAUNCH_SINGLE_INSTANCE}.
*/
public int launchMode;
-
+
+ /**
+ * Constant corresponding to <code>none</code> in
+ * the {@link android.R.attr#documentLaunchMode} attribute.
+ */
+ public static final int DOCUMENT_LAUNCH_NONE = 0;
+ /**
+ * Constant corresponding to <code>intoExisting</code> in
+ * the {@link android.R.attr#documentLaunchMode} attribute.
+ */
+ public static final int DOCUMENT_LAUNCH_INTO_EXISTING = 1;
+ /**
+ * Constant corresponding to <code>always</code> in
+ * the {@link android.R.attr#documentLaunchMode} attribute.
+ */
+ public static final int DOCUMENT_LAUNCH_ALWAYS = 2;
+ /**
+ * The document launch mode style requested by the activity. From the
+ * {@link android.R.attr#documentLaunchMode} attribute, one of
+ * {@link #DOCUMENT_LAUNCH_NONE}, {@link #DOCUMENT_LAUNCH_INTO_EXISTING},
+ * {@link #DOCUMENT_LAUNCH_ALWAYS}.
+ *
+ * <p>Modes DOCUMENT_LAUNCH_ALWAYS
+ * and DOCUMENT_LAUNCH_INTO_EXISTING are equivalent to {@link
+ * android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT
+ * Intent.FLAG_ACTIVITY_NEW_DOCUMENT} with and without {@link
+ * android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+ * Intent.FLAG_ACTIVITY_MULTIPLE_TASK} respectively.
+ */
+ public int documentLaunchMode;
+
/**
* Optional name of a permission required to be able to access this
* Activity. From the "permission" attribute.
@@ -192,10 +222,15 @@
* Bit in {@link #flags} indicating that this activity is to be persisted across
* reboots for display in the Recents list.
* {@link android.R.attr#persistable}
- * @hide
*/
public static final int FLAG_PERSISTABLE = 0x1000;
/**
+ * Bit in {@link #flags} indicating that tasks started with this activity are to be
+ * removed from the recent list of tasks when the last activity in the task is finished.
+ * {@link android.R.attr#autoRemoveFromRecents}
+ */
+ public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 0x2000;
+ /**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the primary user. Only works with broadcast receivers. Set from the
* android.R.attr#primaryUserOnly attribute.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index cf9a296..03eb50f 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -247,7 +247,8 @@
void clearPackagePersistentPreferredActivities(String packageName, int userId);
- void addForwardingIntentFilter(in IntentFilter filter, int userIdOrig, int userIdDest);
+ void addForwardingIntentFilter(in IntentFilter filter, boolean removable, int userIdOrig,
+ int userIdDest);
void clearForwardingIntentFilters(int userIdOrig);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 484a2a1..52a169b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1083,6 +1083,13 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device includes a heart rate monitor.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device has a telephony radio with data
* communication support.
*/
@@ -3507,4 +3514,26 @@
return Environment.getDataDirectory().toString() + "/user/" + userId
+ "/" + packageName;
}
+
+ /**
+ * Adds a forwarding intent filter. After calling this method all intents sent from the user
+ * with id userIdOrig can also be be resolved by activities in the user with id userIdDest if
+ * they match the specified intent filter.
+ * @param filter the {@link IntentFilter} the intent has to match to be forwarded
+ * @param removable if set to false, {@link clearForwardingIntents} will not remove this intent
+ * filter
+ * @param userIdOrig user from which the intent can be forwarded
+ * @param userIdDest user to which the intent can be forwarded
+ * @hide
+ */
+ public abstract void addForwardingIntentFilter(IntentFilter filter, boolean removable,
+ int userIdOrig, int userIdDest);
+
+ /**
+ * Clearing all removable {@link ForwardingIntentFilter}s that are set with the given user as
+ * the origin.
+ * @param userIdOrig user from which the intent can be forwarded
+ * @hide
+ */
+ public abstract void clearForwardingIntentFilters(int userIdOrig);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 080b37b..ff96c51 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2462,17 +2462,6 @@
a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
}
- if (sa.getBoolean(
- com.android.internal.R.styleable.AndroidManifestActivity_persistable, false)) {
- a.info.flags |= ActivityInfo.FLAG_PERSISTABLE;
- }
-
- if (sa.getBoolean(
- com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
- false)) {
- a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
- }
-
if (!receiver) {
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
@@ -2483,6 +2472,9 @@
a.info.launchMode = sa.getInt(
com.android.internal.R.styleable.AndroidManifestActivity_launchMode,
ActivityInfo.LAUNCH_MULTIPLE);
+ a.info.documentLaunchMode = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestActivity_documentLaunchMode,
+ ActivityInfo.DOCUMENT_LAUNCH_NONE);
a.info.screenOrientation = sa.getInt(
com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation,
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
@@ -2492,6 +2484,23 @@
a.info.softInputMode = sa.getInt(
com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
0);
+
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_persistable, false)) {
+ a.info.flags |= ActivityInfo.FLAG_PERSISTABLE;
+ }
+
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
+ false)) {
+ a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
+ }
+
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_autoRemoveFromRecents,
+ false)) {
+ a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
+ }
} else {
a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
a.info.configChanges = 0;
@@ -3591,10 +3600,13 @@
// For use by the package manager to keep track of the path to the
// file an app came from.
public String mScanPath;
-
- // For use by package manager to keep track of where it has done dexopt.
- public boolean mDidDexOpt;
-
+
+ // For use by package manager to keep track of where it needs to do dexopt.
+ public boolean mDexOptNeeded = true;
+
+ // For use by package manager to keep track of when a package was last used.
+ public long mLastPackageUsageTimeInMills;
+
// // User set enabled state.
// public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
//
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 4879c23..499de17 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -2308,8 +2308,8 @@
*/
private Drawable loadDrawableForCookie(TypedValue value, int id, Theme theme) {
if (value.string == null) {
- throw new NotFoundException(
- "Resource is not a Drawable (color or path): " + value);
+ throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
+ + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
}
final String file = value.string.toString();
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 722d956..5f2af8cf 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -372,7 +372,6 @@
/**
* <p>Optional. Hyperfocal distance for this lens.</p>
- * <p>If the lens is fixed focus, the camera device will report 0.</p>
* <p>If the lens is not fixed focus, the camera device will report this
* field when {@link CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION android.lens.info.focusDistanceCalibration} is APPROXIMATE or CALIBRATED.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
@@ -1278,20 +1277,6 @@
new Key<Integer>("android.sensor.orientation", int.class);
/**
- * <p>The number of input samples for each dimension of
- * {@link CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP android.sensor.profileHueSatMap}.</p>
- * <p>The number of input samples for the hue, saturation, and value
- * dimension of {@link CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP android.sensor.profileHueSatMap}. The order of the
- * dimensions given is hue, saturation, value; where hue is the 0th
- * element.</p>
- * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
- *
- * @see CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP
- */
- public static final Key<int[]> SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS =
- new Key<int[]>("android.sensor.profileHueSatMapDimensions", int[].class);
-
- /**
* <p>Optional. Defaults to [OFF]. Lists the supported test
* pattern modes for {@link CaptureRequest#SENSOR_TEST_PATTERN_MODE android.sensor.testPatternMode}.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index bb290af..9d0e0e1 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -192,8 +192,9 @@
*
* <p>The camera device will query each Surface's size and formats upon this
* call, so they must be set to a valid setting at this time (in particular:
- * if the format is user-visible, it must be one of android.scaler.availableFormats;
- * and the size must be one of android.scaler.available[Processed|Jpeg]Sizes).</p>
+ * if the format is user-visible, it must be one of
+ * {@link StreamConfigurationMap#getOutputFormats}; and the size must be one of
+ * {@link StreamConfigurationMap#getOutputSizes(int)}).</p>
*
* <p>When this method is called with valid Surfaces, the device will transition to the {@link
* StateListener#onBusy busy state}. Once configuration is complete, the device will transition
@@ -239,6 +240,9 @@
* @see StateListener#onUnconfigured
* @see #stopRepeating
* @see #flush
+ * @see StreamConfigurationMap#getOutputFormats()
+ * @see StreamConfigurationMap#getOutputSizes(int)
+ * @see StreamConfigurationMap#getOutputSizes(Class)
*/
public void configureOutputs(List<Surface> outputs) throws CameraAccessException;
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index ba8db3a..6e38a22f 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1295,6 +1295,20 @@
public static final int CONTROL_SCENE_MODE_BARCODE = 16;
//
+ // Enumeration values for CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
+ //
+
+ /**
+ * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
+ */
+ public static final int CONTROL_VIDEO_STABILIZATION_MODE_OFF = 0;
+
+ /**
+ * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
+ */
+ public static final int CONTROL_VIDEO_STABILIZATION_MODE_ON = 1;
+
+ //
// Enumeration values for CaptureRequest#EDGE_MODE
//
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index c4e342c..f161f3a 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -831,9 +831,11 @@
* stabilized</p>
*
* @see CaptureRequest#SCALER_CROP_REGION
+ * @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF
+ * @see #CONTROL_VIDEO_STABILIZATION_MODE_ON
*/
- public static final Key<Boolean> CONTROL_VIDEO_STABILIZATION_MODE =
- new Key<Boolean>("android.control.videoStabilizationMode", boolean.class);
+ public static final Key<Integer> CONTROL_VIDEO_STABILIZATION_MODE =
+ new Key<Integer>("android.control.videoStabilizationMode", int.class);
/**
* <p>Operation mode for edge
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index d8981c8..51ea447 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -124,6 +124,58 @@
/**
+ * <p>The mode control selects how the image data is converted from the
+ * sensor's native color into linear sRGB color.</p>
+ * <p>When auto-white balance is enabled with {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, this
+ * control is overridden by the AWB routine. When AWB is disabled, the
+ * application controls how the color mapping is performed.</p>
+ * <p>We define the expected processing pipeline below. For consistency
+ * across devices, this is always the case with TRANSFORM_MATRIX.</p>
+ * <p>When either FULL or HIGH_QUALITY is used, the camera device may
+ * do additional processing but {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
+ * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform} will still be provided by the
+ * camera device (in the results) and be roughly correct.</p>
+ * <p>Switching to TRANSFORM_MATRIX and using the data provided from
+ * FAST or HIGH_QUALITY will yield a picture with the same white point
+ * as what was produced by the camera device in the earlier frame.</p>
+ * <p>The expected processing pipeline is as follows:</p>
+ * <p><img alt="White balance processing pipeline" src="../../../../images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png" /></p>
+ * <p>The white balance is encoded by two values, a 4-channel white-balance
+ * gain vector (applied in the Bayer domain), and a 3x3 color transform
+ * matrix (applied after demosaic).</p>
+ * <p>The 4-channel white-balance gains are defined as:</p>
+ * <pre><code>{@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} = [ R G_even G_odd B ]
+ * </code></pre>
+ * <p>where <code>G_even</code> is the gain for green pixels on even rows of the
+ * output, and <code>G_odd</code> is the gain for green pixels on the odd rows.
+ * These may be identical for a given camera device implementation; if
+ * the camera device does not support a separate gain for even/odd green
+ * channels, it will use the <code>G_even</code> value, and write <code>G_odd</code> equal to
+ * <code>G_even</code> in the output result metadata.</p>
+ * <p>The matrices for color transforms are defined as a 9-entry vector:</p>
+ * <pre><code>{@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform} = [ I0 I1 I2 I3 I4 I5 I6 I7 I8 ]
+ * </code></pre>
+ * <p>which define a transform from input sensor colors, <code>P_in = [ r g b ]</code>,
+ * to output linear sRGB, <code>P_out = [ r' g' b' ]</code>,</p>
+ * <p>with colors as follows:</p>
+ * <pre><code>r' = I0r + I1g + I2b
+ * g' = I3r + I4g + I5b
+ * b' = I6r + I7g + I8b
+ * </code></pre>
+ * <p>Both the input and output value ranges must match. Overflow/underflow
+ * values are clipped to fit within the range.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
+ * @see CaptureRequest#CONTROL_AWB_MODE
+ * @see #COLOR_CORRECTION_MODE_TRANSFORM_MATRIX
+ * @see #COLOR_CORRECTION_MODE_FAST
+ * @see #COLOR_CORRECTION_MODE_HIGH_QUALITY
+ */
+ public static final Key<Integer> COLOR_CORRECTION_MODE =
+ new Key<Integer>("android.colorCorrection.mode", int.class);
+
+ /**
* <p>A color transform matrix to use to transform
* from sensor RGB color space to output linear sRGB color space</p>
* <p>This matrix is either set by the camera device when the request
@@ -176,6 +228,82 @@
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
+ * lights, flicker at the rate of the power supply frequency
+ * (60Hz or 50Hz, depending on country). While this is
+ * typically not noticeable to a person, it can be visible to
+ * a camera device. If a camera sets its exposure time to the
+ * wrong value, the flicker may become visible in the
+ * viewfinder as flicker or in a final captured image, as a
+ * set of variable-brightness bands across the image.</p>
+ * <p>Therefore, the auto-exposure routines of camera devices
+ * include antibanding routines that ensure that the chosen
+ * exposure value will not cause such banding. The choice of
+ * exposure time depends on the rate of flicker, which the
+ * camera device can detect automatically, or the expected
+ * rate can be selected by the application using this
+ * control.</p>
+ * <p>A given camera device may not support all of the possible
+ * options for the antibanding mode. The
+ * {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_ANTIBANDING_MODES android.control.aeAvailableAntibandingModes} key contains
+ * the available modes for a given camera device.</p>
+ * <p>The default mode is AUTO, which must be supported by all
+ * camera devices.</p>
+ * <p>If manual exposure control is enabled (by setting
+ * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} or {@link CaptureRequest#CONTROL_MODE android.control.mode} to OFF),
+ * then this setting has no effect, and the application must
+ * ensure it selects exposure times that do not cause banding
+ * issues. The {@link CaptureResult#STATISTICS_SCENE_FLICKER android.statistics.sceneFlicker} key can assist
+ * the application in this.</p>
+ *
+ * @see CameraCharacteristics#CONTROL_AE_AVAILABLE_ANTIBANDING_MODES
+ * @see CaptureRequest#CONTROL_AE_MODE
+ * @see CaptureRequest#CONTROL_MODE
+ * @see CaptureResult#STATISTICS_SCENE_FLICKER
+ * @see #CONTROL_AE_ANTIBANDING_MODE_OFF
+ * @see #CONTROL_AE_ANTIBANDING_MODE_50HZ
+ * @see #CONTROL_AE_ANTIBANDING_MODE_60HZ
+ * @see #CONTROL_AE_ANTIBANDING_MODE_AUTO
+ */
+ public static final Key<Integer> CONTROL_AE_ANTIBANDING_MODE =
+ new Key<Integer>("android.control.aeAntibandingMode", int.class);
+
+ /**
+ * <p>Adjustment to AE target image
+ * 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>
+ */
+ public static final Key<Integer> CONTROL_AE_EXPOSURE_COMPENSATION =
+ new Key<Integer>("android.control.aeExposureCompensation", int.class);
+
+ /**
+ * <p>Whether AE is currently locked to its latest
+ * calculated values.</p>
+ * <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>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})
+ * parameters. The flash may be fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}
+ * is ON_AUTO_FLASH/ON_AUTO_FLASH_REDEYE and the scene is too dark. If the
+ * {@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_MODE
+ * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
+ * @see CaptureResult#CONTROL_AE_STATE
+ * @see CaptureRequest#SENSOR_EXPOSURE_TIME
+ * @see CaptureRequest#SENSOR_SENSITIVITY
+ */
+ public static final Key<Boolean> CONTROL_AE_LOCK =
+ new Key<Boolean>("android.control.aeLock", boolean.class);
+
+ /**
* <p>The desired mode for the camera device's
* auto-exposure routine.</p>
* <p>This control is only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} is
@@ -237,6 +365,35 @@
new Key<int[]>("android.control.aeRegions", int[].class);
/**
+ * <p>Range over which fps can be adjusted to
+ * maintain exposure</p>
+ * <p>Only constrains AE algorithm, not manual control
+ * of {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}</p>
+ *
+ * @see CaptureRequest#SENSOR_EXPOSURE_TIME
+ */
+ public static final Key<int[]> CONTROL_AE_TARGET_FPS_RANGE =
+ new Key<int[]>("android.control.aeTargetFpsRange", int[].class);
+
+ /**
+ * <p>Whether the camera device will trigger a precapture
+ * metering sequence when it processes this request.</p>
+ * <p>This entry is normally set to IDLE, or is not
+ * included at all in the request settings. When included and
+ * set to START, the camera device will trigger the autoexposure
+ * precapture metering sequence.</p>
+ * <p>The effect of AE precapture trigger depends on the current
+ * AE mode and state; see {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE precapture
+ * state transition details.</p>
+ *
+ * @see CaptureResult#CONTROL_AE_STATE
+ * @see #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE
+ * @see #CONTROL_AE_PRECAPTURE_TRIGGER_START
+ */
+ public static final Key<Integer> CONTROL_AE_PRECAPTURE_TRIGGER =
+ new Key<Integer>("android.control.aePrecaptureTrigger", int.class);
+
+ /**
* <p>Current state of AE algorithm</p>
* <p>Switching between or enabling AE modes ({@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}) always
* resets the AE state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
@@ -481,6 +638,24 @@
new Key<int[]>("android.control.afRegions", int[].class);
/**
+ * <p>Whether the camera device will trigger autofocus for this request.</p>
+ * <p>This entry is normally set to IDLE, or is not
+ * included at all in the request settings.</p>
+ * <p>When included and set to START, the camera device will trigger the
+ * autofocus algorithm. If autofocus is disabled, this trigger has no effect.</p>
+ * <p>When set to CANCEL, the camera device will cancel any active trigger,
+ * and return to its initial AF state.</p>
+ * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what that means for each AF mode.</p>
+ *
+ * @see CaptureResult#CONTROL_AF_STATE
+ * @see #CONTROL_AF_TRIGGER_IDLE
+ * @see #CONTROL_AF_TRIGGER_START
+ * @see #CONTROL_AF_TRIGGER_CANCEL
+ */
+ public static final Key<Integer> CONTROL_AF_TRIGGER =
+ new Key<Integer>("android.control.afTrigger", int.class);
+
+ /**
* <p>Current state of AF algorithm.</p>
* <p>Switching between or enabling AF modes ({@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}) always
* resets the AF state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
@@ -889,6 +1064,16 @@
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
+ * mode; in other modes, AWB is already fixed to a specific
+ * setting.</p>
+ */
+ public static final Key<Boolean> CONTROL_AWB_LOCK =
+ new Key<Boolean>("android.control.awbLock", boolean.class);
+
+ /**
* <p>Whether AWB is currently setting the color
* transform fields, and what its illumination target
* is.</p>
@@ -948,6 +1133,30 @@
new Key<int[]>("android.control.awbRegions", int[].class);
/**
+ * <p>Information to the camera device 3A (auto-exposure,
+ * auto-focus, auto-white balance) routines about the purpose
+ * of this capture, to help the camera device to decide optimal 3A
+ * strategy.</p>
+ * <p>This control (except for MANUAL) is only effective if
+ * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p>
+ * <p>ZERO_SHUTTER_LAG must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+ * contains ZSL. MANUAL must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+ * contains MANUAL_SENSOR.</p>
+ *
+ * @see CaptureRequest#CONTROL_MODE
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @see #CONTROL_CAPTURE_INTENT_CUSTOM
+ * @see #CONTROL_CAPTURE_INTENT_PREVIEW
+ * @see #CONTROL_CAPTURE_INTENT_STILL_CAPTURE
+ * @see #CONTROL_CAPTURE_INTENT_VIDEO_RECORD
+ * @see #CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT
+ * @see #CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG
+ * @see #CONTROL_CAPTURE_INTENT_MANUAL
+ */
+ public static final Key<Integer> CONTROL_CAPTURE_INTENT =
+ new Key<Integer>("android.control.captureIntent", int.class);
+
+ /**
* <p>Current state of AWB algorithm</p>
* <p>Switching between or enabling AWB modes ({@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}) always
* resets the AWB state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
@@ -1078,6 +1287,31 @@
new Key<Integer>("android.control.awbState", int.class);
/**
+ * <p>A special color effect to apply.</p>
+ * <p>When this mode is set, a color effect will be applied
+ * to images produced by the camera device. The interpretation
+ * and implementation of these color effects is left to the
+ * implementor of the camera device, and should not be
+ * depended on to be consistent (or present) across all
+ * devices.</p>
+ * <p>A color effect will only be applied if
+ * {@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF.</p>
+ *
+ * @see CaptureRequest#CONTROL_MODE
+ * @see #CONTROL_EFFECT_MODE_OFF
+ * @see #CONTROL_EFFECT_MODE_MONO
+ * @see #CONTROL_EFFECT_MODE_NEGATIVE
+ * @see #CONTROL_EFFECT_MODE_SOLARIZE
+ * @see #CONTROL_EFFECT_MODE_SEPIA
+ * @see #CONTROL_EFFECT_MODE_POSTERIZE
+ * @see #CONTROL_EFFECT_MODE_WHITEBOARD
+ * @see #CONTROL_EFFECT_MODE_BLACKBOARD
+ * @see #CONTROL_EFFECT_MODE_AQUA
+ */
+ public static final Key<Integer> CONTROL_EFFECT_MODE =
+ new Key<Integer>("android.control.effectMode", int.class);
+
+ /**
* <p>Overall mode of 3A control
* routines.</p>
* <p>High-level 3A control. When set to OFF, all 3A control
@@ -1106,6 +1340,57 @@
new Key<Integer>("android.control.mode", int.class);
/**
+ * <p>A camera mode optimized for conditions typical in a particular
+ * capture setting.</p>
+ * <p>This is the mode that that is active when
+ * <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code>. Aside from FACE_PRIORITY,
+ * these modes will disable {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode},
+ * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.</p>
+ * <p>The interpretation and implementation of these scene modes is left
+ * to the implementor of the camera device. Their behavior will not be
+ * consistent across all devices, and any given device may only implement
+ * a subset of these modes.</p>
+ *
+ * @see CaptureRequest#CONTROL_AE_MODE
+ * @see CaptureRequest#CONTROL_AF_MODE
+ * @see CaptureRequest#CONTROL_AWB_MODE
+ * @see CaptureRequest#CONTROL_MODE
+ * @see #CONTROL_SCENE_MODE_DISABLED
+ * @see #CONTROL_SCENE_MODE_FACE_PRIORITY
+ * @see #CONTROL_SCENE_MODE_ACTION
+ * @see #CONTROL_SCENE_MODE_PORTRAIT
+ * @see #CONTROL_SCENE_MODE_LANDSCAPE
+ * @see #CONTROL_SCENE_MODE_NIGHT
+ * @see #CONTROL_SCENE_MODE_NIGHT_PORTRAIT
+ * @see #CONTROL_SCENE_MODE_THEATRE
+ * @see #CONTROL_SCENE_MODE_BEACH
+ * @see #CONTROL_SCENE_MODE_SNOW
+ * @see #CONTROL_SCENE_MODE_SUNSET
+ * @see #CONTROL_SCENE_MODE_STEADYPHOTO
+ * @see #CONTROL_SCENE_MODE_FIREWORKS
+ * @see #CONTROL_SCENE_MODE_SPORTS
+ * @see #CONTROL_SCENE_MODE_PARTY
+ * @see #CONTROL_SCENE_MODE_CANDLELIGHT
+ * @see #CONTROL_SCENE_MODE_BARCODE
+ */
+ public static final Key<Integer> CONTROL_SCENE_MODE =
+ new Key<Integer>("android.control.sceneMode", int.class);
+
+ /**
+ * <p>Whether video stabilization is
+ * active</p>
+ * <p>If enabled, video stabilization can modify the
+ * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream
+ * stabilized</p>
+ *
+ * @see CaptureRequest#SCALER_CROP_REGION
+ * @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF
+ * @see #CONTROL_VIDEO_STABILIZATION_MODE_ON
+ */
+ public static final Key<Integer> CONTROL_VIDEO_STABILIZATION_MODE =
+ new Key<Integer>("android.control.videoStabilizationMode", int.class);
+
+ /**
* <p>Operation mode for edge
* enhancement.</p>
* <p>Edge/sharpness/detail enhancement. OFF means no
@@ -1621,36 +1906,6 @@
new Key<Rational[]>("android.sensor.neutralColorPoint", Rational[].class);
/**
- * <p>A mapping containing a hue shift, saturation scale, and value scale
- * for each pixel.</p>
- * <p>hue_samples, saturation_samples, and value_samples are given in
- * {@link CameraCharacteristics#SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS android.sensor.profileHueSatMapDimensions}.</p>
- * <p>Each entry of this map contains three floats corresponding to the
- * hue shift, saturation scale, and value scale, respectively; where the
- * hue shift has the lowest index. The map entries are stored in the tag
- * in nested loop order, with the value divisions in the outer loop, the
- * hue divisions in the middle loop, and the saturation divisions in the
- * inner loop. All zero input saturation entries are required to have a
- * value scale factor of 1.0.</p>
- * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
- *
- * @see CameraCharacteristics#SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS
- */
- public static final Key<float[]> SENSOR_PROFILE_HUE_SAT_MAP =
- new Key<float[]>("android.sensor.profileHueSatMap", float[].class);
-
- /**
- * <p>A list of x,y samples defining a tone-mapping curve for gamma adjustment.</p>
- * <p>This tag contains a default tone curve that can be applied while
- * processing the image as a starting point for user adjustments.
- * The curve is specified as a list of value pairs in linear gamma.
- * The curve is interpolated using a cubic spline.</p>
- * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
- */
- public static final Key<float[]> SENSOR_PROFILE_TONE_CURVE =
- new Key<float[]>("android.sensor.profileToneCurve", float[].class);
-
- /**
* <p>The worst-case divergence between Bayer green channels.</p>
* <p>This value is an estimate of the worst case split between the
* Bayer green channels in the red and blue rows in the sensor color
@@ -1688,6 +1943,22 @@
new Key<Float>("android.sensor.greenSplit", float.class);
/**
+ * <p>A pixel <code>[R, G_even, G_odd, B]</code> that supplies the test pattern
+ * when {@link CaptureRequest#SENSOR_TEST_PATTERN_MODE android.sensor.testPatternMode} is SOLID_COLOR.</p>
+ * <p>Each color channel is treated as an unsigned 32-bit integer.
+ * The camera device then uses the most significant X bits
+ * that correspond to how many bits are in its Bayer raw sensor
+ * output.</p>
+ * <p>For example, a sensor with RAW10 Bayer output would use the
+ * 10 most significant bits from each color channel.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#SENSOR_TEST_PATTERN_MODE
+ */
+ public static final Key<int[]> SENSOR_TEST_PATTERN_DATA =
+ new Key<int[]>("android.sensor.testPatternData", int[].class);
+
+ /**
* <p>When enabled, the sensor sends a test pattern instead of
* doing a real exposure from the camera.</p>
* <p>When a test pattern is enabled, all manual sensor controls specified
@@ -1936,6 +2207,20 @@
new Key<int[]>("android.statistics.hotPixelMap", int[].class);
/**
+ * <p>Whether the camera device will output the lens
+ * shading map in output result metadata.</p>
+ * <p>When set to ON,
+ * {@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap} must be provided in
+ * the output result metadata.</p>
+ *
+ * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
+ * @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
+ * @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
+ */
+ public static final Key<Integer> STATISTICS_LENS_SHADING_MAP_MODE =
+ new Key<Integer>("android.statistics.lensShadingMapMode", int.class);
+
+ /**
* <p>Tonemapping / contrast / gamma curve for the blue
* channel, to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is
* CONTRAST_CURVE.</p>
diff --git a/core/java/android/hardware/camera2/ColorSpaceTransform.java b/core/java/android/hardware/camera2/ColorSpaceTransform.java
new file mode 100644
index 0000000..9912e4b
--- /dev/null
+++ b/core/java/android/hardware/camera2/ColorSpaceTransform.java
@@ -0,0 +1,239 @@
+/*
+ * 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 for describing a 3x3 matrix of {@link Rational} values in row-major order.
+ *
+ * <p>This matrix maps a transform from one color space to another. For the particular color space
+ * source and target, see the appropriate camera metadata documentation for the key that provides
+ * this value.</p>
+ *
+ * @see CameraMetadata
+ */
+public final class ColorSpaceTransform {
+
+ /** The number of rows in this matrix. */
+ private static final int ROWS = 3;
+
+ /** The number of columns in this matrix. */
+ private static final int COLUMNS = 3;
+
+ /** The number of total Rational elements in this matrix. */
+ private static final int COUNT = ROWS * COLUMNS;
+
+ /** Number of int elements in a rational. */
+ private static final int RATIONAL_SIZE = 2;
+
+ /** Numerator offset inside a rational (pair). */
+ private static final int OFFSET_NUMERATOR = 0;
+
+ /** Denominator offset inside a rational (pair). */
+ private static final int OFFSET_DENOMINATOR = 1;
+
+ /** Number of int elements in this matrix. */
+ private static final int COUNT_INT = ROWS * COLUMNS * RATIONAL_SIZE;
+
+ /**
+ * Create a new immutable {@link ColorSpaceTransform} instance from a {@link Rational} array.
+ *
+ * <p>The elements must be stored in a row-major order.</p>
+ *
+ * @param elements An array of {@code 9} elements
+ *
+ * @throws IllegalArgumentException
+ * if the count of {@code elements} is not {@code 9}
+ * @throws NullPointerException
+ * if {@code elements} or any sub-element is {@code null}
+ */
+ public ColorSpaceTransform(Rational[] elements) {
+
+ checkNotNull(elements, "elements must not be null");
+ if (elements.length != COUNT) {
+ throw new IllegalArgumentException("elements must be " + COUNT + " length");
+ }
+
+ mElements = new int[COUNT_INT];
+
+ for (int i = 0; i < elements.length; ++i) {
+ checkNotNull(elements, "element[" + i + "] must not be null");
+ mElements[i * RATIONAL_SIZE + OFFSET_NUMERATOR] = elements[i].getNumerator();
+ mElements[i * RATIONAL_SIZE + OFFSET_DENOMINATOR] = elements[i].getDenominator();
+ }
+ }
+
+ /**
+ * Create a new immutable {@link ColorSpaceTransform} instance from an {@code int} array.
+ *
+ * <p>The elements must be stored in a row-major order. Each rational is stored
+ * contiguously as a {@code (numerator, denominator)} pair.</p>
+ *
+ * <p>In particular:<pre>{@code
+ * int[] elements = new int[
+ * N11, D11, N12, D12, N13, D13,
+ * N21, D21, N22, D22, N23, D23,
+ * N31, D31, N32, D32, N33, D33
+ * ];
+ *
+ * new ColorSpaceTransform(elements)}</pre>
+ *
+ * where {@code Nij} and {@code Dij} is the numerator and denominator for row {@code i} and
+ * column {@code j}.</p>
+ *
+ * @param elements An array of {@code 18} elements
+ *
+ * @throws IllegalArgumentException
+ * if the count of {@code elements} is not {@code 18}
+ * @throws NullPointerException
+ * if {@code elements} is {@code null}
+ */
+ public ColorSpaceTransform(int[] elements) {
+ checkNotNull(elements, "elements must not be null");
+ if (elements.length != COUNT_INT) {
+ throw new IllegalArgumentException("elements must be " + COUNT_INT + " length");
+ }
+
+ for (int i = 0; i < elements.length; ++i) {
+ checkNotNull(elements, "element " + i + " must not be null");
+ }
+
+ mElements = Arrays.copyOf(elements, elements.length);
+ }
+
+ /**
+ * Get an element of this matrix by its row and column.
+ *
+ * <p>The rows must be within the range [0, 3),
+ * and the column must be within the range [0, 3).</p>
+ *
+ * @return element (non-{@code null})
+ *
+ * @throws IllegalArgumentException if column or row was out of range
+ */
+ public Rational getElement(int column, int row) {
+ if (column < 0 || column >= COLUMNS) {
+ throw new IllegalArgumentException("column out of range");
+ } else if (row < 0 || row >= ROWS) {
+ throw new IllegalArgumentException("row out of range");
+ }
+
+ int numerator = mElements[row * ROWS * RATIONAL_SIZE + column + OFFSET_NUMERATOR];
+ int denominator = mElements[row * ROWS * RATIONAL_SIZE + column + OFFSET_DENOMINATOR];
+
+ return new Rational(numerator, denominator);
+ }
+
+ /**
+ * Copy the {@link Rational} elements in row-major order from this matrix into the destination.
+ *
+ * @param destination
+ * an array big enough to hold at least {@code 9} elements after the
+ * {@code offset}
+ * @param offset
+ * a non-negative offset into the array
+ * @throws NullPointerException
+ * If {@code destination} was {@code null}
+ * @throws ArrayIndexOutOfBoundsException
+ * If there's not enough room to write the elements at the specified destination and
+ * offset.
+ */
+ public void copyElements(Rational[] destination, int offset) {
+ checkArgumentNonnegative(offset, "offset must not be negative");
+ checkNotNull(destination, "destination must not be null");
+ if (destination.length + offset < COUNT) {
+ throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
+ }
+
+ for (int i = 0, j = 0; i < COUNT; ++i, j += RATIONAL_SIZE) {
+ int numerator = mElements[j + OFFSET_NUMERATOR];
+ int denominator = mElements[j + OFFSET_DENOMINATOR];
+
+ destination[i + offset] = new Rational(numerator, denominator);
+ }
+ }
+
+ /**
+ * Copy the {@link Rational} elements in row-major order from this matrix into the destination.
+ *
+ * <p>Each element is stored as a contiguous rational packed as a
+ * {@code (numerator, denominator)} pair of ints, identical to the
+ * {@link ColorSpaceTransform#ColorSpaceTransform(int[]) constructor}.</p>
+ *
+ * @param destination
+ * an array big enough to hold at least {@code 18} elements after the
+ * {@code offset}
+ * @param offset
+ * a non-negative offset into the array
+ * @throws NullPointerException
+ * If {@code destination} was {@code null}
+ * @throws ArrayIndexOutOfBoundsException
+ * If there's not enough room to write the elements at the specified destination and
+ * offset.
+ *
+ * @see ColorSpaceTransform#ColorSpaceTransform(int[])
+ */
+ public void copyElements(int[] destination, int offset) {
+ checkArgumentNonnegative(offset, "offset must not be negative");
+ checkNotNull(destination, "destination must not be null");
+ if (destination.length + offset < COUNT_INT) {
+ throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
+ }
+
+ // Manual copy faster than System#arraycopy for very small loops
+ for (int i = 0; i < COUNT_INT; ++i) {
+ destination[i + offset] = mElements[i];
+ }
+ }
+
+ /**
+ * Check if this {@link ColorSpaceTransform} is equal to another {@link ColorSpaceTransform}.
+ *
+ * <p>Two color space transforms are equal if and only if all of their elements are
+ * {@link Object#equals 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 ColorSpaceTransform) {
+ final ColorSpaceTransform other = (ColorSpaceTransform) obj;
+ return Arrays.equals(mElements, other.mElements);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return HashCodeHelpers.hashCode(mElements);
+ }
+
+ private final int[] mElements;
+};
diff --git a/core/java/android/hardware/camera2/LensShadingMap.java b/core/java/android/hardware/camera2/LensShadingMap.java
new file mode 100644
index 0000000..2c224f64
--- /dev/null
+++ b/core/java/android/hardware/camera2/LensShadingMap.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;
+
+import static com.android.internal.util.Preconditions.*;
+import static android.hardware.camera2.RggbChannelVector.*;
+
+import android.hardware.camera2.impl.HashCodeHelpers;
+
+import java.util.Arrays;
+
+/**
+ * Immutable class for describing a {@code 4 x N x M} lens shading map of floats.
+ *
+ * @see CameraCharacteristics#LENS_SHADING_MAP
+ */
+public final class LensShadingMap {
+
+ /**
+ * The smallest gain factor in this map.
+ *
+ * <p>All values in this map will be at least this large.</p>
+ */
+ public static final float MINIMUM_GAIN_FACTOR = 1.0f;
+
+ /**
+ * Create a new immutable LensShadingMap instance.
+ *
+ * <p>The elements must be stored in a row-major order (fully packed).</p>
+ *
+ * <p>This constructor takes over the array; do not write to the array afterwards.</p>
+ *
+ * @param elements
+ * An array of elements whose length is
+ * {@code RggbChannelVector.COUNT * rows * columns}
+ *
+ * @throws IllegalArgumentException
+ * if the {@code elements} array length is invalid,
+ * if any of the subelems are not finite or less than {@value #MINIMUM_GAIN_FACTOR},
+ * or if rows or columns is not positive
+ * @throws NullPointerException
+ * if {@code elements} is {@code null}
+ *
+ * @hide
+ */
+ public LensShadingMap(final float[] elements, final int rows, final int columns) {
+
+ mRows = checkArgumentPositive(rows, "rows must be positive");
+ mColumns = checkArgumentPositive(rows, "columns must be positive");
+ mElements = checkNotNull(elements, "elements must not be null");
+
+ if (elements.length != getGainFactorCount()) {
+ throw new IllegalArgumentException("elements must be " + getGainFactorCount() +
+ " length");
+ }
+
+ // Every element must be finite and >= 1.0f
+ checkArrayElementsInRange(elements, MINIMUM_GAIN_FACTOR, Float.MAX_VALUE, "elements");
+ }
+
+ /**
+ * Get the number of rows in this map.
+ */
+ public int getRowCount() {
+ return mRows;
+ }
+
+ /**
+ * Get the number of columns in this map.
+ */
+ public int getColumnCount() {
+ return mColumns;
+ }
+
+ /**
+ * Get the total number of gain factors in this map.
+ *
+ * <p>A single gain factor contains exactly one color channel.
+ * Use with {@link #copyGainFactors} to allocate a large-enough array.</p>
+ */
+ public int getGainFactorCount() {
+ return mRows * mColumns * COUNT;
+ }
+
+ /**
+ * Get a single color channel gain factor from this lens shading map by its row and column.
+ *
+ * <p>The rows must be within the range [0, {@link #getRowCount}),
+ * the column must be within the range [0, {@link #getColumnCount}),
+ * and the color channel must be within the range [0, {@value RggbChannelVector#COUNT}).</p>
+ *
+ * <p>The channel order is {@code [R, Geven, Godd, B]}, where
+ * {@code Geven} is the green channel for the even rows of a Bayer pattern, and
+ * {@code Godd} is the odd rows.
+ * </p>
+ *
+ * @param colorChannel color channel from {@code [R, Geven, Godd, B]}
+ * @param column within the range [0, {@link #getColumnCount})
+ * @param row within the range [0, {@link #getRowCount})
+ *
+ * @return a gain factor >= {@value #MINIMUM_GAIN_FACTOR}
+ *
+ * @throws IllegalArgumentException if any of the parameters was out of range
+ *
+ * @see #RED
+ * @see #GREEN_EVEN
+ * @see #GREEN_ODD
+ * @see #BLUE
+ * @see #getRowCount
+ * @see #getColumnCount
+ */
+ public float getGainFactor(final int colorChannel, final int column, final int row) {
+ if (colorChannel < 0 || colorChannel > COUNT) {
+ throw new IllegalArgumentException("colorChannel out of range");
+ } else if (column < 0 || column >= mColumns) {
+ throw new IllegalArgumentException("column out of range");
+ } else if (row < 0 || row >= mRows) {
+ throw new IllegalArgumentException("row out of range");
+ }
+
+ return mElements[colorChannel + (row * mColumns + column) * COUNT ];
+ }
+
+ /**
+ * Get a gain factor vector from this lens shading map by its row and column.
+ *
+ * <p>The rows must be within the range [0, {@link #getRowCount}),
+ * the column must be within the range [0, {@link #getColumnCount}).</p>
+ *
+ * @param column within the range [0, {@link #getColumnCount})
+ * @param row within the range [0, {@link #getRowCount})
+ *
+ * @return an {@link RggbChannelVector} where each gain factor >= {@value #MINIMUM_GAIN_FACTOR}
+ *
+ * @throws IllegalArgumentException if any of the parameters was out of range
+ *
+ * @see #getRowCount
+ * @see #getColumnCount
+ */
+ public RggbChannelVector getGainFactorVector(final int column, final int row) {
+ if (column < 0 || column >= mColumns) {
+ throw new IllegalArgumentException("column out of range");
+ } else if (row < 0 || row >= mRows) {
+ throw new IllegalArgumentException("row out of range");
+ }
+
+ final int offset = (row * mColumns + column) * COUNT;
+
+ final float red =
+ mElements[RED + offset];
+ final float greenEven =
+ mElements[GREEN_EVEN + offset];
+ final float greenOdd =
+ mElements[GREEN_ODD + offset];
+ final float blue =
+ mElements[BLUE + offset];
+
+ return new RggbChannelVector(red, greenEven, greenOdd, blue);
+ }
+
+ /**
+ * Copy all gain factors in row-major order from this lens shading map into the destination.
+ *
+ * <p>Each gain factor will be >= {@link #MINIMUM_GAIN_FACTOR}.</p>
+ *
+ * @param destination
+ * an array big enough to hold at least {@link RggbChannelVector#COUNT}
+ * elements after the {@code offset}
+ * @param offset
+ * a non-negative offset into the array
+ * @throws NullPointerException
+ * If {@code destination} was {@code null}
+ * @throws IllegalArgumentException
+ * If offset was negative
+ * @throws ArrayIndexOutOfBoundsException
+ * If there's not enough room to write the elements at the specified destination and
+ * offset.
+ *
+ * @see CaptureResult#STATISTICS_LENS_SHADING_MAP
+ */
+ public void copyGainFactors(final float[] destination, final int offset) {
+ checkArgumentNonnegative(offset, "offset must not be negative");
+ checkNotNull(destination, "destination must not be null");
+ if (destination.length + offset < getGainFactorCount()) {
+ throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
+ }
+
+ System.arraycopy(mElements, /*srcPos*/0, destination, offset, getGainFactorCount());
+ }
+
+ /**
+ * Check if this LensShadingMap is equal to another LensShadingMap.
+ *
+ * <p>Two lens shading maps are equal if and only if they have the same rows/columns,
+ * and all of their elements are {@link Object#equals 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 LensShadingMap) {
+ final LensShadingMap other = (LensShadingMap) obj;
+ return mRows == other.mRows
+ && mColumns == other.mColumns
+ && Arrays.equals(mElements, other.mElements);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ int elemsHash = HashCodeHelpers.hashCode(mElements);
+ return HashCodeHelpers.hashCode(mRows, mColumns, elemsHash);
+ }
+
+
+ private final int mRows;
+ private final int mColumns;
+ private final float[] mElements;
+};
diff --git a/core/java/android/hardware/camera2/MeteringRectangle.java b/core/java/android/hardware/camera2/MeteringRectangle.java
new file mode 100644
index 0000000..ff7a745
--- /dev/null
+++ b/core/java/android/hardware/camera2/MeteringRectangle.java
@@ -0,0 +1,224 @@
+/*
+ * 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.util.Size;
+import static com.android.internal.util.Preconditions.*;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.camera2.impl.HashCodeHelpers;
+
+/**
+ * An immutable class to represent a rectangle {@code (x,y, width, height)} with an
+ * additional weight component.
+ *
+ * </p>The rectangle is defined to be inclusive of the specified coordinates.</p>
+ *
+ * <p>When used with a {@link CaptureRequest}, the coordinate system is based on the active pixel
+ * array, with {@code (0,0)} being the top-left pixel in the
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE active pixel array}, and
+ * {@code (android.sensor.info.activeArraySize.width - 1,
+ * android.sensor.info.activeArraySize.height - 1)}
+ * being the bottom-right pixel in the active pixel array.
+ * </p>
+ *
+ * <p>The metering weight is nonnegative.</p>
+ */
+public final class MeteringRectangle {
+
+ private final int mX;
+ private final int mY;
+ private final int mWidth;
+ private final int mHeight;
+ private final int mWeight;
+
+ /**
+ * Create a new metering rectangle.
+ *
+ * @param x coordinate >= 0
+ * @param y coordinate >= 0
+ * @param width width >= 0
+ * @param height height >= 0
+ * @param meteringWeight weight >= 0
+ *
+ * @throws IllegalArgumentException if any of the parameters were non-negative
+ */
+ public MeteringRectangle(int x, int y, int width, int height, int meteringWeight) {
+ mX = checkArgumentNonnegative(x, "x must be nonnegative");
+ mY = checkArgumentNonnegative(y, "y must be nonnegative");
+ mWidth = checkArgumentNonnegative(width, "width must be nonnegative");
+ mHeight = checkArgumentNonnegative(height, "height must be nonnegative");
+ mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
+ }
+
+ /**
+ * Create a new metering rectangle.
+ *
+ * @param xy a non-{@code null} {@link Point} with both x,y >= 0
+ * @param dimensions a non-{@code null} {@link android.util.Size Size} with width, height >= 0
+ * @param meteringWeight weight >= 0
+ *
+ * @throws IllegalArgumentException if any of the parameters were non-negative
+ * @throws NullPointerException if any of the arguments were null
+ */
+ public MeteringRectangle(Point xy, Size dimensions, int meteringWeight) {
+ checkNotNull(xy, "xy must not be null");
+ checkNotNull(dimensions, "dimensions must not be null");
+
+ mX = checkArgumentNonnegative(xy.x, "x must be nonnegative");
+ mY = checkArgumentNonnegative(xy.y, "y must be nonnegative");
+ mWidth = checkArgumentNonnegative(dimensions.getWidth(), "width must be nonnegative");
+ mHeight = checkArgumentNonnegative(dimensions.getHeight(), "height must be nonnegative");
+ mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
+ }
+
+ /**
+ * Create a new metering rectangle.
+ *
+ * @param rect a non-{@code null} rectangle with all x,y,w,h dimensions >= 0
+ * @param meteringWeight weight >= 0
+ *
+ * @throws IllegalArgumentException if any of the parameters were non-negative
+ * @throws NullPointerException if any of the arguments were null
+ */
+ public MeteringRectangle(Rect rect, int meteringWeight) {
+ checkNotNull(rect, "rect must not be null");
+
+ mX = checkArgumentNonnegative(rect.left, "rect.left must be nonnegative");
+ mY = checkArgumentNonnegative(rect.top, "rect.top must be nonnegative");
+ mWidth = checkArgumentNonnegative(rect.width(), "rect.width must be nonnegative");
+ mHeight = checkArgumentNonnegative(rect.height(), "rect.height must be nonnegative");
+ mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
+ }
+
+ /**
+ * Return the X coordinate of the left side of the rectangle.
+ *
+ * @return x coordinate >= 0
+ */
+ public int getX() {
+ return mX;
+ }
+
+ /**
+ * Return the Y coordinate of the upper side of the rectangle.
+ *
+ * @return y coordinate >= 0
+ */
+ public int getY() {
+ return mY;
+ }
+
+ /**
+ * Return the width of the rectangle.
+ *
+ * @return width >= 0
+ */
+ public int getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * Return the height of the rectangle.
+ *
+ * @return height >= 0
+ */
+ public int getHeight() {
+ return mHeight;
+ }
+
+ /**
+ * Return the metering weight of the rectangle.
+ *
+ * @return weight >= 0
+ */
+ public int getMeteringWeight() {
+ return mWeight;
+ }
+
+ /**
+ * Convenience method to create the upper-left (X,Y) coordinate as a {@link Point}.
+ *
+ * @return {@code (x,y)} point with both x,y >= 0
+ */
+ public Point getUpperLeftPoint() {
+ return new Point(mX, mY);
+ }
+
+ /**
+ * Convenience method to create the size from this metering rectangle.
+ *
+ * <p>This strips away the X,Y,weight from the rectangle.</p>
+ *
+ * @return a Size with non-negative width and height
+ */
+ public Size getSize() {
+ return new Size(mWidth, mHeight);
+ }
+
+ /**
+ * Convenience method to create a {@link Rect} from this metering rectangle.
+ *
+ * <p>This strips away the weight from the rectangle.</p>
+ *
+ * @return a {@link Rect} with non-negative x1, y1, x2, y2
+ */
+ public Rect getRect() {
+ return new Rect(mX, mY, mX + mWidth, mY + mHeight);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(final Object other) {
+ if (other instanceof MeteringRectangle) {
+ return equals(other);
+ }
+ return false;
+ }
+
+ /**
+ * Compare two metering rectangles to see if they are equal.
+ *
+ * Two weighted rectangles are only considered equal if each of their components
+ * (x, y, width, height, weight) is respectively equal.
+ *
+ * @param other Another MeteringRectangle
+ *
+ * @return {@code true} if the metering rectangles are equal, {@code false} otherwise
+ */
+ public boolean equals(final MeteringRectangle other) {
+ if (other == null) {
+ return false;
+ }
+
+ return (mX == other.mX
+ && mY == other.mY
+ && mWidth == other.mWidth
+ && mHeight == other.mHeight
+ && mWidth == other.mWidth);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return HashCodeHelpers.hashCode(mX, mY, mWidth, mHeight, mWeight);
+ }
+}
diff --git a/core/java/android/hardware/camera2/ReprocessFormatsMap.java b/core/java/android/hardware/camera2/ReprocessFormatsMap.java
new file mode 100644
index 0000000..c6c59d4
--- /dev/null
+++ b/core/java/android/hardware/camera2/ReprocessFormatsMap.java
@@ -0,0 +1,258 @@
+/*
+ * 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/RggbChannelVector.java b/core/java/android/hardware/camera2/RggbChannelVector.java
new file mode 100644
index 0000000..80167c6
--- /dev/null
+++ b/core/java/android/hardware/camera2/RggbChannelVector.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.hardware.camera2;
+
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Immutable class to store a 4-element vector of floats indexable by a bayer RAW 2x2 pixel block.
+ */
+public final class RggbChannelVector {
+ /**
+ * The number of color channels in this vector.
+ */
+ public static final int COUNT = 4;
+
+ /** Red color channel in a bayer Raw pattern. */
+ public static final int RED = 0;
+
+ /** Green color channel in a bayer Raw pattern used by the even rows. */
+ public static final int GREEN_EVEN = 1;
+
+ /** Green color channel in a bayer Raw pattern used by the odd rows. */
+ public static final int GREEN_ODD = 2;
+
+ /** Blue color channel in a bayer Raw pattern. */
+ public static final int BLUE = 3;
+
+ /**
+ * Create a new {@link RggbChannelVector} from an RGGB 2x2 pixel.
+ *
+ * <p>All pixel values are considered normalized within {@code [0.0f, 1.0f]}
+ * (i.e. {@code 1.0f} could be linearized to {@code 255} if converting to a
+ * non-floating point pixel representation).</p>
+ *
+ * <p>All arguments must be finite; NaN and infinity is not allowed.</p>
+ *
+ * @param red red pixel
+ * @param greenEven green pixel (even row)
+ * @param greenOdd green pixel (odd row)
+ * @param blue blue pixel
+ *
+ * @throws IllegalArgumentException if any of the arguments were not finite
+ */
+ public RggbChannelVector(final float red, final float greenEven, final float greenOdd,
+ final float blue) {
+ mRed = checkArgumentFinite(red, "red");
+ mGreenEven = checkArgumentFinite(greenEven, "greenEven");
+ mGreenOdd = checkArgumentFinite(greenOdd, "greenOdd");
+ mBlue = checkArgumentFinite(blue, "blue");
+ }
+
+ /**
+ * Get the red component.
+ *
+ * @return a floating point value (guaranteed to be finite)
+ */
+ public final float getRed() {
+ return mRed;
+ }
+
+ /**
+ * Get the green (even rows) component.
+ *
+ * @return a floating point value (guaranteed to be finite)
+ */
+ public float getGreenEven() {
+ return mGreenEven;
+ }
+
+ /**
+ * Get the green (odd rows) component.
+ *
+ * @return a floating point value (guaranteed to be finite)
+ */
+ public float getGreenOdd() {
+ return mGreenOdd;
+ }
+
+ /**
+ * Get the blue component.
+ *
+ * @return a floating point value (guaranteed to be finite)
+ */
+ public float getBlue() {
+ return mBlue;
+ }
+
+ /**
+ * Get the component by the color channel index.
+ *
+ * <p>{@code colorChannel} must be one of {@link #RED}, {@link #GREEN_EVEN}, {@link #GREEN_ODD},
+ * {@link #BLUE}.</p>
+ *
+ * @param colorChannel greater or equal to {@code 0} and less than {@link #COUNT}
+ * @return a floating point value (guaranteed to be finite)
+ *
+ * @throws IllegalArgumentException if {@code colorChannel} was out of range
+ */
+ public float getComponent(final int colorChannel) {
+ if (colorChannel < 0 || colorChannel >= COUNT) {
+ throw new IllegalArgumentException("Color channel out of range");
+ }
+
+ switch (colorChannel) {
+ case RED:
+ return mRed;
+ case GREEN_EVEN:
+ return mGreenEven;
+ case GREEN_ODD:
+ return mGreenOdd;
+ case BLUE:
+ return mBlue;
+ default:
+ throw new AssertionError("Unhandled case " + colorChannel);
+ }
+ }
+
+ /**
+ * Copy the vector into the destination in the order {@code [R, Geven, Godd, B]}.
+ *
+ * @param destination
+ * an array big enough to hold at least {@value #COUNT} elements after the
+ * {@code offset}
+ * @param offset
+ * a non-negative offset into the array
+ *
+ * @throws NullPointerException
+ * If {@code destination} was {@code null}
+ * @throws ArrayIndexOutOfBoundsException
+ * If there's not enough room to write the elements at the specified destination and
+ * offset.
+ */
+ public void copyTo(final float[] destination, final int offset) {
+ checkNotNull(destination, "destination must not be null");
+ if (destination.length + offset < COUNT) {
+ throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
+ }
+
+ destination[offset + RED] = mRed;
+ destination[offset + GREEN_EVEN] = mGreenEven;
+ destination[offset + GREEN_ODD] = mGreenOdd;
+ destination[offset + BLUE] = mBlue;
+ }
+
+ /**
+ * Check if this {@link RggbChannelVector} is equal to another {@link RggbChannelVector}.
+ *
+ * <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 RggbChannelVector) {
+ final RggbChannelVector other = (RggbChannelVector) obj;
+ return mRed == other.mRed &&
+ mGreenEven == other.mGreenEven &&
+ mGreenOdd == other.mGreenOdd &&
+ mBlue == other.mBlue;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return Float.floatToIntBits(mRed) ^
+ Float.floatToIntBits(mGreenEven) ^
+ Float.floatToIntBits(mGreenOdd) ^
+ Float.floatToIntBits(mBlue);
+ }
+
+ private final float mRed;
+ private final float mGreenEven;
+ private final float mGreenOdd;
+ private final float mBlue;
+}
diff --git a/core/java/android/hardware/camera2/Size.java b/core/java/android/hardware/camera2/Size.java
index 45aaeae..9328a003 100644
--- a/core/java/android/hardware/camera2/Size.java
+++ b/core/java/android/hardware/camera2/Size.java
@@ -16,32 +16,55 @@
package android.hardware.camera2;
+// TODO: Delete this class, since it was moved to android.util as public API
+
/**
- * A simple immutable class for describing the dimensions of camera image
- * buffers.
+ * Immutable class for describing width and height dimensions in pixels.
+ *
+ * @hide
*/
public final class Size {
/**
- * Create a new immutable Size instance
+ * Create a new immutable Size instance.
*
- * @param width The width to store in the Size instance
- * @param height The height to store in the Size instance
+ * @param width The width of the size, in pixels
+ * @param height The height of the size, in pixels
*/
- public Size(int width, int height) {
+ public Size(final int width, final int height) {
mWidth = width;
mHeight = height;
}
+ /**
+ * Get the width of the size (in pixels).
+ * @return width
+ */
public final int getWidth() {
return mWidth;
}
+ /**
+ * Get the height of the size (in pixels).
+ * @return height
+ */
public final int getHeight() {
return mHeight;
}
+ /**
+ * Check if this size is equal to another size.
+ * <p>
+ * Two sizes are equal if and only if both their widths and heights are
+ * equal.
+ * </p>
+ * <p>
+ * A size object is never equal to any other type of object.
+ * </p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
@Override
- public boolean equals(Object obj) {
+ public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
@@ -49,27 +72,29 @@
return true;
}
if (obj instanceof Size) {
- Size other = (Size) obj;
+ final Size other = (Size) obj;
return mWidth == other.mWidth && mHeight == other.mHeight;
}
return false;
}
+ /**
+ * Return the size represented as a string with the format {@code "WxH"}
+ *
+ * @return string representation of the size
+ */
@Override
public String toString() {
return mWidth + "x" + mHeight;
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public int hashCode() {
- final long INT_MASK = 0xffffffffL;
-
- long asLong = INT_MASK & mWidth;
- asLong <<= 32;
-
- asLong |= (INT_MASK & mHeight);
-
- return ((Long)asLong).hashCode();
+ // assuming most sizes are <2^16, doing a rotate will give us perfect hashing
+ return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
}
private final int mWidth;
diff --git a/core/java/android/hardware/camera2/StreamConfiguration.java b/core/java/android/hardware/camera2/StreamConfiguration.java
new file mode 100644
index 0000000..c53dd7c
--- /dev/null
+++ b/core/java/android/hardware/camera2/StreamConfiguration.java
@@ -0,0 +1,166 @@
+/*
+ * 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
new file mode 100644
index 0000000..189ae62
--- /dev/null
+++ b/core/java/android/hardware/camera2/StreamConfigurationDuration.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;
+
+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
new file mode 100644
index 0000000..e24fd1b
--- /dev/null
+++ b/core/java/android/hardware/camera2/StreamConfigurationMap.java
@@ -0,0 +1,508 @@
+/*
+ * 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
new file mode 100644
index 0000000..ee20d68
--- /dev/null
+++ b/core/java/android/hardware/camera2/TonemapCurve.java
@@ -0,0 +1,290 @@
+/*
+ * 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.graphics.PointF;
+import android.hardware.camera2.impl.HashCodeHelpers;
+
+import java.util.Arrays;
+
+/**
+ * Immutable class for describing a {@code 2 x M x 3} tonemap curve of floats.
+ *
+ * <p>This defines red, green, and blue curves that the {@link CameraDevice} will
+ * use as the tonemapping/contrast/gamma curve when {@link CaptureRequest#TONEMAP_MODE} is
+ * set to {@link CameraMetadata#TONEMAP_MODE_CONTRAST_CURVE}.</p>
+ *
+ * <p>The total number of points {@code (Pin, Pout)} for each color channel can be no more than
+ * {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS}.</p>
+ *
+ * <p>The coordinate system for each point is within the inclusive range
+ * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p>
+ *
+ * @see CaptureRequest#TONEMAP_CURVE_BLUE
+ * @see CaptureRequest#TONEMAP_CURVE_GREEN
+ * @see CaptureRequest#TONEMAP_CURVE_RED
+ * @see CameraMetadata#TONEMAP_MODE_CONTRAST_CURVE
+ * @see CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS
+ */
+public final class TonemapCurve {
+ /**
+ * Lower bound tonemap value corresponding to pure black for a single color channel.
+ */
+ public static final float LEVEL_BLACK = 0.0f;
+
+ /**
+ * Upper bound tonemap value corresponding to a pure white for a single color channel.
+ */
+ public static final float LEVEL_WHITE = 1.0f;
+
+ /**
+ * Number of elements in a {@code (Pin, Pout)} point;
+ */
+ public static final int POINT_SIZE = 2;
+
+ /**
+ * Index of the red color channel curve.
+ */
+ public static final int CHANNEL_RED = 0;
+ /**
+ * Index of the green color channel curve.
+ */
+ public static final int CHANNEL_GREEN = 1;
+ /**
+ * Index of the blue color channel curve.
+ */
+ public static final int CHANNEL_BLUE = 2;
+
+ /**
+ * Create a new immutable TonemapCurve instance.
+ *
+ * <p>Values are stored as a contiguous {@code (Pin, Pout}) point.</p>
+ *
+ * <p>All parameters may have independent length but should have at most
+ * {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS} * {@value #POINT_SIZE} elements.</p>
+ *
+ * <p>All sub-elements must be in the inclusive range of
+ * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p>
+ *
+ * <p>This constructor copies the array contents and does not retain ownership of the array.</p>
+ *
+ * @param elements An array of elements whose length is {@code CHANNEL_COUNT * rows * columns}
+ *
+ * @throws IllegalArgumentException
+ * if the {@code elements} array length is invalid,
+ * if any of the subelems are not finite
+ * @throws NullPointerException
+ * if any of the parameters is {@code null}
+ *
+ * @hide
+ */
+ public TonemapCurve(float[] red, float[] green, float[] blue) {
+ // TODO: maxCurvePoints check?
+
+ checkNotNull(red, "red must not be null");
+ checkNotNull(green, "green must not be null");
+ checkNotNull(blue, "blue must not be null");
+
+ checkArgumentArrayLengthDivisibleBy(red, POINT_SIZE, "red");
+ checkArgumentArrayLengthDivisibleBy(green, POINT_SIZE, "green");
+ checkArgumentArrayLengthDivisibleBy(blue, POINT_SIZE, "blue");
+
+ checkArrayElementsInRange(red, LEVEL_BLACK, LEVEL_WHITE, "red");
+ checkArrayElementsInRange(green, LEVEL_BLACK, LEVEL_WHITE, "green");
+ checkArrayElementsInRange(blue, LEVEL_BLACK, LEVEL_WHITE, "blue");
+
+ mRed = Arrays.copyOf(red, red.length);
+ mGreen = Arrays.copyOf(green, green.length);
+ mBlue = Arrays.copyOf(blue, blue.length);
+ }
+
+ private static void checkArgumentArrayLengthDivisibleBy(float[] array,
+ int divisible, String arrayName) {
+ if (array.length % divisible != 0) {
+ throw new IllegalArgumentException(arrayName + " size must be divisible by "
+ + divisible);
+ }
+ }
+
+ private static int checkArgumentColorChannel(int colorChannel) {
+ switch (colorChannel) {
+ case CHANNEL_RED:
+ case CHANNEL_GREEN:
+ case CHANNEL_BLUE:
+ break;
+ default:
+ throw new IllegalArgumentException("colorChannel out of range");
+ }
+
+ return colorChannel;
+ }
+
+ /**
+ * Get the number of points stored in this tonemap curve for the specified color channel.
+ *
+ * @param colorChannel one of {@link #CHANNEL_RED}, {@link #CHANNEL_GREEN}, {@link #CHANNEL_BLUE}
+ * @return number of points stored in this tonemap for that color's curve (>= 0)
+ *
+ * @throws IllegalArgumentException if {@code colorChannel} was out of range
+ */
+ public int getPointCount(int colorChannel) {
+ checkArgumentColorChannel(colorChannel);
+
+ return getCurve(colorChannel).length / POINT_SIZE;
+ }
+
+ /**
+ * Get the point for a color channel at a specified index.
+ *
+ * <p>The index must be at least 0 but no greater than {@link #getPointCount(int)} for
+ * that {@code colorChannel}.</p>
+ *
+ * <p>All returned coordinates in the point are between the range of
+ * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p>
+ *
+ * @param colorChannel {@link #CHANNEL_RED}, {@link #CHANNEL_GREEN}, or {@link #CHANNEL_BLUE}
+ * @param index at least 0 but no greater than {@code getPointCount(colorChannel)}
+ * @return the {@code (Pin, Pout)} pair mapping the tone for that index
+ *
+ * @throws IllegalArgumentException if {@code colorChannel} or {@code index} was out of range
+ *
+ * @see #LEVEL_BLACK
+ * @see #LEVEL_WHITE
+ */
+ public PointF getPoint(int colorChannel, int index) {
+ checkArgumentColorChannel(colorChannel);
+ if (index < 0 || index >= getPointCount(colorChannel)) {
+ throw new IllegalArgumentException("index out of range");
+ }
+
+ final float[] curve = getCurve(colorChannel);
+
+ final float pIn = curve[index * POINT_SIZE + OFFSET_POINT_IN];
+ final float pOut = curve[index * POINT_SIZE + OFFSET_POINT_OUT];
+
+ return new PointF(pIn, pOut);
+ }
+
+ /**
+ * Copy the color curve for a single color channel from this tonemap curve into the destination.
+ *
+ * <p>
+ * <!--The output is encoded the same as in the constructor -->
+ * Values are stored as packed {@code (Pin, Pout}) points, and there are a total of
+ * {@link #getPointCount} points for that respective channel.</p>
+ *
+ * <p>All returned coordinates are between the range of
+ * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p>
+ *
+ * @param destination
+ * an array big enough to hold at least {@link #getPointCount} {@code *}
+ * {@link #POINT_SIZE} elements after the {@code offset}
+ * @param offset
+ * a non-negative offset into the array
+ * @throws NullPointerException
+ * If {@code destination} was {@code null}
+ * @throws IllegalArgumentException
+ * If offset was negative
+ * @throws ArrayIndexOutOfBoundsException
+ * If there's not enough room to write the elements at the specified destination and
+ * offset.
+ *
+ * @see CaptureRequest#TONEMAP_CURVE_BLUE
+ * @see CaptureRequest#TONEMAP_CURVE_RED
+ * @see CaptureRequest#TONEMAP_CURVE_GREEN
+ * @see #LEVEL_BLACK
+ * @see #LEVEL_WHITE
+ */
+ public void copyColorCurve(int colorChannel, float[] destination,
+ int offset) {
+ checkArgumentNonnegative(offset, "offset must not be negative");
+ checkNotNull(destination, "destination must not be null");
+
+ if (destination.length + offset < getPointCount(colorChannel) * POINT_SIZE) {
+ throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
+ }
+
+ float[] curve = getCurve(colorChannel);
+ System.arraycopy(curve, /*srcPos*/0, destination, offset, curve.length);
+ }
+
+ /**
+ * Check if this TonemapCurve is equal to another TonemapCurve.
+ *
+ * <p>Two matrices are equal if and only if all of their elements are
+ * {@link Object#equals equal}.</p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof TonemapCurve) {
+ final TonemapCurve other = (TonemapCurve) obj;
+ return Arrays.equals(mRed, other.mRed) &&
+ Arrays.equals(mGreen, other.mGreen) &&
+ Arrays.equals(mBlue, other.mBlue);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ if (mHashCalculated) {
+ // Avoid re-calculating hash. Data is immutable so this is both legal and faster.
+ return mHashCode;
+ }
+
+ mHashCode = HashCodeHelpers.hashCode(mRed, mGreen, mBlue);
+ mHashCalculated = true;
+
+ return mHashCode;
+ }
+
+ private float[] getCurve(int colorChannel) {
+ switch (colorChannel) {
+ case CHANNEL_RED:
+ return mRed;
+ case CHANNEL_GREEN:
+ return mGreen;
+ case CHANNEL_BLUE:
+ return mBlue;
+ default:
+ throw new AssertionError("colorChannel out of range");
+ }
+ }
+
+ private final static int OFFSET_POINT_IN = 0;
+ private final static int OFFSET_POINT_OUT = 1;
+
+ private final float[] mRed;
+ private final float[] mGreen;
+ private final float[] mBlue;
+
+ private int mHashCode;
+ private boolean mHashCalculated = false;
+};
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index 40a7905..988f8f9 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -647,7 +647,7 @@
* should have arrived. The following line checks whether this holds.
*/
if (frameNumber != mCompletedFrameNumber + 1) {
- throw new AssertionError(String.format(
+ Log.e(TAG, String.format(
"result frame number %d comes out of order, should be %d + 1",
frameNumber, mCompletedFrameNumber));
}
diff --git a/core/java/android/hardware/camera2/impl/HashCodeHelpers.java b/core/java/android/hardware/camera2/impl/HashCodeHelpers.java
new file mode 100644
index 0000000..2d63827
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/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.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/hdmi/HdmiCec.java b/core/java/android/hardware/hdmi/HdmiCec.java
index 8578a32..7213c78 100644
--- a/core/java/android/hardware/hdmi/HdmiCec.java
+++ b/core/java/android/hardware/hdmi/HdmiCec.java
@@ -85,7 +85,7 @@
public static final int ADDR_RESERVED_2 = 13;
/** Logical address for TV other than the one assigned with {@link #ADDR_TV} */
- public static final int ADDR_FREE_USE = 14;
+ public static final int ADDR_SPECIFIC_USE = 14;
/** Logical address for devices to which address cannot be allocated */
public static final int ADDR_UNREGISTERED = 15;
@@ -160,6 +160,8 @@
public static final int MESSAGE_SET_EXTERNAL_TIMER = 0xA2;
public static final int MESSAGE_ABORT = 0xFF;
+ public static final int UNKNOWN_VENDOR_ID = 0xFFFFFF;
+
public static final int POWER_STATUS_UNKNOWN = -1;
public static final int POWER_STATUS_ON = 0;
public static final int POWER_STATUS_STANDBY = 1;
@@ -179,6 +181,7 @@
DEVICE_RECORDER, // ADDR_RECORDER_3
DEVICE_TUNER, // ADDR_TUNER_4
DEVICE_PLAYBACK, // ADDR_PLAYBACK_3
+ DEVICE_TV, // ADDR_SPECIFIC_USE
};
private static final String[] DEFAULT_NAMES = {
@@ -194,6 +197,7 @@
"Recorder_3",
"Tuner_4",
"Playback_3",
+ "Secondary_TV",
};
private HdmiCec() { } // Prevents instantiation.
@@ -221,9 +225,7 @@
* @return true if the given address is valid
*/
public static boolean isValidAddress(int address) {
- // TODO: We leave out the address 'free use(14)' for now. Check this later
- // again to make sure it is a valid address for communication.
- return (ADDR_TV <= address && address <= ADDR_PLAYBACK_3);
+ return (ADDR_TV <= address && address <= ADDR_SPECIFIC_USE);
}
/**
diff --git a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
new file mode 100644
index 0000000..9698445
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
@@ -0,0 +1,168 @@
+/*
+ * 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.hdmi;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class to encapsulate device information for HDMI-CEC. This container
+ * include basic information such as logical address, physical address and
+ * device type, and additional information like vendor id and osd name.
+ */
+public final class HdmiCecDeviceInfo implements Parcelable {
+ // Logical address, phsical address, device type, vendor id and display name
+ // are immutable value.
+ private final int mLogicalAddress;
+ private final int mPhysicalAddress;
+ private final int mDeviceType;
+ private final int mVendorId;
+ private final String mDisplayName;
+
+
+ /**
+ * A helper class to deserialize {@link HdmiCecDeviceInfo} for a parcel.
+ */
+ public static final Parcelable.Creator<HdmiCecDeviceInfo> CREATOR =
+ new Parcelable.Creator<HdmiCecDeviceInfo>() {
+ @Override
+ public HdmiCecDeviceInfo createFromParcel(Parcel source) {
+ int logicalAddress = source.readInt();
+ int physicalAddress = source.readInt();
+ int deviceType = source.readInt();
+ int vendorId = source.readInt();
+ String displayName = source.readString();
+ return new HdmiCecDeviceInfo(logicalAddress, physicalAddress, deviceType,
+ vendorId, displayName);
+ }
+
+ @Override
+ public HdmiCecDeviceInfo[] newArray(int size) {
+ return new HdmiCecDeviceInfo[size];
+ }
+ };
+
+ /**
+ * Constructor.
+ *
+ * @param logicalAddress logical address of HDMI-Cec device.
+ * For more details, refer {@link HdmiCec}
+ * @param physicalAddress physical address of HDMI-Cec device
+ * @param deviceType type of device. For more details, refer {@link HdmiCec}
+ * @param vendorId vendor id of device. It's used for vendor specific command
+ * @param displayName name of device
+ * @hide
+ */
+ public HdmiCecDeviceInfo(int logicalAddress, int physicalAddress, int deviceType,
+ int vendorId, String displayName) {
+ mLogicalAddress = logicalAddress;
+ mPhysicalAddress = physicalAddress;
+ mDeviceType = deviceType;
+ mDisplayName = displayName;
+ mVendorId = vendorId;
+ }
+
+ /**
+ * Return the logical address of the device. It can have 0-15 values.
+ * For more details, refer constants between {@link HdmiCec#ADDR_TV}
+ * and {@link HdmiCec#ADDR_UNREGISTERED}.
+ */
+ public int getLogicalAddress() {
+ return mLogicalAddress;
+ }
+
+ /**
+ * Return the physical address of the device.
+ */
+ public int getPhysicalAddress() {
+ return mPhysicalAddress;
+ }
+
+ /**
+ * Return type of the device. For more details, refer constants between
+ * {@link HdmiCec#DEVICE_TV} and {@link HdmiCec#DEVICE_INACTIVE}.
+ */
+ public int getDeviceType() {
+ return mDeviceType;
+ }
+
+ /**
+ * Return display (OSD) name of the device.
+ */
+ public String getDisplayName() {
+ return mDisplayName;
+ }
+
+ /**
+ * Return vendor id of the device. Vendor id is used to distinguish devices
+ * built by other manufactures. This is required for vendor-specific command
+ * on CEC standard.
+ */
+ public int getVendorId() {
+ return mVendorId;
+ }
+
+ /**
+ * Describe the kinds of special objects contained in this Parcelable's
+ * marshalled representation.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Serialize this object into a {@link Parcel}.
+ *
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ * May be 0 or {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mLogicalAddress);
+ dest.writeInt(mPhysicalAddress);
+ dest.writeInt(mDeviceType);
+ dest.writeInt(mVendorId);
+ dest.writeString(mDisplayName);
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer s = new StringBuffer();
+ s.append("logical_address: ").append(mLogicalAddress).append(", ");
+ s.append("physical_address: ").append(mPhysicalAddress).append(", ");
+ s.append("device_type: ").append(mDeviceType).append(", ");
+ s.append("vendor_id: ").append(mVendorId).append(", ");
+ s.append("display_name: ").append(mDisplayName);
+ return s.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof HdmiCecDeviceInfo)) {
+ return false;
+ }
+
+ HdmiCecDeviceInfo other = (HdmiCecDeviceInfo) obj;
+ return mLogicalAddress == other.mLogicalAddress
+ && mPhysicalAddress == other.mPhysicalAddress
+ && mDeviceType == other.mDeviceType
+ && mVendorId == other.mVendorId
+ && mDisplayName.equals(other.mDisplayName);
+ }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiCecMessage.java b/core/java/android/hardware/hdmi/HdmiCecMessage.java
index be94d97..ddaf870 100644
--- a/core/java/android/hardware/hdmi/HdmiCecMessage.java
+++ b/core/java/android/hardware/hdmi/HdmiCecMessage.java
@@ -19,6 +19,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import libcore.util.EmptyArray;
+
import java.util.Arrays;
/**
@@ -28,6 +30,8 @@
*/
public final class HdmiCecMessage implements Parcelable {
+ public static final byte[] EMPTY_PARAM = EmptyArray.BYTE;
+
private static final int MAX_MESSAGE_LENGTH = 16;
private final int mSource;
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 505ef9c..f6438b4 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -666,7 +666,8 @@
mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
mInflater = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
- mWindow = new SoftInputWindow(this, mTheme, mDispatcherState);
+ mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
+ false);
if (mHardwareAccelerated) {
mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
}
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index df1afee..a9bace1 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -30,11 +30,20 @@
* method window. It will be displayed along the edge of the screen, moving
* the application user interface away from it so that the focused item is
* always visible.
+ * @hide
*/
-class SoftInputWindow extends Dialog {
+public class SoftInputWindow extends Dialog {
+ final String mName;
+ final Callback mCallback;
+ final KeyEvent.Callback mKeyEventCallback;
final KeyEvent.DispatcherState mDispatcherState;
+ final boolean mTakesFocus;
private final Rect mBounds = new Rect();
-
+
+ public interface Callback {
+ public void onBackPressed();
+ }
+
public void setToken(IBinder token) {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.token = token;
@@ -53,10 +62,15 @@
* using styles. This theme is applied on top of the current theme in
* <var>context</var>. If 0, the default dialog theme will be used.
*/
- public SoftInputWindow(Context context, int theme,
- KeyEvent.DispatcherState dispatcherState) {
+ public SoftInputWindow(Context context, String name, int theme, Callback callback,
+ KeyEvent.Callback keyEventCallback, KeyEvent.DispatcherState dispatcherState,
+ boolean takesFocus) {
super(context, theme);
+ mName = name;
+ mCallback = callback;
+ mKeyEventCallback = keyEventCallback;
mDispatcherState = dispatcherState;
+ mTakesFocus = takesFocus;
initDockWindow();
}
@@ -148,11 +162,47 @@
}
}
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (mKeyEventCallback != null && mKeyEventCallback.onKeyDown(keyCode, event)) {
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ if (mKeyEventCallback != null && mKeyEventCallback.onKeyLongPress(keyCode, event)) {
+ return true;
+ }
+ return super.onKeyLongPress(keyCode, event);
+ }
+
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (mKeyEventCallback != null && mKeyEventCallback.onKeyUp(keyCode, event)) {
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
+ if (mKeyEventCallback != null && mKeyEventCallback.onKeyMultiple(keyCode, count, event)) {
+ return true;
+ }
+ return super.onKeyMultiple(keyCode, count, event);
+ }
+
+ public void onBackPressed() {
+ if (mCallback != null) {
+ mCallback.onBackPressed();
+ } else {
+ super.onBackPressed();
+ }
+ }
+
private void initDockWindow() {
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.type = WindowManager.LayoutParams.TYPE_INPUT_METHOD;
- lp.setTitle("InputMethod");
+ lp.setTitle(mName);
lp.gravity = Gravity.BOTTOM;
lp.width = -1;
@@ -161,11 +211,19 @@
//lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
getWindow().setAttributes(lp);
- getWindow().setFlags(
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
+
+ int windowSetFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+ int windowModFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
- WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+ WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+
+ if (!mTakesFocus) {
+ windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ } else {
+ windowSetFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+ windowModFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+ }
+
+ getWindow().setFlags(windowSetFlags, windowModFlags);
}
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 3da00b1..30d7043 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1307,14 +1307,13 @@
* doing something unusual like general internal filtering this may be useful. On
* a private network where the proxy is not accessible, you may break HTTP using this.
*
- * @param p The a {@link ProxyProperties} object defining the new global
+ * @param p The a {@link ProxyInfo} object defining the new global
* HTTP proxy. A {@code null} value will clear the global HTTP proxy.
*
* <p>This method requires the call to hold the permission
- * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
- * {@hide}
+ * android.Manifest.permission#CONNECTIVITY_INTERNAL.
*/
- public void setGlobalProxy(ProxyProperties p) {
+ public void setGlobalProxy(ProxyInfo p) {
try {
mService.setGlobalProxy(p);
} catch (RemoteException e) {
@@ -1324,14 +1323,13 @@
/**
* Retrieve any network-independent global HTTP proxy.
*
- * @return {@link ProxyProperties} for the current global HTTP proxy or {@code null}
+ * @return {@link ProxyInfo} for the current global HTTP proxy or {@code null}
* if no global HTTP proxy is set.
*
* <p>This method requires the call to hold the permission
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
- * {@hide}
*/
- public ProxyProperties getGlobalProxy() {
+ public ProxyInfo getGlobalProxy() {
try {
return mService.getGlobalProxy();
} catch (RemoteException e) {
@@ -1343,14 +1341,14 @@
* Get the HTTP proxy settings for the current default network. Note that
* if a global proxy is set, it will override any per-network setting.
*
- * @return the {@link ProxyProperties} for the current HTTP proxy, or {@code null} if no
+ * @return the {@link ProxyInfo} for the current HTTP proxy, or {@code null} if no
* HTTP proxy is active.
*
* <p>This method requires the call to hold the permission
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
* {@hide}
*/
- public ProxyProperties getProxy() {
+ public ProxyInfo getProxy() {
try {
return mService.getProxy();
} catch (RemoteException e) {
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 381a817..d53a856 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -21,7 +21,7 @@
import android.net.NetworkInfo;
import android.net.NetworkQuotaInfo;
import android.net.NetworkState;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
import android.os.IBinder;
import android.os.Messenger;
import android.os.ParcelFileDescriptor;
@@ -107,11 +107,11 @@
void reportInetCondition(int networkType, int percentage);
- ProxyProperties getGlobalProxy();
+ ProxyInfo getGlobalProxy();
- void setGlobalProxy(in ProxyProperties p);
+ void setGlobalProxy(in ProxyInfo p);
- ProxyProperties getProxy();
+ ProxyInfo getProxy();
void setDataDependency(int networkType, boolean met);
diff --git a/core/java/android/net/INetworkScoreCache.aidl b/core/java/android/net/INetworkScoreCache.aidl
new file mode 100644
index 0000000..35601ce
--- /dev/null
+++ b/core/java/android/net/INetworkScoreCache.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 android.net;
+
+import android.net.ScoredNetwork;
+
+/**
+ * A service which stores a subset of scored networks from the active network scorer.
+ *
+ * <p>To be implemented by network subsystems (e.g. Wi-Fi). NetworkScoreService will propagate
+ * scores down to each subsystem depending on the network type. Implementations may register for
+ * a given network type by calling NetworkScoreManager.registerNetworkSubsystem.
+ *
+ * <p>A proper implementation should throw SecurityException whenever the caller is not privileged.
+ * It may request scores by calling NetworkScoreManager#requestScores(NetworkKey[]); a call to
+ * updateScores may follow but may not depending on the active scorer's implementation, and in
+ * general this method may be called at any time.
+ *
+ * <p>Implementations should also override dump() so that "adb shell dumpsys network_score" includes
+ * the current scores for each network for debugging purposes.
+ * @hide
+ */
+interface INetworkScoreCache
+{
+ void updateScores(in List<ScoredNetwork> networks);
+
+ void clearScores();
+}
+
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index a72d9a0..626bd2a 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -16,6 +16,7 @@
package android.net;
+import android.net.INetworkScoreCache;
import android.net.ScoredNetwork;
/**
@@ -34,8 +35,7 @@
/**
* Clear all scores.
* @return whether the clear was successful.
- * @throws SecurityException if the caller is neither the current active scorer nor the scorer
- * manager.
+ * @throws SecurityException if the caller is neither the current active scorer nor the system.
*/
boolean clearScores();
@@ -43,7 +43,19 @@
* Set the active scorer and clear existing scores.
* @param packageName the package name of the new scorer to use.
* @return true if the operation succeeded, or false if the new package is not a valid scorer.
- * @throws SecurityException if the caller is not the scorer manager.
+ * @throws SecurityException if the caller is not the system.
*/
boolean setActiveScorer(in String packageName);
+
+ /**
+ * Register a network subsystem for scoring.
+ *
+ * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
+ * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
+ * @throws SecurityException if the caller is not the system.
+ * @throws IllegalArgumentException if a score cache is already registed for this type.
+ * @hide
+ */
+ void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache);
+
}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 4dfd3d9..2dcc544 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -16,7 +16,7 @@
package android.net;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
import android.os.Parcelable;
import android.os.Parcel;
import android.text.TextUtils;
@@ -65,7 +65,7 @@
private ArrayList<InetAddress> mDnses = new ArrayList<InetAddress>();
private String mDomains;
private ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
- private ProxyProperties mHttpProxy;
+ private ProxyInfo mHttpProxy;
private int mMtu;
// Stores the properties of links that are "stacked" above this link.
@@ -101,7 +101,7 @@
mDomains = source.getDomains();
for (RouteInfo r : source.getRoutes()) mRoutes.add(r);
mHttpProxy = (source.getHttpProxy() == null) ?
- null : new ProxyProperties(source.getHttpProxy());
+ null : new ProxyInfo(source.getHttpProxy());
for (LinkProperties l: source.mStackedLinks.values()) {
addStackedLink(l);
}
@@ -295,10 +295,10 @@
return routes;
}
- public void setHttpProxy(ProxyProperties proxy) {
+ public void setHttpProxy(ProxyInfo proxy) {
mHttpProxy = proxy;
}
- public ProxyProperties getHttpProxy() {
+ public ProxyInfo getHttpProxy() {
return mHttpProxy;
}
@@ -720,7 +720,7 @@
netProp.addRoute((RouteInfo)in.readParcelable(null));
}
if (in.readByte() == 1) {
- netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
+ netProp.setHttpProxy((ProxyInfo)in.readParcelable(null));
}
ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
in.readList(stackedLinks, LinkProperties.class.getClassLoader());
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 6dd56d9..352512e 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -19,6 +19,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
+import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -101,7 +102,7 @@
* determine the current scorer and offer the user the ability to select a different scorer via
* the {@link #ACTION_CHANGE_ACTIVE} intent.
* @return the full package name of the current active scorer, or null if there is no active
- * scorer.
+ * scorer.
*/
public String getActiveScorerPackage() {
return NetworkScorerAppManager.getActiveScorer(mContext);
@@ -151,8 +152,8 @@
*
* @return true if the operation succeeded, or false if the new package is not a valid scorer.
* @throws SecurityException if the caller does not hold the
- * {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission indicating that
- * it can manage scorer applications.
+ * {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission indicating
+ * that it can manage scorer applications.
* @hide
*/
public boolean setActiveScorer(String packageName) throws SecurityException {
@@ -162,4 +163,44 @@
return false;
}
}
+
+ /**
+ * Request scoring for networks.
+ *
+ * <p>Note that this is just a helper method to assemble the broadcast, and will run in the
+ * calling process.
+ *
+ * @return true if the broadcast was sent, or false if there is no active scorer.
+ * @throws SecurityException if the caller does not hold the
+ * {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission.
+ * @hide
+ */
+ public boolean requestScores(NetworkKey[] networks) throws SecurityException {
+ String activeScorer = getActiveScorerPackage();
+ if (activeScorer == null) {
+ return false;
+ }
+ Intent intent = new Intent(ACTION_SCORE_NETWORKS);
+ intent.setPackage(activeScorer);
+ intent.putExtra(EXTRA_NETWORKS_TO_SCORE, networks);
+ mContext.sendBroadcast(intent);
+ return true;
+ }
+
+ /**
+ * Register a network score cache.
+ *
+ * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
+ * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
+ * @throws SecurityException if the caller does not hold the
+ * {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission.
+ * @throws IllegalArgumentException if a score cache is already registered for this type.
+ * @hide
+ */
+ public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
+ try {
+ mService.registerNetworkScoreCache(networkType, scoreCache);
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java
index 033332c..8f41e85 100644
--- a/core/java/android/net/Proxy.java
+++ b/core/java/android/net/Proxy.java
@@ -19,6 +19,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
+import android.net.ProxyInfo;
import android.text.TextUtils;
import android.util.Log;
@@ -63,8 +64,11 @@
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
- /** {@hide} **/
- public static final String EXTRA_PROXY_INFO = "proxy";
+ /**
+ * Intent extra included with {@link #PROXY_CHANGE_ACTION} intents.
+ * It describes the new proxy being used (as a {@link ProxyInfo} object).
+ */
+ public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
/** @hide */
public static final int PROXY_VALID = 0;
@@ -114,24 +118,14 @@
*/
public static final java.net.Proxy getProxy(Context ctx, String url) {
String host = "";
- if (url != null) {
+ if ((url != null) && !isLocalHost(host)) {
URI uri = URI.create(url);
- host = uri.getHost();
- }
+ ProxySelector proxySelector = ProxySelector.getDefault();
- if (!isLocalHost(host)) {
- if (sConnectivityManager == null) {
- sConnectivityManager = (ConnectivityManager)ctx.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- }
- if (sConnectivityManager == null) return java.net.Proxy.NO_PROXY;
+ List<java.net.Proxy> proxyList = proxySelector.select(uri);
- ProxyProperties proxyProperties = sConnectivityManager.getProxy();
-
- if (proxyProperties != null) {
- if (!proxyProperties.isExcluded(host)) {
- return proxyProperties.makeProxy();
- }
+ if (proxyList.size() > 0) {
+ return proxyList.get(0);
}
}
return java.net.Proxy.NO_PROXY;
@@ -274,50 +268,8 @@
return PROXY_VALID;
}
- static class AndroidProxySelectorRoutePlanner
- extends org.apache.http.impl.conn.ProxySelectorRoutePlanner {
-
- private Context mContext;
-
- public AndroidProxySelectorRoutePlanner(SchemeRegistry schreg, ProxySelector prosel,
- Context context) {
- super(schreg, prosel);
- mContext = context;
- }
-
- @Override
- protected java.net.Proxy chooseProxy(List<java.net.Proxy> proxies, HttpHost target,
- HttpRequest request, HttpContext context) {
- return getProxy(mContext, target.getHostName());
- }
-
- @Override
- protected HttpHost determineProxy(HttpHost target, HttpRequest request,
- HttpContext context) {
- return getPreferredHttpHost(mContext, target.getHostName());
- }
-
- @Override
- public HttpRoute determineRoute(HttpHost target, HttpRequest request,
- HttpContext context) {
- HttpHost proxy = getPreferredHttpHost(mContext, target.getHostName());
- if (proxy == null) {
- return new HttpRoute(target);
- } else {
- return new HttpRoute(target, null, proxy, false);
- }
- }
- }
-
/** @hide */
- public static final HttpRoutePlanner getAndroidProxySelectorRoutePlanner(Context context) {
- AndroidProxySelectorRoutePlanner ret = new AndroidProxySelectorRoutePlanner(
- new SchemeRegistry(), ProxySelector.getDefault(), context);
- return ret;
- }
-
- /** @hide */
- public static final void setHttpProxySystemProperty(ProxyProperties p) {
+ public static final void setHttpProxySystemProperty(ProxyInfo p) {
String host = null;
String port = null;
String exclList = null;
@@ -325,8 +277,8 @@
if (p != null) {
host = p.getHost();
port = Integer.toString(p.getPort());
- exclList = p.getExclusionList();
- pacFileUrl = p.getPacFileUrl();
+ exclList = p.getExclusionListAsString();
+ pacFileUrl = p.getPacFileUrl().toString();
}
setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
}
diff --git a/core/java/android/net/ProxyProperties.aidl b/core/java/android/net/ProxyInfo.aidl
similarity index 95%
rename from core/java/android/net/ProxyProperties.aidl
rename to core/java/android/net/ProxyInfo.aidl
index 02ea15d..2c91960 100644
--- a/core/java/android/net/ProxyProperties.aidl
+++ b/core/java/android/net/ProxyInfo.aidl
@@ -17,5 +17,5 @@
package android.net;
-parcelable ProxyProperties;
+parcelable ProxyInfo;
diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyInfo.java
similarity index 61%
rename from core/java/android/net/ProxyProperties.java
rename to core/java/android/net/ProxyInfo.java
index 50f45e8..b40941f 100644
--- a/core/java/android/net/ProxyProperties.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -21,14 +21,23 @@
import android.os.Parcelable;
import android.text.TextUtils;
+import org.apache.http.client.HttpClient;
+
import java.net.InetSocketAddress;
+import java.net.URLConnection;
+import java.util.List;
import java.util.Locale;
/**
- * A container class for the http proxy info
- * @hide
+ * Describes a proxy configuration.
+ *
+ * Proxy configurations are already integrated within the Apache HTTP stack.
+ * So {@link URLConnection} and {@link HttpClient} will use them automatically.
+ *
+ * Other HTTP stacks will need to obtain the proxy info from
+ * {@link Proxy#PROXY_CHANGE_ACTION} broadcast as the extra {@link Proxy#EXTRA_PROXY_INFO}.
*/
-public class ProxyProperties implements Parcelable {
+public class ProxyInfo implements Parcelable {
private String mHost;
private int mPort;
@@ -36,32 +45,82 @@
private String[] mParsedExclusionList;
private String mPacFileUrl;
+ /**
+ *@hide
+ */
public static final String LOCAL_EXCL_LIST = "";
+ /**
+ *@hide
+ */
public static final int LOCAL_PORT = -1;
+ /**
+ *@hide
+ */
public static final String LOCAL_HOST = "localhost";
- public ProxyProperties(String host, int port, String exclList) {
+ /**
+ * Constructs a {@link ProxyInfo} object that points at a Direct proxy
+ * on the specified host and port.
+ */
+ public static ProxyInfo buildDirectProxy(String host, int port) {
+ return new ProxyInfo(host, port, null);
+ }
+
+ /**
+ * Constructs a {@link ProxyInfo} object that points at a Direct proxy
+ * on the specified host and port.
+ *
+ * The proxy will not be used to access any host in exclusion list, exclList.
+ *
+ * @param exclList Hosts to exclude using the proxy on connections for. These
+ * hosts can use wildcards such as *.example.com.
+ */
+ public static ProxyInfo buildDirectProxy(String host, int port, List<String> exclList) {
+ String[] array = exclList.toArray(new String[exclList.size()]);
+ return new ProxyInfo(host, port, TextUtils.join(",", array), array);
+ }
+
+ /**
+ * Construct a {@link ProxyInfo} that will download and run the PAC script
+ * at the specified URL.
+ */
+ public static ProxyInfo buildPacProxy(Uri pacUri) {
+ return new ProxyInfo(pacUri.toString());
+ }
+
+ /**
+ * Create a ProxyProperties that points at a HTTP Proxy.
+ * @hide
+ */
+ public ProxyInfo(String host, int port, String exclList) {
mHost = host;
mPort = port;
setExclusionList(exclList);
}
- public ProxyProperties(String pacFileUrl) {
+ /**
+ * Create a ProxyProperties that points at a PAC URL.
+ * @hide
+ */
+ public ProxyInfo(String pacFileUrl) {
mHost = LOCAL_HOST;
mPort = LOCAL_PORT;
setExclusionList(LOCAL_EXCL_LIST);
mPacFileUrl = pacFileUrl;
}
- // Only used in PacManager after Local Proxy is bound.
- public ProxyProperties(String pacFileUrl, int localProxyPort) {
+ /**
+ * Only used in PacManager after Local Proxy is bound.
+ * @hide
+ */
+ public ProxyInfo(String pacFileUrl, int localProxyPort) {
mHost = LOCAL_HOST;
mPort = localProxyPort;
setExclusionList(LOCAL_EXCL_LIST);
mPacFileUrl = pacFileUrl;
}
- private ProxyProperties(String host, int port, String exclList, String[] parsedExclList) {
+ private ProxyInfo(String host, int port, String exclList, String[] parsedExclList) {
mHost = host;
mPort = port;
mExclusionList = exclList;
@@ -70,16 +129,22 @@
}
// copy constructor instead of clone
- public ProxyProperties(ProxyProperties source) {
+ /**
+ * @hide
+ */
+ public ProxyInfo(ProxyInfo source) {
if (source != null) {
mHost = source.getHost();
mPort = source.getPort();
- mPacFileUrl = source.getPacFileUrl();
- mExclusionList = source.getExclusionList();
+ mPacFileUrl = source.mPacFileUrl;
+ mExclusionList = source.getExclusionListAsString();
mParsedExclusionList = source.mParsedExclusionList;
}
}
+ /**
+ * @hide
+ */
public InetSocketAddress getSocketAddress() {
InetSocketAddress inetSocketAddress = null;
try {
@@ -88,20 +153,46 @@
return inetSocketAddress;
}
- public String getPacFileUrl() {
- return mPacFileUrl;
+ /**
+ * Returns the URL of the current PAC script or null if there is
+ * no PAC script.
+ */
+ public Uri getPacFileUrl() {
+ if (TextUtils.isEmpty(mPacFileUrl)) {
+ return null;
+ }
+ return Uri.parse(mPacFileUrl);
}
+ /**
+ * When configured to use a Direct Proxy this returns the host
+ * of the proxy.
+ */
public String getHost() {
return mHost;
}
+ /**
+ * When configured to use a Direct Proxy this returns the port
+ * of the proxy
+ */
public int getPort() {
return mPort;
}
- // comma separated
- public String getExclusionList() {
+ /**
+ * When configured to use a Direct Proxy this returns the list
+ * of hosts for which the proxy is ignored.
+ */
+ public String[] getExclusionList() {
+ return mParsedExclusionList;
+ }
+
+ /**
+ * comma separated
+ * @hide
+ */
+ public String getExclusionListAsString() {
return mExclusionList;
}
@@ -111,33 +202,13 @@
if (mExclusionList == null) {
mParsedExclusionList = new String[0];
} else {
- String splitExclusionList[] = exclusionList.toLowerCase(Locale.ROOT).split(",");
- mParsedExclusionList = new String[splitExclusionList.length * 2];
- for (int i = 0; i < splitExclusionList.length; i++) {
- String s = splitExclusionList[i].trim();
- if (s.startsWith(".")) s = s.substring(1);
- mParsedExclusionList[i*2] = s;
- mParsedExclusionList[(i*2)+1] = "." + s;
- }
+ mParsedExclusionList = exclusionList.toLowerCase(Locale.ROOT).split(",");
}
}
- public boolean isExcluded(String url) {
- if (TextUtils.isEmpty(url) || mParsedExclusionList == null ||
- mParsedExclusionList.length == 0) return false;
-
- Uri u = Uri.parse(url);
- String urlDomain = u.getHost();
- if (urlDomain == null) return false;
- for (int i = 0; i< mParsedExclusionList.length; i+=2) {
- if (urlDomain.equals(mParsedExclusionList[i]) ||
- urlDomain.endsWith(mParsedExclusionList[i+1])) {
- return true;
- }
- }
- return false;
- }
-
+ /**
+ * @hide
+ */
public boolean isValid() {
if (!TextUtils.isEmpty(mPacFileUrl)) return true;
return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost,
@@ -145,6 +216,9 @@
mExclusionList == null ? "" : mExclusionList);
}
+ /**
+ * @hide
+ */
public java.net.Proxy makeProxy() {
java.net.Proxy proxy = java.net.Proxy.NO_PROXY;
if (mHost != null) {
@@ -179,17 +253,17 @@
@Override
public boolean equals(Object o) {
- if (!(o instanceof ProxyProperties)) return false;
- ProxyProperties p = (ProxyProperties)o;
+ if (!(o instanceof ProxyInfo)) return false;
+ 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)) {
return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort;
}
- if (!TextUtils.isEmpty(p.getPacFileUrl())) {
+ if (!TextUtils.isEmpty(p.mPacFileUrl)) {
return false;
}
- if (mExclusionList != null && !mExclusionList.equals(p.getExclusionList())) return false;
+ if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) return false;
if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) {
return false;
}
@@ -245,15 +319,15 @@
* Implement the Parcelable interface.
* @hide
*/
- public static final Creator<ProxyProperties> CREATOR =
- new Creator<ProxyProperties>() {
- public ProxyProperties createFromParcel(Parcel in) {
+ public static final Creator<ProxyInfo> CREATOR =
+ new Creator<ProxyInfo>() {
+ public ProxyInfo createFromParcel(Parcel in) {
String host = null;
int port = 0;
if (in.readByte() != 0) {
String url = in.readString();
int localPort = in.readInt();
- return new ProxyProperties(url, localPort);
+ return new ProxyInfo(url, localPort);
}
if (in.readByte() != 0) {
host = in.readString();
@@ -261,13 +335,13 @@
}
String exclList = in.readString();
String[] parsedExclList = in.readStringArray();
- ProxyProperties proxyProperties =
- new ProxyProperties(host, port, exclList, parsedExclList);
+ ProxyInfo proxyProperties =
+ new ProxyInfo(host, port, exclList, parsedExclList);
return proxyProperties;
}
- public ProxyProperties[] newArray(int size) {
- return new ProxyProperties[size];
+ public ProxyInfo[] newArray(int size) {
+ return new ProxyInfo[size];
}
};
}
diff --git a/core/java/android/net/RssiCurve.java b/core/java/android/net/RssiCurve.java
index 33e81c2..dd744d3 100644
--- a/core/java/android/net/RssiCurve.java
+++ b/core/java/android/net/RssiCurve.java
@@ -98,6 +98,27 @@
}
/**
+ * Lookup the score for a given RSSI value.
+ *
+ * @param rssi The RSSI to lookup. If the RSSI falls below the start of the curve, the score at
+ * the start of the curve will be returned. If it falls after the end of the curve, the
+ * score at the end of the curve will be returned.
+ * @return the score for the given RSSI.
+ */
+ public byte lookupScore(int rssi) {
+ int index = (rssi - start) / bucketWidth;
+
+ // Snap the index to the closest bucket if it falls outside the curve.
+ if (index < 0) {
+ index = 0;
+ } else if (index > rssiBuckets.length - 1) {
+ index = rssiBuckets.length - 1;
+ }
+
+ return rssiBuckets[index];
+ }
+
+ /**
* Determine if two RSSI curves are defined in the same way.
*
* <p>Note that two curves can be equivalent but defined differently, e.g. if one bucket in one
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 9e9820f..e78ce33 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -175,6 +175,8 @@
private static final String POWER_USE_ITEM_DATA = "pwi";
private static final String DISCHARGE_STEP_DATA = "dsd";
private static final String CHARGE_STEP_DATA = "csd";
+ private static final String DISCHARGE_TIME_REMAIN_DATA = "dtr";
+ private static final String CHARGE_TIME_REMAIN_DATA = "ctr";
private final StringBuilder mFormatBuilder = new StringBuilder(32);
private final Formatter mFormatter = new Formatter(mFormatBuilder);
@@ -909,6 +911,8 @@
*/
public abstract int getScreenOnCount(int which);
+ public abstract long getInteractiveTime(long elapsedRealtimeUs, int which);
+
public static final int SCREEN_BRIGHTNESS_DARK = 0;
public static final int SCREEN_BRIGHTNESS_DIM = 1;
public static final int SCREEN_BRIGHTNESS_MEDIUM = 2;
@@ -934,8 +938,6 @@
public abstract long getScreenBrightnessTime(int brightnessBin,
long elapsedRealtimeUs, int which);
- public abstract int getInputEventCount(int which);
-
/**
* Returns the time in microseconds that the phone has been on while the device was
* running on battery.
@@ -1569,6 +1571,7 @@
final long totalRealtime = computeRealtime(rawRealtime, which);
final long totalUptime = computeUptime(rawUptime, which);
final long screenOnTime = getScreenOnTime(rawRealtime, which);
+ final long interactiveTime = getInteractiveTime(rawRealtime, which);
final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
final long wifiOnTime = getWifiOnTime(rawRealtime, which);
final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
@@ -1637,8 +1640,8 @@
wifiRunningTime / 1000, bluetoothOnTime / 1000,
mobileRxTotalBytes, mobileTxTotalBytes, wifiRxTotalBytes, wifiTxTotalBytes,
fullWakeLockTimeTotal, partialWakeLockTimeTotal,
- getInputEventCount(which), getMobileRadioActiveTime(rawRealtime, which),
- getMobileRadioActiveAdjustedTime(which));
+ 0 /*legacy input event count*/, getMobileRadioActiveTime(rawRealtime, which),
+ getMobileRadioActiveAdjustedTime(which), interactiveTime / 1000);
// Dump screen brightness stats
Object[] args = new Object[NUM_SCREEN_BRIGHTNESS_BINS];
@@ -2011,6 +2014,7 @@
sb.append("realtime, ");
formatTimeMs(sb, totalUptime / 1000);
sb.append("uptime");
+ pw.println(sb.toString());
if (batteryTimeRemaining >= 0) {
sb.setLength(0);
sb.append(prefix);
@@ -2029,16 +2033,25 @@
pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss", getStartClockTime()).toString());
final long screenOnTime = getScreenOnTime(rawRealtime, which);
+ final long interactiveTime = getInteractiveTime(rawRealtime, which);
final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
final long wifiOnTime = getWifiOnTime(rawRealtime, which);
final long bluetoothOnTime = getBluetoothOnTime(rawRealtime, which);
sb.setLength(0);
sb.append(prefix);
+ sb.append(" Interactive: "); formatTimeMs(sb, interactiveTime / 1000);
+ sb.append("("); sb.append(formatRatioLocked(interactiveTime, whichBatteryRealtime));
+ sb.append(")");
+ pw.println(sb.toString());
+ sb.setLength(0);
+ sb.append(prefix);
sb.append(" Screen on: "); formatTimeMs(sb, screenOnTime / 1000);
sb.append("("); sb.append(formatRatioLocked(screenOnTime, whichBatteryRealtime));
sb.append(") "); sb.append(getScreenOnCount(which));
- sb.append("x, Input events: "); sb.append(getInputEventCount(which));
+ sb.append("x, Active phone call: "); formatTimeMs(sb, phoneOnTime / 1000);
+ sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime));
+ sb.append(")");
pw.println(sb.toString());
if (phoneOnTime != 0) {
sb.setLength(0);
@@ -2897,7 +2910,7 @@
}
}
if (!didWake && wakelockTag != null) {
- pw.print(longNames ? "wake_lock=" : "w=");
+ pw.print(longNames ? " wake_lock=" : ",w=");
if (longNames) {
UserHandle.formatUid(pw, wakelockTag.uid);
pw.print(":\"");
@@ -3076,7 +3089,7 @@
HISTORY_STATE2_DESCRIPTIONS, !checkin);
if (rec.wakeReasonTag != null) {
if (checkin) {
- pw.print(",Wr=");
+ pw.print(",wr=");
pw.print(rec.wakeReasonTag.poolIdx);
} else {
pw.print(" wake_reason=");
@@ -3423,8 +3436,21 @@
if (!filtering) {
dumpDurationSteps(pw, DISCHARGE_STEP_DATA, getDischargeStepDurationsArray(),
getNumDischargeStepDurations(), true);
+ String[] lineArgs = new String[1];
+ long timeRemaining = computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
+ if (timeRemaining >= 0) {
+ lineArgs[0] = Long.toString(timeRemaining);
+ dumpLine(pw, 0 /* uid */, "i" /* category */, DISCHARGE_TIME_REMAIN_DATA,
+ (Object[])lineArgs);
+ }
dumpDurationSteps(pw, CHARGE_STEP_DATA, getChargeStepDurationsArray(),
getNumChargeStepDurations(), true);
+ timeRemaining = computeChargeTimeRemaining(SystemClock.elapsedRealtime());
+ if (timeRemaining >= 0) {
+ lineArgs[0] = Long.toString(timeRemaining);
+ dumpLine(pw, 0 /* uid */, "i" /* category */, CHARGE_TIME_REMAIN_DATA,
+ (Object[])lineArgs);
+ }
}
if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
dumpCheckinLocked(context, pw, STATS_SINCE_CHARGED, -1);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index b6a872a..84639eb 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -91,7 +91,6 @@
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
-
public static final String DISALLOW_SHARE_LOCATION = "no_share_location";
/**
@@ -145,6 +144,96 @@
*/
public static final String DISALLOW_REMOVE_USER = "no_remove_user";
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from enabling or
+ * accessing debugging features. The default value is <code>false</code>.
+ * <p/>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from configuring VPN.
+ * The default value is <code>false</code>.
+ * <p/>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_VPN = "no_config_vpn";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from configuring Tethering
+ * & portable hotspots. The default value is <code>false</code>.
+ * <p/>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from factory resetting
+ * from Settings.
+ * The default value is <code>false</code>.
+ * <p>
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_FACTORY_RESET = "no_factory_reset";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from adding new users and
+ * profiles. The default value is <code>false</code>.
+ * <p>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_ADD_USER = "no_add_user";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from disabling application
+ * verification. The default value is <code>false</code>.
+ * <p>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String ENSURE_VERIFY_APPS = "ensure_verify_apps";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from configuring cell
+ * broadcasts. The default value is <code>false</code>.
+ * <p>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from configuring mobile
+ * networks. The default value is <code>false</code>.
+ * <p>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
+
+ /**
+ * Key for user restrictions. Specifies if a user is disallowed from configuring
+ * applications in Settings. The default value is <code>false</code>.
+ * <p>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_APPS = "no_config_apps";
+
/** @hide */
public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3;
/** @hide */
@@ -504,8 +593,7 @@
ArrayList<UserHandle> profiles = new ArrayList<UserHandle>();
List<UserInfo> users = new ArrayList<UserInfo>();
try {
- // TODO: Switch enabledOnly to true once client apps are updated
- users = mService.getProfiles(UserHandle.myUserId(), false /* enabledOnly */);
+ users = mService.getProfiles(UserHandle.myUserId(), true /* enabledOnly */);
} catch (RemoteException re) {
Log.w(TAG, "Could not get user list", re);
return null;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ab06230..e0ac60b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2838,6 +2838,8 @@
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SAVED_STATE);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED);
+ MOVED_TO_GLOBAL.add(Settings.Global.WIFI_ENHANCED_AUTO_JOIN);
+ MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NETWORK_SHOW_RSSI);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_ON);
MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED);
MOVED_TO_GLOBAL.add(Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON);
@@ -3480,6 +3482,12 @@
"lock_screen_appwidget_ids";
/**
+ * List of enrolled fingerprint identifiers (comma-delimited).
+ * @hide
+ */
+ public static final String USER_FINGERPRINT_IDS = "user_fingerprint_ids";
+
+ /**
* Id of the appwidget shown on the lock screen when appwidgets are disabled.
* @hide
*/
@@ -4395,6 +4403,13 @@
public static final String ANR_SHOW_BACKGROUND = "anr_show_background";
/**
+ * (Experimental). If nonzero, WebView uses data reduction proxy to save network
+ * bandwidth. Otherwise, WebView does not use data reduction proxy.
+ * @hide
+ */
+ public static final String WEBVIEW_DATA_REDUCTION_PROXY = "webview_data_reduction_proxy";
+
+ /**
* The {@link ComponentName} string of the service to be used as the voice recognition
* service.
*
@@ -5456,7 +5471,21 @@
public static final String WIFI_SUPPLICANT_SCAN_INTERVAL_MS =
"wifi_supplicant_scan_interval_ms";
- /**
+ /**
+ * whether frameworks handles wifi auto-join
+ * @hide
+ */
+ public static final String WIFI_ENHANCED_AUTO_JOIN =
+ "wifi_enhanced_auto_join";
+
+ /**
+ * whether settings show RSSI
+ * @hide
+ */
+ public static final String WIFI_NETWORK_SHOW_RSSI =
+ "wifi_network_show_rssi";
+
+ /**
* The interval in milliseconds to scan at supplicant when p2p is connected
* @hide
*/
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 2303d65..b02a79d 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -300,10 +300,6 @@
public void onDetachedFromWindow() {
}
- @Override
- public void onWindowDismissed() {
- }
-
/** {@inheritDoc} */
@Override
public void onPanelClosed(int featureId, Menu menu) {
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/service/fingerprint/FingerprintManager.java
new file mode 100644
index 0000000..0d14c59
--- /dev/null
+++ b/core/java/android/service/fingerprint/FingerprintManager.java
@@ -0,0 +1,200 @@
+/**
+ * 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.fingerprint;
+
+import android.app.ActivityManagerNative;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+/**
+ * A class that coordinates access to the fingerprint hardware.
+ */
+
+public class FingerprintManager {
+ private static final String TAG = "FingerprintManager";
+ protected static final boolean DEBUG = true;
+ private static final String FINGERPRINT_SERVICE_PACKAGE = "com.android.service.fingerprint";
+ private static final String FINGERPRINT_SERVICE_CLASS =
+ "com.android.service.fingerprint.FingerprintService";
+ private static final int MSG_ENROLL_RESULT = 100;
+ private static final int MSG_SCANNED = 101;
+ private static final int MSG_ERROR = 102;
+ private static final int MSG_REMOVED = 103;
+
+ public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10;
+ public static final int FINGERPRINT_ERROR = -1; // One of the error messages below.
+
+ // Progress messages.
+ public static final int FINGERPRINT_SCANNED = 1;
+ public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2;
+ public static final int FINGERPRINT_TEMPLATE_REMOVED = 4;
+
+ // Error messages. Must agree with fingerprint HAL definitions.
+ public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1;
+ public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2;
+ public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
+ public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
+
+ private IFingerprintService mService;
+ private FingerprintManagerReceiver mClientReceiver;
+
+ private Handler mHandler = new Handler() {
+ public void handleMessage(android.os.Message msg) {
+ if (mClientReceiver != null) {
+ switch(msg.what) {
+ case MSG_ENROLL_RESULT:
+ mClientReceiver.onEnrollResult(msg.arg1, msg.arg2);
+ break;
+ case MSG_SCANNED:
+ mClientReceiver.onScanned(msg.arg1, msg.arg2);
+ break;
+ case MSG_ERROR:
+ mClientReceiver.onError(msg.arg1);
+ break;
+ case MSG_REMOVED:
+ mClientReceiver.onRemoved(msg.arg1);
+ }
+ }
+ }
+ };
+
+ public FingerprintManager(Context context) {
+ // Connect to service...
+ Intent intent = new Intent();
+ intent.setClassName(FINGERPRINT_SERVICE_PACKAGE, FINGERPRINT_SERVICE_CLASS);
+ if (!context.bindServiceAsUser(intent, mFingerprintConnection,
+ Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF)) {
+ if (DEBUG) Log.v(TAG, "Can't bind to " + FINGERPRINT_SERVICE_CLASS);
+ }
+ }
+
+ private final ServiceConnection mFingerprintConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG) Log.v(TAG, "Connected to FingerprintService");
+ mService = IFingerprintService.Stub.asInterface(service);
+ try {
+ mService.startListening(mServiceReceiver, getCurrentUserId());
+ } catch (RemoteException e) {
+ if (DEBUG) Log.v(TAG, "Failed to set callback", e);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) Log.v(TAG, "Disconnected from FingerprintService");
+ mService = null;
+ }
+ };
+
+ private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
+
+ public void onEnrollResult(int fingerprintId, int remaining) {
+ mHandler.obtainMessage(MSG_ENROLL_RESULT, fingerprintId, remaining).sendToTarget();
+ }
+
+ public void onScanned(int fingerprintId, int confidence) {
+ mHandler.obtainMessage(MSG_SCANNED, fingerprintId, confidence)
+ .sendToTarget();;
+ }
+
+ public void onError(int error) {
+ mHandler.obtainMessage(MSG_ERROR, error, 0).sendToTarget();
+ }
+
+ public void onRemoved(int fingerprintId) {
+ mHandler.obtainMessage(MSG_REMOVED, fingerprintId, 0).sendToTarget();
+ }
+ };
+
+ /**
+ * Start the enrollment process. Timeout dictates how long to wait for the user to
+ * enroll a fingerprint.
+ *
+ * @param timeout
+ */
+ public void enroll(long timeout) {
+ if (mServiceReceiver == null) {
+ throw new IllegalStateException("enroll: Call registerCallback() first");
+ }
+ if (mService != null) try {
+ mService.enroll(timeout, getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception while enrolling: ", e);
+ }
+ }
+
+ /**
+ * Remove the given fingerprintId from the system. FingerprintId of 0 has special meaning
+ * which is to delete all fingerprint data for the current user. Use with caution.
+ * @param fingerprintId
+ */
+ public void remove(int fingerprintId) {
+ if (mService != null) try {
+ mService.remove(fingerprintId, getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e);
+ }
+ }
+
+ /**
+ * Starts listening for fingerprint events. When a finger is scanned or recognized, the
+ * client will be notified via the callback.
+ */
+ public void startListening(FingerprintManagerReceiver receiver) {
+ mClientReceiver = receiver;
+ if (mService != null) {
+ try {
+ mService.startListening(mServiceReceiver, getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in startListening(): ", e);
+ }
+ }
+ }
+
+ private int getCurrentUserId() {
+ try {
+ return ActivityManagerNative.getDefault().getCurrentUser().id;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get current user id\n");
+ return UserHandle.USER_NULL;
+ }
+ }
+
+ /**
+ * Stops the client from listening to fingerprint events.
+ */
+ public void stopListening() {
+ mClientReceiver = null;
+ if (mService != null) {
+ try {
+ mService.stopListening(getCurrentUserId());
+ } catch (RemoteException e) {
+ Log.v(TAG, "Remote exception in stopListening(): ", e);
+ }
+ } else {
+ Log.w(TAG, "stopListening(): Service not connected!");
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
new file mode 100644
index 0000000..34f1655
--- /dev/null
+++ b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
@@ -0,0 +1,59 @@
+package android.service.fingerprint;
+/**
+ * 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.
+ */
+
+public class FingerprintManagerReceiver {
+ /**
+ * Fingerprint enrollment progress update. Enrollment is considered complete if
+ * remaining hits 0 without {@link #onError(int)} being called.
+ *
+ * @param fingerprintId the fingerprint we're currently enrolling
+ * @param remaining the number of samples required to complete enrollment. It's up to
+ * the hardware to define what each step in enrollment means. Some hardware
+ * requires multiple samples of the same part of the finger. Others require sampling of
+ * different parts of the finger. The enrollment flow can use remaining to
+ * mean "step x" of the process or "just need another sample."
+ */
+ public void onEnrollResult(int fingerprintId, int remaining) { }
+
+ /**
+ * Fingerprint scan detected. Most clients will use this function to detect a fingerprint
+ *
+ * @param fingerprintId is the finger the hardware has detected.
+ * @param confidence from 0 (no confidence) to 65535 (high confidence). Fingerprint 0 has
+ * special meaning - the finger wasn't recognized.
+ */
+ public void onScanned(int fingerprintId, int confidence) { }
+
+ /**
+ * An error was detected during scan or enrollment. One of
+ * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE},
+ * {@link FingerprintManager#FINGERPRINT_ERROR_BAD_CAPTURE} or
+ * {@link FingerprintManager#FINGERPRINT_ERROR_TIMEOUT}
+ * {@link FingerprintManager#FINGERPRINT_ERROR_NO_SPACE}
+ *
+ * @param error one of the above error codes
+ */
+ public void onError(int error) { }
+
+ /**
+ * The given fingerprint template was successfully removed by the driver.
+ * See {@link FingerprintManager#remove(int)}
+ *
+ * @param fingerprintId id of template to remove.
+ */
+ public void onRemoved(int fingerprintId) { }
+}
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintService.java b/core/java/android/service/fingerprint/FingerprintService.java
new file mode 100644
index 0000000..c7fa7cd
--- /dev/null
+++ b/core/java/android/service/fingerprint/FingerprintService.java
@@ -0,0 +1,219 @@
+/**
+ * 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.fingerprint;
+
+import android.app.Service;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+
+/**
+ * A service to manage multiple clients that want to access the fingerprint HAL API.
+ * The service is responsible for maintaining a list of clients and dispatching all
+ * fingerprint -related events.
+ *
+ * @hide
+ */
+public class FingerprintService extends Service {
+ private final String TAG = FingerprintService.class.getSimpleName() +
+ "[" + getClass().getSimpleName() + "]";
+ private static final boolean DEBUG = true;
+ HashMap<IFingerprintServiceReceiver, ClientData> mClients =
+ new HashMap<IFingerprintServiceReceiver, ClientData>();
+
+ private static final int MSG_NOTIFY = 10;
+
+ Handler mHandler = new Handler() {
+ public void handleMessage(android.os.Message msg) {
+ switch (msg.what) {
+ case MSG_NOTIFY:
+ handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj);
+ break;
+
+ default:
+ Slog.w(TAG, "Unknown message:" + msg.what);
+ }
+ }
+ };
+
+ private static final int STATE_IDLE = 0;
+ private static final int STATE_LISTENING = 1;
+ private static final int STATE_ENROLLING = 2;
+ private static final int STATE_DELETING = 3;
+ private static final long MS_PER_SEC = 1000;
+
+ private static final class ClientData {
+ public IFingerprintServiceReceiver receiver;
+ int state;
+ int userId;
+ }
+
+ @Override
+ public final IBinder onBind(Intent intent) {
+ if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
+ return new FingerprintServiceWrapper();
+ }
+
+ // JNI methods to communicate from FingerprintManagerService to HAL
+ native int nativeEnroll(int timeout);
+ native int nativeRemove(int fingerprintId);
+
+ // JNI methods for communicating from HAL to clients
+ void notify(int msg, int arg1, int arg2) {
+ mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget();
+ }
+
+ void handleNotify(int msg, int arg1, int arg2) {
+ for (int i = 0; i < mClients.size(); i++) {
+ ClientData clientData = mClients.get(i);
+ switch (msg) {
+ case FingerprintManager.FINGERPRINT_ERROR: {
+ if (clientData.state != STATE_IDLE) {
+ // FINGERPRINT_ERROR_HW_UNAVAILABLE
+ // FINGERPRINT_ERROR_BAD_CAPTURE
+ // FINGERPRINT_ERROR_TIMEOUT
+ // FINGERPRINT_ERROR_NO_SPACE
+ final int error = arg1;
+ clientData.state = STATE_IDLE;
+ if (clientData.receiver != null) {
+ try {
+ clientData.receiver.onError(error);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ }
+ }
+ }
+ }
+ break;
+ case FingerprintManager.FINGERPRINT_SCANNED: {
+ final int fingerId = arg1;
+ final int confidence = arg2;
+ if (clientData.state == STATE_LISTENING && clientData.receiver != null) {
+ try {
+ clientData.receiver.onScanned(fingerId, confidence);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ }
+ }
+ break;
+ }
+ case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
+ if (clientData.state == STATE_ENROLLING) {
+ final int fingerId = arg1;
+ final int remaining = arg2;
+ if (remaining == 0) {
+ FingerprintUtils.addFingerprintIdForUser(fingerId,
+ getContentResolver(), clientData.userId);
+ clientData.state = STATE_IDLE; // Nothing left to do
+ }
+ if (clientData.receiver != null) {
+ try {
+ clientData.receiver.onEnrollResult(fingerId, remaining);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ }
+ }
+ }
+ break;
+ }
+ case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
+ int fingerId = arg1;
+ if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
+ if (clientData.state == STATE_DELETING) {
+ FingerprintUtils.removeFingerprintIdForUser(fingerId, getContentResolver(),
+ clientData.userId);
+ if (clientData.receiver != null) {
+ try {
+ clientData.receiver.onRemoved(fingerId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ int enroll(IFingerprintServiceReceiver receiver, long timeout, int userId) {
+ ClientData clientData = mClients.get(receiver);
+ if (clientData != null) {
+ if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ clientData.state = STATE_ENROLLING;
+ return nativeEnroll((int) (timeout / MS_PER_SEC));
+ }
+ return -1;
+ }
+
+ int remove(IFingerprintServiceReceiver receiver, int fingerId, int userId) {
+ ClientData clientData = mClients.get(receiver);
+ if (clientData != null) {
+ if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ clientData.state = STATE_DELETING;
+ // The fingerprint id will be removed when we get confirmation from the HAL
+ return nativeRemove(fingerId);
+ }
+ return -1;
+ }
+
+ void startListening(IFingerprintServiceReceiver receiver, int userId) {
+ ClientData clientData = new ClientData();
+ clientData.state = STATE_LISTENING;
+ clientData.receiver = receiver;
+ clientData.userId = userId;
+ mClients.put(receiver, clientData);
+ }
+
+ void stopListening(IFingerprintServiceReceiver receiver, int userId) {
+ ClientData clientData = mClients.get(receiver);
+ if (clientData != null) {
+ clientData.state = STATE_IDLE;
+ clientData.userId = -1;
+ clientData.receiver = null;
+ }
+ mClients.remove(receiver);
+ }
+
+ private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
+ IFingerprintServiceReceiver mReceiver;
+ public int enroll(long timeout, int userId) {
+ return mReceiver != null ? FingerprintService.this.enroll(mReceiver, timeout, userId)
+ : FingerprintManager.FINGERPRINT_ERROR_NO_RECEIVER;
+ }
+
+ public int remove(int fingerprintId, int userId) {
+ return FingerprintService.this.remove(mReceiver, fingerprintId, userId);
+ }
+
+ public void startListening(IFingerprintServiceReceiver receiver, int userId) {
+ mReceiver = receiver;
+ FingerprintService.this.startListening(receiver, userId);
+ }
+
+ public void stopListening(int userId) {
+ FingerprintService.this.stopListening(mReceiver, userId);
+ }
+ }
+}
diff --git a/core/java/android/service/fingerprint/FingerprintUtils.java b/core/java/android/service/fingerprint/FingerprintUtils.java
new file mode 100644
index 0000000..81a2aac
--- /dev/null
+++ b/core/java/android/service/fingerprint/FingerprintUtils.java
@@ -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.
+ */
+
+package android.service.fingerprint;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.Arrays;
+
+class FingerprintUtils {
+ private static final boolean DEBUG = true;
+ private static final String TAG = "FingerprintUtils";
+
+ public static int[] getFingerprintIdsForUser(ContentResolver res, int userId) {
+ String fingerIdsRaw = Settings.Secure.getStringForUser(res,
+ Settings.Secure.USER_FINGERPRINT_IDS, userId);
+
+ String[] fingerStringIds = fingerIdsRaw.replace("[","").replace("]","").split(", ");
+ int result[] = new int[fingerStringIds.length];
+ for (int i = 0; i < result.length; i++) {
+ try {
+ result[i] = Integer.decode(fingerStringIds[i]);
+ } catch (NumberFormatException e) {
+ if (DEBUG) Log.d(TAG, "Error when parsing finger id " + fingerStringIds[i]);
+ }
+ }
+ return result;
+ }
+
+ public static void addFingerprintIdForUser(int fingerId, ContentResolver res, int userId) {
+ int[] fingerIds = getFingerprintIdsForUser(res, userId);
+
+ // FingerId 0 has special meaning.
+ if (fingerId == 0) return;
+
+ // Don't allow dups
+ for (int i = 0; i < fingerIds.length; i++) {
+ if (fingerIds[i] == fingerId) return;
+ }
+ int[] newList = Arrays.copyOf(fingerIds, fingerIds.length + 1);
+ newList[fingerIds.length] = fingerId;
+ Settings.Secure.putStringForUser(res, Settings.Secure.USER_FINGERPRINT_IDS,
+ Arrays.toString(newList), userId);
+ }
+
+ public static boolean removeFingerprintIdForUser(int fingerId, ContentResolver res, int userId)
+ {
+ // FingerId 0 has special meaning. The HAL layer is supposed to remove each finger one
+ // at a time and invoke notify() for each fingerId. If we get called with 0 here, it means
+ // something bad has happened.
+ if (fingerId == 0) throw new IllegalStateException("Bad fingerId");
+
+ int[] fingerIds = getFingerprintIdsForUser(res, userId);
+ int[] resultIds = Arrays.copyOf(fingerIds, fingerIds.length);
+ int resultCount = 0;
+ for (int i = 0; i < fingerIds.length; i++) {
+ if (fingerId != fingerIds[i]) {
+ resultIds[resultCount++] = fingerIds[i];
+ }
+ }
+ if (resultCount > 0) {
+ Settings.Secure.putStringForUser(res, Settings.Secure.USER_FINGERPRINT_IDS,
+ Arrays.toString(Arrays.copyOf(resultIds, resultCount)), userId);
+ return true;
+ }
+ return false;
+ }
+
+};
+
diff --git a/core/java/android/service/fingerprint/IFingerprintService.aidl b/core/java/android/service/fingerprint/IFingerprintService.aidl
new file mode 100644
index 0000000..e92c20c
--- /dev/null
+++ b/core/java/android/service/fingerprint/IFingerprintService.aidl
@@ -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 android.service.fingerprint;
+
+import android.os.Bundle;
+import android.service.fingerprint.IFingerprintServiceReceiver;
+
+/**
+ * Communication channel from client to the fingerprint service.
+ * @hide
+ */
+interface IFingerprintService {
+ // Returns 0 if successfully started, -1 otherwise
+ int enroll(long timeout, int userId);
+
+ // Returns 0 if fingerprintId's template can be removed, -1 otherwise
+ int remove(int fingerprintId, int userId);
+
+ // Start listening for fingerprint events. This has the side effect of starting
+ // the hardware if not already started.
+ oneway void startListening(IFingerprintServiceReceiver receiver, int userId);
+
+ // Stops listening for fingerprints
+ oneway void stopListening(int userId);
+}
diff --git a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
new file mode 100644
index 0000000..4826b59
--- /dev/null
+++ b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.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.service.fingerprint;
+
+import android.os.Bundle;
+import android.os.UserHandle;
+
+/**
+ * Communication channel from the FingerprintService back to FingerprintManager.
+ * @hide
+ */
+oneway interface IFingerprintServiceReceiver {
+ void onEnrollResult(int fingerprintId, int remaining);
+ void onScanned(int fingerprintId, int confidence);
+ void onError(int error);
+ void onRemoved(int fingerprintId);
+}
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index 71e3166..aa724f0 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -41,16 +41,25 @@
public static final int FLAG_RELEVANT_ALWAYS = 1 << 1;
public final Uri id;
- public String caption;
- public int state;
- public int flags;
+ public final String summary;
+ public final String line1;
+ public final String line2;
+ public final int icon;
+ public final int state;
+ public final int flags;
- public Condition(Uri id, String caption, int state, int flags) {
+ public Condition(Uri id, String summary, String line1, String line2, int icon,
+ int state, int flags) {
if (id == null) throw new IllegalArgumentException("id is required");
- if (caption == null) throw new IllegalArgumentException("caption is required");
+ if (summary == null) throw new IllegalArgumentException("summary is required");
+ if (line1 == null) throw new IllegalArgumentException("line1 is required");
+ if (line2 == null) throw new IllegalArgumentException("line2 is required");
if (!isValidState(state)) throw new IllegalArgumentException("state is invalid: " + state);
this.id = id;
- this.caption = caption;
+ this.summary = summary;
+ this.line1 = line1;
+ this.line2 = line2;
+ this.icon = icon;
this.state = state;
this.flags = flags;
}
@@ -58,6 +67,9 @@
private Condition(Parcel source) {
this((Uri)source.readParcelable(Condition.class.getClassLoader()),
source.readString(),
+ source.readString(),
+ source.readString(),
+ source.readInt(),
source.readInt(),
source.readInt());
}
@@ -69,16 +81,22 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(id, 0);
- dest.writeString(caption);
+ dest.writeString(summary);
+ dest.writeString(line1);
+ dest.writeString(line2);
+ dest.writeInt(icon);
dest.writeInt(state);
- dest.writeInt(flags);
+ dest.writeInt(this.flags);
}
@Override
public String toString() {
return new StringBuilder(Condition.class.getSimpleName()).append('[')
.append("id=").append(id)
- .append(",caption=").append(caption)
+ .append(",summary=").append(summary)
+ .append(",line1=").append(line1)
+ .append(",line2=").append(line2)
+ .append(",icon=").append(icon)
.append(",state=").append(stateToString(state))
.append(",flags=").append(flags)
.append(']').toString();
@@ -92,20 +110,31 @@
throw new IllegalArgumentException("state is invalid: " + state);
}
+ public static String relevanceToString(int flags) {
+ final boolean now = (flags & FLAG_RELEVANT_NOW) != 0;
+ final boolean always = (flags & FLAG_RELEVANT_ALWAYS) != 0;
+ if (!now && !always) return "NONE";
+ if (now && always) return "NOW, ALWAYS";
+ return now ? "NOW" : "ALWAYS";
+ }
+
@Override
public boolean equals(Object o) {
if (!(o instanceof Condition)) return false;
if (o == this) return true;
final Condition other = (Condition) o;
return Objects.equals(other.id, id)
- && Objects.equals(other.caption, caption)
+ && Objects.equals(other.summary, summary)
+ && Objects.equals(other.line1, line1)
+ && Objects.equals(other.line2, line2)
+ && other.icon == icon
&& other.state == state
&& other.flags == flags;
}
@Override
public int hashCode() {
- return Objects.hash(id, caption, state, flags);
+ return Objects.hash(id, summary, line1, line2, icon, state, flags);
}
@Override
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 72720d1..e7cdc4e 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -87,7 +87,7 @@
}
private String key() {
- return pkg + '|' + id + '|' + tag + '|' + uid;
+ return user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid;
}
public void writeToParcel(Parcel out, int flags) {
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 925ddcf..846e292 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -16,6 +16,8 @@
package android.service.notification;
+import android.content.ComponentName;
+import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -25,6 +27,8 @@
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Objects;
/**
@@ -51,6 +55,10 @@
private static final String SLEEP_ATT_END_HR = "endHour";
private static final String SLEEP_ATT_END_MIN = "endMin";
+ private static final String CONDITION_TAG = "condition";
+ private static final String CONDITION_ATT_COMPONENT = "component";
+ private static final String CONDITION_ATT_ID = "id";
+
public boolean allowCalls;
public boolean allowMessages;
@@ -59,6 +67,8 @@
public int sleepStartMinute;
public int sleepEndHour;
public int sleepEndMinute;
+ public ComponentName[] conditionComponents;
+ public Uri[] conditionIds;
public ZenModeConfig() { }
@@ -72,6 +82,16 @@
sleepStartMinute = source.readInt();
sleepEndHour = source.readInt();
sleepEndMinute = source.readInt();
+ int len = source.readInt();
+ if (len > 0) {
+ conditionComponents = new ComponentName[len];
+ source.readTypedArray(conditionComponents, ComponentName.CREATOR);
+ }
+ len = source.readInt();
+ if (len > 0) {
+ conditionIds = new Uri[len];
+ source.readTypedArray(conditionIds, Uri.CREATOR);
+ }
}
@Override
@@ -88,6 +108,18 @@
dest.writeInt(sleepStartMinute);
dest.writeInt(sleepEndHour);
dest.writeInt(sleepEndMinute);
+ if (conditionComponents != null && conditionComponents.length > 0) {
+ dest.writeInt(conditionComponents.length);
+ dest.writeTypedArray(conditionComponents, 0);
+ } else {
+ dest.writeInt(0);
+ }
+ if (conditionIds != null && conditionIds.length > 0) {
+ dest.writeInt(conditionIds.length);
+ dest.writeTypedArray(conditionIds, 0);
+ } else {
+ dest.writeInt(0);
+ }
}
@Override
@@ -98,6 +130,10 @@
.append(",sleepMode=").append(sleepMode)
.append(",sleepStart=").append(sleepStartHour).append('.').append(sleepStartMinute)
.append(",sleepEnd=").append(sleepEndHour).append('.').append(sleepEndMinute)
+ .append(",conditionComponents=")
+ .append(conditionComponents == null ? null : TextUtils.join(",", conditionComponents))
+ .append(",conditionIds=")
+ .append(conditionIds == null ? null : TextUtils.join(",", conditionIds))
.append(']').toString();
}
@@ -112,13 +148,16 @@
&& other.sleepStartHour == sleepStartHour
&& other.sleepStartMinute == sleepStartMinute
&& other.sleepEndHour == sleepEndHour
- && other.sleepEndMinute == sleepEndMinute;
+ && other.sleepEndMinute == sleepEndMinute
+ && Objects.deepEquals(other.conditionComponents, conditionComponents)
+ && Objects.deepEquals(other.conditionIds, conditionIds);
}
@Override
public int hashCode() {
return Objects.hash(allowCalls, allowMessages, sleepMode, sleepStartHour,
- sleepStartMinute, sleepEndHour, sleepEndMinute);
+ sleepStartMinute, sleepEndHour, sleepEndMinute,
+ Arrays.hashCode(conditionComponents), Arrays.hashCode(conditionIds));
}
public boolean isValid() {
@@ -136,9 +175,18 @@
if (!ZEN_TAG.equals(tag)) return null;
final ZenModeConfig rt = new ZenModeConfig();
final int version = Integer.parseInt(parser.getAttributeValue(null, ZEN_ATT_VERSION));
+ final ArrayList<ComponentName> conditionComponents = new ArrayList<ComponentName>();
+ final ArrayList<Uri> conditionIds = new ArrayList<Uri>();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
tag = parser.getName();
- if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) return rt;
+ if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) {
+ if (!conditionComponents.isEmpty()) {
+ rt.conditionComponents = conditionComponents
+ .toArray(new ComponentName[conditionComponents.size()]);
+ rt.conditionIds = conditionIds.toArray(new Uri[conditionIds.size()]);
+ }
+ return rt;
+ }
if (type == XmlPullParser.START_TAG) {
if (ALLOW_TAG.equals(tag)) {
rt.allowCalls = safeBoolean(parser, ALLOW_ATT_CALLS, false);
@@ -155,10 +203,18 @@
rt.sleepStartMinute = isValidMinute(startMinute) ? startMinute : 0;
rt.sleepEndHour = isValidHour(endHour) ? endHour : 0;
rt.sleepEndMinute = isValidMinute(endMinute) ? endMinute : 0;
+ } else if (CONDITION_TAG.equals(tag)) {
+ final ComponentName component =
+ safeComponentName(parser, CONDITION_ATT_COMPONENT);
+ final Uri conditionId = safeUri(parser, CONDITION_ATT_ID);
+ if (component != null && conditionId != null) {
+ conditionComponents.add(component);
+ conditionIds.add(conditionId);
+ }
}
}
}
- return rt;
+ throw new IllegalStateException("Failed to reach END_DOCUMENT");
}
public void writeXml(XmlSerializer out) throws IOException {
@@ -180,6 +236,16 @@
out.attribute(null, SLEEP_ATT_END_MIN, Integer.toString(sleepEndMinute));
out.endTag(null, SLEEP_TAG);
+ if (conditionComponents != null && conditionIds != null
+ && conditionComponents.length == conditionIds.length) {
+ for (int i = 0; i < conditionComponents.length; i++) {
+ out.startTag(null, CONDITION_TAG);
+ out.attribute(null, CONDITION_ATT_COMPONENT,
+ conditionComponents[i].flattenToString());
+ out.attribute(null, CONDITION_ATT_ID, conditionIds[i].toString());
+ out.endTag(null, CONDITION_TAG);
+ }
+ }
out.endTag(null, ZEN_TAG);
}
@@ -203,6 +269,18 @@
return Integer.valueOf(val);
}
+ private static ComponentName safeComponentName(XmlPullParser parser, String att) {
+ final String val = parser.getAttributeValue(null, att);
+ if (TextUtils.isEmpty(val)) return null;
+ return ComponentName.unflattenFromString(val);
+ }
+
+ private static Uri safeUri(XmlPullParser parser, String att) {
+ final String val = parser.getAttributeValue(null, att);
+ if (TextUtils.isEmpty(val)) return null;
+ return Uri.parse(val);
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
index 7dbf66b..9f9c312 100644
--- a/core/java/android/service/voice/IVoiceInteractionSession.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -16,13 +16,14 @@
package android.service.voice;
-import android.os.Bundle;
-
-import com.android.internal.app.IVoiceInteractorCallback;
-import com.android.internal.app.IVoiceInteractorRequest;
+import android.content.Intent;
/**
* @hide
*/
-interface IVoiceInteractionSession {
+oneway interface IVoiceInteractionSession {
+ void taskStarted(in Intent intent, int taskId);
+ void taskFinished(in Intent intent, int taskId);
+ void closeSystemDialogs();
+ void destroy();
}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index d005890..e15489b 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -27,6 +27,19 @@
import android.os.ServiceManager;
import com.android.internal.app.IVoiceInteractionManagerService;
+/**
+ * Top-level service of the current global voice interactor, which is providing
+ * support for hotwording, the back-end of a {@link android.app.VoiceInteractor}, etc.
+ * The current VoiceInteractionService that has been selected by the user is kept
+ * always running by the system, to allow it to do things like listen for hotwords
+ * in the background to instigate voice interactions.
+ *
+ * <p>Because this service is always running, it should be kept as lightweight as
+ * possible. Heavy-weight operations (including showing UI) should be implemented
+ * in the associated {@link android.service.voice.VoiceInteractionSessionService} when
+ * an actual voice interaction is taking place, and that service should run in a
+ * separate process from this one.
+ */
public class VoiceInteractionService extends Service {
/**
* The {@link Intent} that must be declared as handled by the service.
@@ -51,11 +64,9 @@
IVoiceInteractionManagerService mSystemService;
- public void startVoiceActivity(Intent intent, Bundle sessionArgs) {
+ public void startSession(Bundle args) {
try {
- mSystemService.startVoiceActivity(intent,
- intent.resolveType(getContentResolver()),
- mInterface, sessionArgs);
+ mSystemService.startSession(mInterface, args);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 963b6b4..a83544d 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -16,7 +16,14 @@
package android.service.voice;
+import android.app.Dialog;
+import android.app.Instrumentation;
import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Region;
+import android.inputmethodservice.SoftInputWindow;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -25,16 +32,53 @@
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import com.android.internal.app.IVoiceInteractionManagerService;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.IVoiceInteractorCallback;
import com.android.internal.app.IVoiceInteractorRequest;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
-public abstract class VoiceInteractionSession {
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+public abstract class VoiceInteractionSession implements KeyEvent.Callback {
static final String TAG = "VoiceInteractionSession";
static final boolean DEBUG = true;
+ final Context mContext;
+ final HandlerCaller mHandlerCaller;
+
+ final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState();
+
+ IVoiceInteractionManagerService mSystemService;
+ IBinder mToken;
+
+ int mTheme = 0;
+ LayoutInflater mInflater;
+ TypedArray mThemeAttrs;
+ View mRootView;
+ FrameLayout mContentFrame;
+ SoftInputWindow mWindow;
+
+ boolean mInitialized;
+ boolean mWindowAdded;
+ boolean mWindowVisible;
+ boolean mWindowWasVisible;
+ boolean mInShowWindow;
+
+ final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>();
+
+ final Insets mTmpInsets = new Insets();
+ final int[] mTmpLocation = new int[2];
+
final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() {
@Override
public IVoiceInteractorRequest startConfirmation(String callingPackage,
@@ -71,6 +115,27 @@
};
final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() {
+ @Override
+ public void taskStarted(Intent intent, int taskId) {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_STARTED,
+ taskId, intent));
+ }
+
+ @Override
+ public void taskFinished(Intent intent, int taskId) {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_TASK_FINISHED,
+ taskId, intent));
+ }
+
+ @Override
+ public void closeSystemDialogs() {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_CLOSE_SYSTEM_DIALOGS));
+ }
+
+ @Override
+ public void destroy() {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DESTROY));
+ }
};
public static class Request {
@@ -129,38 +194,128 @@
static final int MSG_SUPPORTS_COMMANDS = 3;
static final int MSG_CANCEL = 4;
- final Context mContext;
- final HandlerCaller mHandlerCaller;
- final HandlerCaller.Callback mHandlerCallerCallback = new HandlerCaller.Callback() {
+ static final int MSG_TASK_STARTED = 100;
+ static final int MSG_TASK_FINISHED = 101;
+ static final int MSG_CLOSE_SYSTEM_DIALOGS = 102;
+ static final int MSG_DESTROY = 103;
+
+ class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
@Override
public void executeMessage(Message msg) {
- SomeArgs args = (SomeArgs)msg.obj;
+ SomeArgs args;
switch (msg.what) {
case MSG_START_CONFIRMATION:
+ args = (SomeArgs)msg.obj;
if (DEBUG) Log.d(TAG, "onConfirm: req=" + ((Request) args.arg2).mInterface
+ " prompt=" + args.arg3 + " extras=" + args.arg4);
onConfirm((Caller)args.arg1, (Request)args.arg2, (String)args.arg3,
(Bundle)args.arg4);
break;
case MSG_START_COMMAND:
+ args = (SomeArgs)msg.obj;
if (DEBUG) Log.d(TAG, "onCommand: req=" + ((Request) args.arg2).mInterface
+ " command=" + args.arg3 + " extras=" + args.arg4);
onCommand((Caller) args.arg1, (Request) args.arg2, (String) args.arg3,
(Bundle) args.arg4);
break;
case MSG_SUPPORTS_COMMANDS:
+ args = (SomeArgs)msg.obj;
if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg2);
args.arg1 = onGetSupportedCommands((Caller) args.arg1, (String[]) args.arg2);
break;
case MSG_CANCEL:
+ args = (SomeArgs)msg.obj;
if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request) args.arg1).mInterface);
onCancel((Request)args.arg1);
break;
+ case MSG_TASK_STARTED:
+ if (DEBUG) Log.d(TAG, "onTaskStarted: intent=" + msg.obj
+ + " taskId=" + msg.arg1);
+ onTaskStarted((Intent) msg.obj, msg.arg1);
+ break;
+ case MSG_TASK_FINISHED:
+ if (DEBUG) Log.d(TAG, "onTaskFinished: intent=" + msg.obj
+ + " taskId=" + msg.arg1);
+ onTaskFinished((Intent) msg.obj, msg.arg1);
+ break;
+ case MSG_CLOSE_SYSTEM_DIALOGS:
+ if (DEBUG) Log.d(TAG, "onCloseSystemDialogs");
+ onCloseSystemDialogs();
+ break;
+ case MSG_DESTROY:
+ if (DEBUG) Log.d(TAG, "doDestroy");
+ doDestroy();
+ break;
}
}
- };
- final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>();
+ @Override
+ public void onBackPressed() {
+ VoiceInteractionSession.this.onBackPressed();
+ }
+ }
+
+ final MyCallbacks mCallbacks = new MyCallbacks();
+
+ /**
+ * Information about where interesting parts of the input method UI appear.
+ */
+ public static final class Insets {
+ /**
+ * This is the top part of the UI that is the main content. It is
+ * used to determine the basic space needed, to resize/pan the
+ * application behind. It is assumed that this inset does not
+ * change very much, since any change will cause a full resize/pan
+ * of the application behind. This value is relative to the top edge
+ * of the input method window.
+ */
+ public int contentTopInsets;
+
+ /**
+ * This is the region of the UI that is touchable. It is used when
+ * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}.
+ * The region should be specified relative to the origin of the window frame.
+ */
+ public final Region touchableRegion = new Region();
+
+ /**
+ * Option for {@link #touchableInsets}: the entire window frame
+ * can be touched.
+ */
+ public static final int TOUCHABLE_INSETS_FRAME
+ = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
+
+ /**
+ * Option for {@link #touchableInsets}: the area inside of
+ * the content insets can be touched.
+ */
+ public static final int TOUCHABLE_INSETS_CONTENT
+ = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
+
+ /**
+ * Option for {@link #touchableInsets}: the region specified by
+ * {@link #touchableRegion} can be touched.
+ */
+ public static final int TOUCHABLE_INSETS_REGION
+ = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
+
+ /**
+ * Determine which area of the window is touchable by the user. May
+ * be one of: {@link #TOUCHABLE_INSETS_FRAME},
+ * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_REGION}.
+ */
+ public int touchableInsets;
+ }
+
+ final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
+ new ViewTreeObserver.OnComputeInternalInsetsListener() {
+ public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
+ onComputeInsets(mTmpInsets);
+ info.contentInsets.top = info.visibleInsets.top = mTmpInsets.contentTopInsets;
+ info.touchableRegion.set(mTmpInsets.touchableRegion);
+ info.setTouchableInsets(mTmpInsets.touchableInsets);
+ }
+ };
public VoiceInteractionSession(Context context) {
this(context, new Handler());
@@ -169,7 +324,7 @@
public VoiceInteractionSession(Context context, Handler handler) {
mContext = context;
mHandlerCaller = new HandlerCaller(context, handler.getLooper(),
- mHandlerCallerCallback, true);
+ mCallbacks, true);
}
Request findRequest(IVoiceInteractorCallback callback, boolean newRequest) {
@@ -188,6 +343,192 @@
}
}
+ void doCreate(IVoiceInteractionManagerService service, IBinder token, Bundle args) {
+ mSystemService = service;
+ mToken = token;
+ onCreate(args);
+ }
+
+ void doDestroy() {
+ if (mInitialized) {
+ mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
+ mInsetsComputer);
+ if (mWindowAdded) {
+ mWindow.dismiss();
+ mWindowAdded = false;
+ }
+ mInitialized = false;
+ }
+ }
+
+ void initViews() {
+ mInitialized = true;
+
+ mThemeAttrs = mContext.obtainStyledAttributes(android.R.styleable.VoiceInteractionSession);
+ mRootView = mInflater.inflate(
+ com.android.internal.R.layout.voice_interaction_session, null);
+ mRootView.setSystemUiVisibility(
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+ mWindow.setContentView(mRootView);
+ mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
+
+ mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content);
+ }
+
+ public void showWindow() {
+ if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
+ + " mWindowVisible=" + mWindowVisible);
+
+ if (mInShowWindow) {
+ Log.w(TAG, "Re-entrance in to showWindow");
+ return;
+ }
+
+ try {
+ mInShowWindow = true;
+ if (!mWindowVisible) {
+ mWindowVisible = true;
+ if (!mWindowAdded) {
+ mWindowAdded = true;
+ View v = onCreateContentView();
+ if (v != null) {
+ setContentView(v);
+ }
+ }
+ mWindow.show();
+ }
+ } finally {
+ mWindowWasVisible = true;
+ mInShowWindow = false;
+ }
+ }
+
+ public void hideWindow() {
+ if (mWindowVisible) {
+ mWindow.hide();
+ mWindowVisible = false;
+ }
+ }
+
+ /**
+ * You can call this to customize the theme used by your IME's window.
+ * This must be set before {@link #onCreate}, so you
+ * will typically call it in your constructor with the resource ID
+ * of your custom theme.
+ */
+ public void setTheme(int theme) {
+ if (mWindow != null) {
+ throw new IllegalStateException("Must be called before onCreate()");
+ }
+ mTheme = theme;
+ }
+
+ public void startVoiceActivity(Intent intent) {
+ if (mToken == null) {
+ throw new IllegalStateException("Can't call before onCreate()");
+ }
+ try {
+ int res = mSystemService.startVoiceActivity(mToken, intent,
+ intent.resolveType(mContext.getContentResolver()));
+ Instrumentation.checkStartActivityResult(res, intent);
+ } catch (RemoteException e) {
+ }
+ }
+
+ public LayoutInflater getLayoutInflater() {
+ return mInflater;
+ }
+
+ public Dialog getWindow() {
+ return mWindow;
+ }
+
+ public void finish() {
+ if (mToken == null) {
+ throw new IllegalStateException("Can't call before onCreate()");
+ }
+ hideWindow();
+ try {
+ mSystemService.finish(mToken);
+ } catch (RemoteException e) {
+ }
+ }
+
+ public void onCreate(Bundle args) {
+ mTheme = mTheme != 0 ? mTheme
+ : com.android.internal.R.style.Theme_DeviceDefault_VoiceInteractionSession;
+ mInflater = (LayoutInflater)mContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
+ mCallbacks, this, mDispatcherState, true);
+ mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+ initViews();
+ mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
+ mWindow.setToken(mToken);
+ }
+
+ public void onDestroy() {
+ }
+
+ public View onCreateContentView() {
+ return null;
+ }
+
+ public void setContentView(View view) {
+ mContentFrame.removeAllViews();
+ mContentFrame.addView(view, new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ }
+
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
+ return false;
+ }
+
+ public void onBackPressed() {
+ finish();
+ }
+
+ public void onCloseSystemDialogs() {
+ finish();
+ }
+
+ /**
+ * Compute the interesting insets into your UI. The default implementation
+ * uses the entire window frame as the insets. The default touchable
+ * insets are {@link Insets#TOUCHABLE_INSETS_FRAME}.
+ *
+ * @param outInsets Fill in with the current UI insets.
+ */
+ public void onComputeInsets(Insets outInsets) {
+ int[] loc = mTmpLocation;
+ View decor = getWindow().getWindow().getDecorView();
+ decor.getLocationInWindow(loc);
+ outInsets.contentTopInsets = loc[1];
+ outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_FRAME;
+ outInsets.touchableRegion.setEmpty();
+ }
+
+ public void onTaskStarted(Intent intent, int taskId) {
+ }
+
+ public void onTaskFinished(Intent intent, int taskId) {
+ finish();
+ }
+
public abstract boolean[] onGetSupportedCommands(Caller caller, String[] commands);
public abstract void onConfirm(Caller caller, Request request, String prompt, Bundle extras);
public abstract void onCommand(Caller caller, Request request, String command, Bundle extras);
diff --git a/core/java/android/service/voice/VoiceInteractionSessionService.java b/core/java/android/service/voice/VoiceInteractionSessionService.java
index 40e5bba..e793849 100644
--- a/core/java/android/service/voice/VoiceInteractionSessionService.java
+++ b/core/java/android/service/voice/VoiceInteractionSessionService.java
@@ -29,11 +29,15 @@
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
+/**
+ * An active voice interaction session, initiated by a {@link VoiceInteractionService}.
+ */
public abstract class VoiceInteractionSessionService extends Service {
static final int MSG_NEW_SESSION = 1;
IVoiceInteractionManagerService mSystemService;
+ VoiceInteractionSession mSession;
IVoiceInteractionSessionService mInterface = new IVoiceInteractionSessionService.Stub() {
public void newSession(IBinder token, Bundle args) {
@@ -73,9 +77,14 @@
}
void doNewSession(IBinder token, Bundle args) {
- VoiceInteractionSession session = onNewSession(args);
+ if (mSession != null) {
+ mSession.doDestroy();
+ mSession = null;
+ }
+ mSession = onNewSession(args);
try {
- mSystemService.deliverNewSession(token, session.mSession, session.mInteractor);
+ mSystemService.deliverNewSession(token, mSession.mSession, mSession.mInteractor);
+ mSession.doCreate(mSystemService, token, args);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/speech/tts/BlockingAudioTrack.java b/core/java/android/speech/tts/BlockingAudioTrack.java
index 186cb49..92bb0ac 100644
--- a/core/java/android/speech/tts/BlockingAudioTrack.java
+++ b/core/java/android/speech/tts/BlockingAudioTrack.java
@@ -83,7 +83,7 @@
mVolume = volume;
mPan = pan;
- mBytesPerFrame = getBytesPerFrame(mAudioFormat) * mChannelCount;
+ mBytesPerFrame = AudioFormat.getBytesPerSample(mAudioFormat) * mChannelCount;
mIsShortUtterance = false;
mAudioBufferSize = 0;
mBytesWritten = 0;
@@ -229,17 +229,6 @@
return audioTrack;
}
- private static int getBytesPerFrame(int audioFormat) {
- if (audioFormat == AudioFormat.ENCODING_PCM_8BIT) {
- return 1;
- } else if (audioFormat == AudioFormat.ENCODING_PCM_16BIT) {
- return 2;
- }
-
- return -1;
- }
-
-
private void blockUntilDone(AudioTrack audioTrack) {
if (mBytesWritten <= 0) {
return;
diff --git a/core/java/android/speech/tts/FileSynthesisCallback.java b/core/java/android/speech/tts/FileSynthesisCallback.java
index 717aeb6..d84f7f0 100644
--- a/core/java/android/speech/tts/FileSynthesisCallback.java
+++ b/core/java/android/speech/tts/FileSynthesisCallback.java
@@ -278,8 +278,7 @@
private ByteBuffer makeWavHeader(int sampleRateInHz, int audioFormat, int channelCount,
int dataLength) {
- // TODO: is AudioFormat.ENCODING_DEFAULT always the same as ENCODING_PCM_16BIT?
- int sampleSizeInBytes = (audioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
+ int sampleSizeInBytes = AudioFormat.getBytesPerSample(audioFormat);
int byteRate = sampleRateInHz * sampleSizeInBytes * channelCount;
short blockAlign = (short) (sampleSizeInBytes * channelCount);
short bitsPerSample = (short) (sampleSizeInBytes * 8);
diff --git a/core/java/android/transition/MoveImage.java b/core/java/android/transition/MoveImage.java
index e4c3939..183cdd2 100644
--- a/core/java/android/transition/MoveImage.java
+++ b/core/java/android/transition/MoveImage.java
@@ -125,7 +125,7 @@
Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX);
Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX);
- if (!startMatrix.equals(endMatrix)) {
+ if (startMatrix != null && !startMatrix.equals(endMatrix)) {
changes.add(PropertyValuesHolder.ofObject(MatrixClippedDrawable.MATRIX_PROPERTY,
new MatrixEvaluator(), startMatrix, endMatrix));
}
@@ -230,7 +230,9 @@
private static void expandClip(Rect bounds, Matrix matrix, Rect clip, Rect otherClip) {
RectF boundsF = new RectF(bounds);
- matrix.mapRect(boundsF);
+ if (matrix != null) {
+ matrix.mapRect(boundsF);
+ }
clip.left = expandMinDimension(boundsF.left, clip.left, otherClip.left);
clip.top = expandMinDimension(boundsF.top, clip.top, otherClip.top);
clip.right = expandMaxDimension(boundsF.right, clip.right, otherClip.right);
@@ -256,10 +258,20 @@
int drawableWidth = drawable.getIntrinsicWidth();
int drawableHeight = drawable.getIntrinsicHeight();
ImageView.ScaleType scaleType = imageView.getScaleType();
- if (drawableWidth <= 0 || drawableHeight <= 0 || scaleType == ImageView.ScaleType.FIT_XY) {
- return null;
+ Matrix matrix;
+ if (drawableWidth <= 0 || drawableHeight <= 0) {
+ matrix = null;
+ } else if (scaleType == ImageView.ScaleType.FIT_XY) {
+ matrix = new Matrix();
+ float scaleX = imageView.getWidth();
+ scaleX /= drawableWidth;
+ float scaleY = imageView.getHeight();
+ scaleY /= drawableHeight;
+ matrix.setScale(scaleX, scaleY);
+ } else {
+ matrix = new Matrix(imageView.getImageMatrix());
}
- return new Matrix(imageView.getImageMatrix());
+ return matrix;
}
private Rect findClip(ImageView imageView) {
diff --git a/core/java/android/util/Range.java b/core/java/android/util/Range.java
new file mode 100644
index 0000000..9a4bd4b
--- /dev/null
+++ b/core/java/android/util/Range.java
@@ -0,0 +1,144 @@
+/*
+ * 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.util;
+
+import static com.android.internal.util.Preconditions.*;
+
+import android.hardware.camera2.impl.HashCodeHelpers;
+
+/**
+ * Immutable class for describing the range of two numeric values.
+ * <p>
+ * A range (or "interval") defines the inclusive boundaries around a contiguous span of
+ * values of some {@link Comparable} type; for example,
+ * "integers from 1 to 100 inclusive."
+ * </p>
+ * <p>
+ * All ranges are bounded, and the left side of the range is always {@code >=}
+ * the right side of the range.
+ * </p>
+ *
+ * <p>Although the implementation itself is immutable, there is no restriction that objects
+ * stored must also be immutable. If mutable objects are stored here, then the range
+ * effectively becomes mutable. </p>
+ */
+public final class Range<T extends Comparable<? super T>> {
+ /**
+ * Create a new immutable range.
+ *
+ * <p>
+ * The endpoints are {@code [lower, upper]}; that
+ * is the range is bounded. {@code lower} must be {@link Comparable#compareTo lesser or equal}
+ * to {@code upper}.
+ * </p>
+ *
+ * @param lower The lower endpoint (inclusive)
+ * @param upper The upper endpoint (inclusive)
+ *
+ * @throws NullPointerException if {@code lower} or {@code upper} is {@code null}
+ */
+ public Range(final T lower, final T upper) {
+ mLower = checkNotNull(lower, "lower must not be null");
+ mUpper = checkNotNull(upper, "upper must not be null");
+
+ if (lower.compareTo(upper) > 0) {
+ throw new IllegalArgumentException("lower must be less than or equal to upper");
+ }
+ }
+
+ /**
+ * Create a new immutable range, with the argument types inferred.
+ *
+ * <p>
+ * The endpoints are {@code [lower, upper]}; that
+ * is the range is bounded. {@code lower} must be {@link Comparable#compareTo lesser or equal}
+ * to {@code upper}.
+ * </p>
+ *
+ * @param lower The lower endpoint (inclusive)
+ * @param upper The upper endpoint (inclusive)
+ *
+ * @throws NullPointerException if {@code lower} or {@code upper} is {@code null}
+ */
+ public static <T extends Comparable<? super T>> Range<T> create(final T lower, final T upper) {
+ return new Range<T>(lower, upper);
+ }
+
+ /**
+ * Get the lower endpoint.
+ *
+ * @return a non-{@code null} {@code T} reference
+ */
+ public T getLower() {
+ return mLower;
+ }
+
+ /**
+ * Get the upper endpoint.
+ *
+ * @return a non-{@code null} {@code T} reference
+ */
+ public T getUpper() {
+ return mUpper;
+ }
+
+ /**
+ * Compare two ranges for equality.
+ *
+ * <p>A range is considered equal if and only if both the lower and upper endpoints
+ * are also equal.</p>
+ *
+ * @return {@code true} if the ranges are equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof Range) {
+ @SuppressWarnings("rawtypes")
+ final
+ Range other = (Range) obj;
+ return mLower.equals(other.mLower) && mUpper.equals(other.mUpper);
+ }
+ return false;
+ }
+
+ /**
+ * Return the range as a string representation {@code "[lower, upper]"}.
+ *
+ * @return string representation of the range
+ */
+ @Override
+ public String toString() {
+ return String.format("[%s, %s]", mLower, mUpper);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return HashCodeHelpers.hashCode(mLower, mUpper);
+ }
+
+ private final T mLower;
+ private final T mUpper;
+};
diff --git a/core/java/android/util/Size.java b/core/java/android/util/Size.java
new file mode 100644
index 0000000..ba1a35f
--- /dev/null
+++ b/core/java/android/util/Size.java
@@ -0,0 +1,98 @@
+/*
+ * 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.util;
+
+/**
+ * Immutable class for describing width and height dimensions in pixels.
+ */
+public final class Size {
+ /**
+ * Create a new immutable Size instance.
+ *
+ * @param width The width of the size, in pixels
+ * @param height The height of the size, in pixels
+ */
+ public Size(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ }
+
+ /**
+ * Get the width of the size (in pixels).
+ * @return width
+ */
+ public int getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * Get the height of the size (in pixels).
+ * @return height
+ */
+ public int getHeight() {
+ return mHeight;
+ }
+
+ /**
+ * Check if this size is equal to another size.
+ * <p>
+ * Two sizes are equal if and only if both their widths and heights are
+ * equal.
+ * </p>
+ * <p>
+ * A size object is never equal to any other type of object.
+ * </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 Size) {
+ Size other = (Size) obj;
+ return mWidth == other.mWidth && mHeight == other.mHeight;
+ }
+ return false;
+ }
+
+ /**
+ * Return the size represented as a string with the format {@code "WxH"}
+ *
+ * @return string representation of the size
+ */
+ @Override
+ public String toString() {
+ return mWidth + "x" + mHeight;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ // assuming most sizes are <2^16, doing a rotate will give us perfect hashing
+ return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
+ }
+
+ private final int mWidth;
+ private final int mHeight;
+};
diff --git a/core/java/android/util/SizeF.java b/core/java/android/util/SizeF.java
new file mode 100644
index 0000000..0a8b4ed
--- /dev/null
+++ b/core/java/android/util/SizeF.java
@@ -0,0 +1,108 @@
+/*
+ * 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.util;
+
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Immutable class for describing width and height dimensions in some arbitrary
+ * unit.
+ * <p>
+ * Width and height are finite values stored as a floating point representation.
+ * </p>
+ */
+public final class SizeF {
+ /**
+ * Create a new immutable SizeF instance.
+ *
+ * <p>Both the {@code width} and the {@code height} must be a finite number.
+ * In particular, {@code NaN} and positive/negative infinity are illegal values.</p>
+ *
+ * @param width The width of the size
+ * @param height The height of the size
+ *
+ * @throws IllegalArgumentException
+ * if either {@code width} or {@code height} was not finite.
+ */
+ public SizeF(final float width, final float height) {
+ mWidth = checkArgumentFinite(width, "width");
+ mHeight = checkArgumentFinite(height, "height");
+ }
+
+ /**
+ * Get the width of the size (as an arbitrary unit).
+ * @return width
+ */
+ public float getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * Get the height of the size (as an arbitrary unit).
+ * @return height
+ */
+ public float getHeight() {
+ return mHeight;
+ }
+
+ /**
+ * Check if this size is equal to another size.
+ *
+ * <p>Two sizes are equal if and only if both their widths and heights are the same.</p>
+ *
+ * <p>For this purpose, the width/height float values are considered to be the same if and only
+ * if the method {@link Float#floatToIntBits(float)} returns the identical {@code int} value
+ * when applied to each.</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 SizeF) {
+ final SizeF other = (SizeF) obj;
+ return mWidth == other.mWidth && mHeight == other.mHeight;
+ }
+ return false;
+ }
+
+ /**
+ * Return the size represented as a string with the format {@code "WxH"}
+ *
+ * @return string representation of the size
+ */
+ @Override
+ public String toString() {
+ return mWidth + "x" + mHeight;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return Float.floatToIntBits(mWidth) ^ Float.floatToIntBits(mHeight);
+ }
+
+ private final float mWidth;
+ private final float mHeight;
+};
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index f1523ae..0a76075 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -259,6 +259,14 @@
return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay;
}
+ /**
+ * @return The refresh rate as the nanoseconds between frames
+ * @hide
+ */
+ long getFrameIntervalNanos() {
+ return mFrameIntervalNanos;
+ }
+
void dump(String prefix, PrintWriter writer) {
String innerPrefix = prefix + " ";
writer.print(prefix); writer.println("Choreographer:");
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 5b2ce60..6c451eb 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -18,6 +18,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
import android.graphics.DrawFilter;
import android.graphics.Matrix;
import android.graphics.NinePatch;
@@ -262,27 +263,6 @@
private static native int nCallDrawGLFunction(long renderer, long drawGLFunction);
- @Override
- public int invokeFunctors(Rect dirty) {
- return nInvokeFunctors(mRenderer, dirty);
- }
-
- private static native int nInvokeFunctors(long renderer, Rect dirty);
-
- @Override
- public void detachFunctor(long functor) {
- nDetachFunctor(mRenderer, functor);
- }
-
- private static native void nDetachFunctor(long renderer, long functor);
-
- @Override
- public void attachFunctor(long functor) {
- nAttachFunctor(mRenderer, functor);
- }
-
- private static native void nAttachFunctor(long renderer, long functor);
-
///////////////////////////////////////////////////////////////////////////
// Memory
///////////////////////////////////////////////////////////////////////////
@@ -888,6 +868,16 @@
float radius, long paint);
@Override
+ public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
+ CanvasProperty<Float> radius, CanvasProperty<Paint> paint) {
+ nDrawCircle(mRenderer, cx.getNativeContainer(), cy.getNativeContainer(),
+ radius.getNativeContainer(), paint.getNativeContainer());
+ }
+
+ private static native void nDrawCircle(long renderer, long propCx,
+ long propCy, long propRadius, long propPaint);
+
+ @Override
public void drawColor(int color) {
drawColor(color, PorterDuff.Mode.SRC_OVER);
}
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index 2b29e5c..a94ec3a 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.NonNull;
import android.util.Pools.SynchronizedPool;
/**
@@ -32,19 +33,25 @@
private static final SynchronizedPool<GLES20RecordingCanvas> sPool =
new SynchronizedPool<GLES20RecordingCanvas>(POOL_LIMIT);
+ RenderNode mNode;
+
private GLES20RecordingCanvas() {
super(true, true);
}
- static GLES20RecordingCanvas obtain() {
+ static GLES20RecordingCanvas obtain(@NonNull RenderNode node) {
+ if (node == null) throw new IllegalArgumentException("node cannot be null");
+
GLES20RecordingCanvas canvas = sPool.acquire();
if (canvas == null) {
canvas = new GLES20RecordingCanvas();
}
+ canvas.mNode = node;
return canvas;
}
void recycle() {
+ mNode = null;
sPool.release(this);
}
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 97339cc..7b49006 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -168,7 +168,6 @@
private final Rect mRedrawClip = new Rect();
private final int[] mSurfaceSize = new int[2];
- private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
private long mDrawDelta = Long.MAX_VALUE;
@@ -654,6 +653,11 @@
}
@Override
+ void setOpaque(boolean opaque) {
+ // Not supported
+ }
+
+ @Override
boolean loadSystemProperties() {
boolean value;
boolean changed = false;
@@ -1116,22 +1120,6 @@
mName = name;
}
- class FunctorsRunnable implements Runnable {
- View.AttachInfo attachInfo;
-
- @Override
- public void run() {
- final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
- if (renderer == null || !renderer.isEnabled() || renderer != GLRenderer.this) {
- return;
- }
-
- if (checkRenderContext() != SURFACE_STATE_ERROR) {
- mCanvas.invokeFunctors(mRedrawClip);
- }
- }
- }
-
@Override
void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
Rect dirty) {
@@ -1366,23 +1354,6 @@
}
}
- @Override
- void detachFunctor(long functor) {
- if (mCanvas != null) {
- mCanvas.detachFunctor(functor);
- }
- }
-
- @Override
- void attachFunctor(View.AttachInfo attachInfo, long functor) {
- if (mCanvas != null) {
- mCanvas.attachFunctor(functor);
- mFunctorsRunnable.attachInfo = attachInfo;
- attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
- attachInfo.mHandler.postDelayed(mFunctorsRunnable, 0);
- }
- }
-
/**
* Ensures the current EGL context and surface are the ones we expect.
* This method throws an IllegalStateException if invoked from a thread
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index 233f846..9568760 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -18,6 +18,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.graphics.Rect;
@@ -110,45 +111,6 @@
}
/**
- * Invoke all the functors who requested to be invoked during the previous frame.
- *
- * @param dirty Ignored
- *
- * @return Ignored
- *
- * @hide
- */
- public int invokeFunctors(Rect dirty) {
- return RenderNode.STATUS_DONE;
- }
-
- /**
- * Detaches the specified functor from the current functor execution queue.
- *
- * @param functor The native functor to remove from the execution queue.
- *
- * @see #invokeFunctors(android.graphics.Rect)
- * @see #callDrawGLFunction(long)
- * @see #detachFunctor(long)
- *
- * @hide
- */
- abstract void detachFunctor(long functor);
-
- /**
- * Attaches the specified functor to the current functor execution queue.
- *
- * @param functor The native functor to add to the execution queue.
- *
- * @see #invokeFunctors(android.graphics.Rect)
- * @see #callDrawGLFunction(long)
- * @see #detachFunctor(long)
- *
- * @hide
- */
- abstract void attachFunctor(long functor);
-
- /**
* Indicates that the specified layer must be updated as soon as possible.
*
* @param layer The layer to update
@@ -189,4 +151,7 @@
* @hide
*/
abstract void clearLayerUpdates();
+
+ public abstract void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
+ CanvasProperty<Float> radius, CanvasProperty<Paint> paint);
}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index d31c79d..e366697 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -423,28 +423,6 @@
abstract boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap);
/**
- * Detaches the specified functor from the current functor execution queue.
- *
- * @param functor The native functor to remove from the execution queue.
- *
- * @see HardwareCanvas#callDrawGLFunction(int)
- * @see #attachFunctor(android.view.View.AttachInfo, long)
- */
- abstract void detachFunctor(long functor);
-
- /**
- * Schedules the specified functor in the functors execution queue.
- *
- * @param attachInfo AttachInfo tied to this renderer.
- * @param functor The native functor to insert in the execution queue.
- *
- * @see HardwareCanvas#callDrawGLFunction(int)
- * @see #detachFunctor(long)
- *
- */
- abstract void attachFunctor(View.AttachInfo attachInfo, long functor);
-
- /**
* Schedules the functor for execution in either kModeProcess or
* kModeProcessNoContext, depending on whether or not there is an EGLContext.
*
@@ -491,6 +469,11 @@
abstract void setName(String name);
/**
+ * Change the HardwareRenderer's opacity
+ */
+ abstract void setOpaque(boolean opaque);
+
+ /**
* Creates a hardware renderer using OpenGL.
*
* @param translucent True if the surface is translucent, false otherwise
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index e19bda9..b9ed801 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -21,13 +21,16 @@
import android.os.Message;
import android.os.Trace;
import android.widget.FrameLayout;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.Xml;
import java.io.IOException;
@@ -61,7 +64,8 @@
* @see Context#getSystemService
*/
public abstract class LayoutInflater {
- private final boolean DEBUG = false;
+ private static final String TAG = LayoutInflater.class.getSimpleName();
+ private static final boolean DEBUG = false;
/**
* This field should be made private, so it is hidden from the SDK.
@@ -395,8 +399,13 @@
* the inflated XML file.
*/
public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
- if (DEBUG) System.out.println("INFLATING from resource: " + resource);
- XmlResourceParser parser = getContext().getResources().getLayout(resource);
+ final Resources res = getContext().getResources();
+ if (DEBUG) {
+ Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+ + Integer.toHexString(resource) + ")");
+ }
+
+ final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 8b80c3e0..0cfde94 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -239,7 +239,7 @@
* @see #isValid()
*/
public HardwareCanvas start(int width, int height) {
- HardwareCanvas canvas = GLES20RecordingCanvas.obtain();
+ HardwareCanvas canvas = GLES20RecordingCanvas.obtain(this);
canvas.setViewport(width, height);
// The dirty rect should always be null for a display list
canvas.onPreDraw(null);
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index b70ae3d..a675821 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -16,6 +16,9 @@
package android.view;
+import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
+import android.graphics.Paint;
import android.util.SparseIntArray;
import java.lang.ref.WeakReference;
@@ -26,18 +29,22 @@
public final class RenderNodeAnimator {
// Keep in sync with enum RenderProperty in Animator.h
- private static final int TRANSLATION_X = 0;
- private static final int TRANSLATION_Y = 1;
- private static final int TRANSLATION_Z = 2;
- private static final int SCALE_X = 3;
- private static final int SCALE_Y = 4;
- private static final int ROTATION = 5;
- private static final int ROTATION_X = 6;
- private static final int ROTATION_Y = 7;
- private static final int X = 8;
- private static final int Y = 9;
- private static final int Z = 10;
- private static final int ALPHA = 11;
+ public static final int TRANSLATION_X = 0;
+ public static final int TRANSLATION_Y = 1;
+ public static final int TRANSLATION_Z = 2;
+ public static final int SCALE_X = 3;
+ public static final int SCALE_Y = 4;
+ public static final int ROTATION = 5;
+ public static final int ROTATION_X = 6;
+ public static final int ROTATION_Y = 7;
+ public static final int X = 8;
+ public static final int Y = 9;
+ public static final int Z = 10;
+ public static final int ALPHA = 11;
+
+ // Keep in sync with enum PaintFields in Animator.h
+ public static final int PAINT_STROKE_WIDTH = 0;
+ public static final int PAINT_ALPHA = 1;
// ViewPropertyAnimator uses a mask for its values, we need to remap them
// to the enum values here. RenderPropertyAnimator can't use the mask values
@@ -59,8 +66,8 @@
}};
// Keep in sync DeltaValueType in Animator.h
- private static final int DELTA_TYPE_ABSOLUTE = 0;
- private static final int DELTA_TYPE_DELTA = 1;
+ public static final int DELTA_TYPE_ABSOLUTE = 0;
+ public static final int DELTA_TYPE_DELTA = 1;
private RenderNode mTarget;
private long mNativePtr;
@@ -74,6 +81,19 @@
property, deltaType, deltaValue);
}
+ public RenderNodeAnimator(CanvasProperty<Float> property, int deltaType, float deltaValue) {
+ mNativePtr = nCreateCanvasPropertyFloatAnimator(
+ new WeakReference<RenderNodeAnimator>(this),
+ property.getNativeContainer(), deltaType, deltaValue);
+ }
+
+ public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField,
+ int deltaType, float deltaValue) {
+ mNativePtr = nCreateCanvasPropertyPaintAnimator(
+ new WeakReference<RenderNodeAnimator>(this),
+ property.getNativeContainer(), paintField, deltaType, deltaValue);
+ }
+
public void start(View target) {
mTarget = target.mRenderNode;
mTarget.addAnimator(this);
@@ -81,6 +101,15 @@
target.invalidateViewProperty(true, false);
}
+ public void start(Canvas canvas) {
+ if (!(canvas instanceof GLES20RecordingCanvas)) {
+ throw new IllegalArgumentException("Not a GLES20RecordingCanvas");
+ }
+ GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas;
+ mTarget = recordingCanvas.mNode;
+ mTarget.addAnimator(this);
+ }
+
public void cancel() {
mTarget.removeAnimator(this);
}
@@ -117,6 +146,10 @@
private static native long nCreateAnimator(WeakReference<RenderNodeAnimator> weakThis,
int property, int deltaValueType, float deltaValue);
+ private static native long nCreateCanvasPropertyFloatAnimator(WeakReference<RenderNodeAnimator> weakThis,
+ long canvasProperty, int deltaValueType, float deltaValue);
+ private static native long nCreateCanvasPropertyPaintAnimator(WeakReference<RenderNodeAnimator> weakThis,
+ long canvasProperty, int paintField, int deltaValueType, float deltaValue);
private static native void nSetDuration(long nativePtr, int duration);
private static native void nUnref(long nativePtr);
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 2d55a01..c15ce44 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -74,8 +74,10 @@
IBinder displayToken, int orientation,
int l, int t, int r, int b,
int L, int T, int R, int B);
- private static native boolean nativeGetDisplayInfo(
- IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo);
+ private static native SurfaceControl.PhysicalDisplayInfo[] nativeGetDisplayConfigs(
+ IBinder displayToken);
+ private static native int nativeGetActiveConfig(IBinder displayToken);
+ private static native boolean nativeSetActiveConfig(IBinder displayToken, int id);
private static native void nativeBlankDisplay(IBinder displayToken);
private static native void nativeUnblankDisplay(IBinder displayToken);
@@ -499,14 +501,25 @@
nativeBlankDisplay(displayToken);
}
- public static boolean getDisplayInfo(IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo) {
+ public static SurfaceControl.PhysicalDisplayInfo[] getDisplayConfigs(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- if (outInfo == null) {
- throw new IllegalArgumentException("outInfo must not be null");
+ return nativeGetDisplayConfigs(displayToken);
+ }
+
+ public static int getActiveConfig(IBinder displayToken) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
}
- return nativeGetDisplayInfo(displayToken, outInfo);
+ return nativeGetActiveConfig(displayToken);
+ }
+
+ public static boolean setActiveConfig(IBinder displayToken, int id) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+ return nativeSetActiveConfig(displayToken, id);
}
public static void setDisplayProjection(IBinder displayToken,
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 3cfe5e9..1765c43 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -23,7 +23,6 @@
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
-import android.os.Looper;
import android.util.AttributeSet;
import android.util.Log;
@@ -119,8 +118,6 @@
private boolean mUpdateLayer;
private boolean mUpdateSurface;
- private SurfaceTexture.OnFrameAvailableListener mUpdateListener;
-
private Canvas mCanvas;
private int mSaveCount;
@@ -370,21 +367,7 @@
mSurface.setDefaultBufferSize(getWidth(), getHeight());
nCreateNativeWindow(mSurface);
- mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
- @Override
- public void onFrameAvailable(SurfaceTexture surfaceTexture) {
- // Per SurfaceTexture's documentation, the callback may be invoked
- // from an arbitrary thread
- updateLayer();
-
- if (Looper.myLooper() == Looper.getMainLooper()) {
- invalidate();
- } else {
- postInvalidate();
- }
- }
- };
- mSurface.setOnFrameAvailableListener(mUpdateListener);
+ mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
if (mListener != null && !mUpdateSurface) {
mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
@@ -422,7 +405,7 @@
// To cancel updates, the easiest thing to do is simply to remove the
// updates listener
if (visibility == VISIBLE) {
- mSurface.setOnFrameAvailableListener(mUpdateListener);
+ mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
updateLayerAndInvalidate();
} else {
mSurface.setOnFrameAvailableListener(null);
@@ -767,6 +750,15 @@
mListener = listener;
}
+ private final SurfaceTexture.OnFrameAvailableListener mUpdateListener =
+ new SurfaceTexture.OnFrameAvailableListener() {
+ @Override
+ public void onFrameAvailable(SurfaceTexture surfaceTexture) {
+ updateLayer();
+ invalidate();
+ }
+ };
+
/**
* This listener can be used to be notified when the surface texture
* associated with this texture view is available.
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index eaec8ab..2587ba1 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -19,7 +19,6 @@
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
-import android.os.SystemClock;
import android.os.Trace;
import android.view.Surface.OutOfResourcesException;
import android.view.View.AttachInfo;
@@ -52,16 +51,29 @@
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;
+ // Needs a ViewRoot invalidate
+ private static final int SYNC_INVALIDATE_REQUIRED = 0x1;
+
private int mWidth, mHeight;
private long mNativeProxy;
private boolean mInitialized = false;
private RenderNode mRootNode;
+ private Choreographer mChoreographer;
ThreadedRenderer(boolean translucent) {
long rootNodePtr = nCreateRootRenderNode();
mRootNode = RenderNode.adopt(rootNodePtr);
mRootNode.setClipToBounds(false);
mNativeProxy = nCreateProxy(translucent, rootNodePtr);
+
+ // Setup timing
+ mChoreographer = Choreographer.getInstance();
+ nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
}
@Override
@@ -136,6 +148,11 @@
}
@Override
+ void setOpaque(boolean opaque) {
+ nSetOpaque(mNativeProxy, opaque);
+ }
+
+ @Override
int getWidth() {
return mWidth;
}
@@ -158,16 +175,7 @@
@Override
boolean loadSystemProperties() {
- return false;
- }
-
- /**
- * TODO: Remove
- * Temporary hack to allow RenderThreadTest prototype app to trigger
- * replaying a DisplayList after modifying the displaylist properties
- *
- * @hide */
- public void repeatLastDraw() {
+ return nLoadSystemProperties(mNativeProxy);
}
private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
@@ -194,7 +202,8 @@
@Override
void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
attachInfo.mIgnoreDirtyState = true;
- attachInfo.mDrawingTime = SystemClock.uptimeMillis();
+ long frameTimeNanos = mChoreographer.getFrameTimeNanos();
+ attachInfo.mDrawingTime = frameTimeNanos / NANOS_PER_MS;
updateRootDisplayList(view, callbacks);
@@ -203,17 +212,11 @@
if (dirty == null) {
dirty = NULL_RECT;
}
- nSyncAndDrawFrame(mNativeProxy, dirty.left, dirty.top, dirty.right, dirty.bottom);
- }
-
- @Override
- void detachFunctor(long functor) {
- // no-op, we never attach functors to need to detach them
- }
-
- @Override
- void attachFunctor(AttachInfo attachInfo, long functor) {
- invokeFunctor(functor, true);
+ int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
+ dirty.left, dirty.top, dirty.right, dirty.bottom);
+ if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
+ attachInfo.mViewRootImpl.invalidate();
+ }
}
@Override
@@ -297,13 +300,17 @@
private static native long nCreateProxy(boolean translucent, long rootRenderNode);
private static native void nDeleteProxy(long nativeProxy);
+ private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos);
+ private static native boolean nLoadSystemProperties(long nativeProxy);
+
private static native boolean nInitialize(long nativeProxy, Surface window);
private static native void nUpdateSurface(long nativeProxy, Surface window);
private static native void nPauseSurface(long nativeProxy, Surface window);
private static native void nSetup(long nativeProxy, int width, int height);
+ private static native void nSetOpaque(long nativeProxy, boolean opaque);
private static native void nSetDisplayListData(long nativeProxy, long displayList,
long newData);
- private static native void nSyncAndDrawFrame(long nativeProxy,
+ private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos,
int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
private static native void nDestroyCanvasAndSurface(long nativeProxy);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 85e3b3d..bef96b1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,7 +16,9 @@
package android.view;
+import android.animation.AnimatorInflater;
import android.animation.RevealAnimator;
+import android.animation.StateListAnimator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -667,6 +669,7 @@
* @attr ref android.R.styleable#View_scrollbarTrackVertical
* @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_soundEffectsEnabled
* @attr ref android.R.styleable#View_tag
@@ -3258,6 +3261,11 @@
private Outline mOutline;
/**
+ * Animator that automatically runs based on state changes.
+ */
+ private StateListAnimator mStateListAnimator;
+
+ /**
* When this view has focus and the next focus is {@link #FOCUS_LEFT},
* the user may specify which view to go to next.
*/
@@ -3995,6 +4003,10 @@
case R.styleable.View_nestedScrollingEnabled:
setNestedScrollingEnabled(a.getBoolean(attr, false));
break;
+ case R.styleable.View_stateListAnimator:
+ setStateListAnimator(AnimatorInflater.loadStateListAnimator(context,
+ a.getResourceId(attr, 0)));
+ break;
}
}
@@ -6147,12 +6159,12 @@
// call into it as a fallback in case we're in a class that overrides it
// and has logic to perform.
if (fitSystemWindows(insets.getSystemWindowInsets())) {
- return insets.cloneWithSystemWindowInsetsConsumed();
+ return insets.consumeSystemWindowInsets();
}
} else {
// We were called from within a direct call to fitSystemWindows.
if (fitSystemWindowsInt(insets.getSystemWindowInsets())) {
- return insets.cloneWithSystemWindowInsetsConsumed();
+ return insets.consumeSystemWindowInsets();
}
}
return insets;
@@ -9766,6 +9778,7 @@
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -9809,6 +9822,7 @@
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -9852,6 +9866,7 @@
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -9887,6 +9902,7 @@
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -9922,6 +9938,7 @@
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -9958,7 +9975,7 @@
* @attr ref android.R.styleable#View_transformPivotX
*/
public void setPivotX(float pivotX) {
- if (mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) {
+ if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) {
invalidateViewProperty(true, false);
mRenderNode.setPivotX(pivotX);
invalidateViewProperty(false, true);
@@ -9999,7 +10016,7 @@
* @attr ref android.R.styleable#View_transformPivotY
*/
public void setPivotY(float pivotY) {
- if (mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) {
+ if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) {
invalidateViewProperty(true, false);
mRenderNode.setPivotY(pivotY);
invalidateViewProperty(false, true);
@@ -10083,6 +10100,8 @@
mPrivateFlags &= ~PFLAG_ALPHA_SET;
invalidateViewProperty(true, false);
mRenderNode.setAlpha(getFinalAlpha());
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
}
}
@@ -10513,6 +10532,7 @@
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -10612,6 +10632,40 @@
}
/**
+ * Returns the current StateListAnimator if exists.
+ *
+ * @return StateListAnimator or null if it does not exists
+ * @see #setStateListAnimator(android.animation.StateListAnimator)
+ */
+ public StateListAnimator getStateListAnimator() {
+ return mStateListAnimator;
+ }
+
+ /**
+ * Attaches the provided StateListAnimator to this View.
+ * <p>
+ * Any previously attached StateListAnimator will be detached.
+ *
+ * @param stateListAnimator The StateListAnimator to update the view
+ * @see {@link android.animation.StateListAnimator}
+ */
+ public void setStateListAnimator(StateListAnimator stateListAnimator) {
+ if (mStateListAnimator == stateListAnimator) {
+ return;
+ }
+ if (mStateListAnimator != null) {
+ mStateListAnimator.setTarget(null);
+ }
+ mStateListAnimator = stateListAnimator;
+ if (stateListAnimator != null) {
+ stateListAnimator.setTarget(this);
+ if (isAttachedToWindow()) {
+ stateListAnimator.setState(getDrawableState());
+ }
+ }
+ }
+
+ /**
* Sets the outline of the view, which defines the shape of the shadow it
* casts.
* <p>
@@ -10661,6 +10715,7 @@
} else {
mRenderNode.setOutline(null);
}
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -10815,6 +10870,7 @@
}
invalidateParentIfNeeded();
}
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -10861,6 +10917,7 @@
}
invalidateParentIfNeeded();
}
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
@@ -12824,7 +12881,6 @@
destroyLayer(false);
cleanupDraw();
-
mCurrentAnimation = null;
}
@@ -15478,9 +15534,11 @@
/**
* This function is called whenever the state of the view changes in such
* a way that it impacts the state of drawables being shown.
- *
- * <p>Be sure to call through to the superclass when overriding this
- * function.
+ * <p>
+ * If the View has a StateListAnimator, it will also be called to run necessary state
+ * change animations.
+ * <p>
+ * Be sure to call through to the superclass when overriding this function.
*
* @see Drawable#setState(int[])
*/
@@ -15489,6 +15547,10 @@
if (d != null && d.isStateful()) {
d.setState(getDrawableState());
}
+
+ if (mStateListAnimator != null) {
+ mStateListAnimator.setState(getDrawableState());
+ }
}
/**
@@ -15633,11 +15695,17 @@
/**
* Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()}
* on all Drawable objects associated with this view.
+ * <p>
+ * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator
+ * attached to this view.
*/
public void jumpDrawablesToCurrentState() {
if (mBackground != null) {
mBackground.jumpToCurrentState();
}
+ if (mStateListAnimator != null) {
+ mStateListAnimator.jumpToCurrentState();
+ }
}
/**
@@ -17989,7 +18057,9 @@
*
* <p>If this property is set to true the view will be permitted to initiate nested
* scrolling operations with a compatible parent view in the current hierarchy. If this
- * view does not implement nested scrolling this will have no effect.</p>
+ * view does not implement nested scrolling this will have no effect. Disabling nested scrolling
+ * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping}
+ * the nested scroll.</p>
*
* @param enabled true to enable nested scrolling, false to disable
*
@@ -17999,6 +18069,7 @@
if (enabled) {
mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED;
} else {
+ stopNestedScroll();
mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED;
}
}
@@ -18138,23 +18209,29 @@
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
- int startX = 0;
- int startY = 0;
- if (offsetInWindow != null) {
- getLocationInWindow(offsetInWindow);
- startX = offsetInWindow[0];
- startY = offsetInWindow[1];
- }
+ if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) {
+ int startX = 0;
+ int startY = 0;
+ if (offsetInWindow != null) {
+ getLocationInWindow(offsetInWindow);
+ startX = offsetInWindow[0];
+ startY = offsetInWindow[1];
+ }
- mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed,
- dxUnconsumed, dyUnconsumed);
+ mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed,
+ dxUnconsumed, dyUnconsumed);
- if (offsetInWindow != null) {
- getLocationInWindow(offsetInWindow);
- offsetInWindow[0] -= startX;
- offsetInWindow[1] -= startY;
+ if (offsetInWindow != null) {
+ getLocationInWindow(offsetInWindow);
+ offsetInWindow[0] -= startX;
+ offsetInWindow[1] -= startY;
+ }
+ return true;
+ } else if (offsetInWindow != null) {
+ // No motion, no dispatch. Keep offsetInWindow up to date.
+ offsetInWindow[0] = 0;
+ offsetInWindow[1] = 0;
}
- return true;
}
return false;
}
@@ -18180,30 +18257,35 @@
*/
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
- int startX = 0;
- int startY = 0;
- if (offsetInWindow != null) {
- getLocationInWindow(offsetInWindow);
- startX = offsetInWindow[0];
- startY = offsetInWindow[1];
- }
-
- if (consumed == null) {
- if (mTempNestedScrollConsumed == null) {
- mTempNestedScrollConsumed = new int[2];
+ if (dx != 0 || dy != 0) {
+ int startX = 0;
+ int startY = 0;
+ if (offsetInWindow != null) {
+ getLocationInWindow(offsetInWindow);
+ startX = offsetInWindow[0];
+ startY = offsetInWindow[1];
}
- consumed = mTempNestedScrollConsumed;
- }
- consumed[0] = 0;
- consumed[1] = 0;
- mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed);
- if (offsetInWindow != null) {
- getLocationInWindow(offsetInWindow);
- offsetInWindow[0] -= startX;
- offsetInWindow[1] -= startY;
+ if (consumed == null) {
+ if (mTempNestedScrollConsumed == null) {
+ mTempNestedScrollConsumed = new int[2];
+ }
+ consumed = mTempNestedScrollConsumed;
+ }
+ consumed[0] = 0;
+ consumed[1] = 0;
+ mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed);
+
+ if (offsetInWindow != null) {
+ getLocationInWindow(offsetInWindow);
+ offsetInWindow[0] -= startX;
+ offsetInWindow[1] -= startY;
+ }
+ return consumed[0] != 0 || consumed[1] != 0;
+ } else if (offsetInWindow != null) {
+ offsetInWindow[0] = 0;
+ offsetInWindow[1] = 0;
}
- return consumed[0] != 0 || consumed[1] != 0;
}
return false;
}
@@ -18211,18 +18293,24 @@
/**
* Dispatch a fling to a nested scrolling parent.
*
- * <p>If a nested scrolling child view would normally fling but it is at the edge of its
- * own content it should use this method to delegate the fling to its nested scrolling parent.
- * The view implementation can use a {@link VelocityTracker} to obtain the velocity values
- * to pass.</p>
+ * <p>This method should be used to indicate that a nested scrolling child has detected
+ * suitable conditions for a fling. Generally this means that a touch scroll has ended with a
+ * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds
+ * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity}
+ * along a scrollable axis.</p>
+ *
+ * <p>If a nested scrolling child view would normally fling but it is at the edge of
+ * its own content, it can use this method to delegate the fling to its nested scrolling
+ * parent instead. The parent may optionally consume the fling or observe a child fling.</p>
*
* @param velocityX Horizontal fling velocity in pixels per second
* @param velocityY Vertical fling velocity in pixels per second
- * @return true if the nested scrolling parent consumed the fling
+ * @param consumed true if the child consumed the fling, false otherwise
+ * @return true if the nested scrolling parent consumed or otherwise reacted to the fling
*/
- public boolean dispatchNestedFling(float velocityX, float velocityY) {
+ public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
- return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY);
+ return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed);
}
return false;
}
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 5112b9a..4e91ad4 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -234,6 +234,7 @@
private final int mOverscrollDistance;
private final int mOverflingDistance;
private final boolean mFadingMarqueeEnabled;
+ private final long mGlobalActionsKeyTimeout;
private boolean sHasPermanentMenuKey;
private boolean sHasPermanentMenuKeySet;
@@ -261,6 +262,7 @@
mOverscrollDistance = OVERSCROLL_DISTANCE;
mOverflingDistance = OVERFLING_DISTANCE;
mFadingMarqueeEnabled = true;
+ mGlobalActionsKeyTimeout = GLOBAL_ACTIONS_KEY_TIMEOUT;
}
/**
@@ -287,8 +289,6 @@
mEdgeSlop = (int) (sizeAndDensity * EDGE_SLOP + 0.5f);
mFadingEdgeLength = (int) (sizeAndDensity * FADING_EDGE_LENGTH + 0.5f);
- mMinimumFlingVelocity = (int) (density * MINIMUM_FLING_VELOCITY + 0.5f);
- mMaximumFlingVelocity = (int) (density * MAXIMUM_FLING_VELOCITY + 0.5f);
mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f);
mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f);
mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
@@ -339,6 +339,13 @@
mPagingTouchSlop = mTouchSlop * 2;
mDoubleTapTouchSlop = mTouchSlop;
+
+ mMinimumFlingVelocity = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.config_viewMinFlingVelocity);
+ mMaximumFlingVelocity = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.config_viewMaxFlingVelocity);
+ mGlobalActionsKeyTimeout = res.getInteger(
+ com.android.internal.R.integer.config_globalActionsKeyTimeout);
}
/**
@@ -695,12 +702,26 @@
*
* @return how long a user needs to press the relevant key to bring up
* the global actions dialog.
+ * @deprecated This timeout should not be used by applications
*/
+ @Deprecated
public static long getGlobalActionKeyTimeout() {
return GLOBAL_ACTIONS_KEY_TIMEOUT;
}
/**
+ * The amount of time a user needs to press the relevant key to bring up
+ * the global actions dialog.
+ *
+ * @return how long a user needs to press the relevant key to bring up
+ * the global actions dialog.
+ * @hide
+ */
+ public long getDeviceGlobalActionKeyTimeout() {
+ return mGlobalActionsKeyTimeout;
+ }
+
+ /**
* The amount of friction applied to scrolls and flings.
*
* @return A scalar dimensionless value representing the coefficient of
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 8865ab4..4309366 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2342,7 +2342,6 @@
if (disallowIntercept) {
mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
- stopNestedScroll();
} else {
mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
}
@@ -4639,6 +4638,7 @@
if (invalidate) {
invalidateViewProperty(false, false);
}
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
/**
@@ -5914,7 +5914,7 @@
* @inheritDoc
*/
@Override
- public boolean onNestedFling(View target, float velocityX, float velocityY) {
+ public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
return false;
}
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 3cd6449..588b9cd 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -512,14 +512,21 @@
/**
* Request a fling from a nested scroll.
*
+ * <p>This method signifies that a nested scrolling child has detected suitable conditions
+ * for a fling. Generally this means that a touch scroll has ended with a
+ * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds
+ * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity}
+ * along a scrollable axis.</p>
+ *
* <p>If a nested scrolling child view would normally fling but it is at the edge of
- * its own content, it can delegate the fling to its nested scrolling parent instead.
- * This method allows the parent to optionally consume the fling.</p>
+ * its own content, it can use this method to delegate the fling to its nested scrolling
+ * parent instead. The parent may optionally consume the fling or observe a child fling.</p>
*
* @param target View that initiated the nested scroll
* @param velocityX Horizontal velocity in pixels per second.
* @param velocityY Vertical velocity in pixels per second
- * @return true if this parent consumed the fling
+ * @param consumed true if the child consumed the fling, false otherwise
+ * @return true if this parent consumed or otherwise reacted to the fling
*/
- public boolean onNestedFling(View target, float velocityX, float velocityY);
+ public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 14e422c..9b09d85 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -234,6 +234,7 @@
InputStage mFirstInputStage;
InputStage mFirstPostImeInputStage;
+ InputStage mSyntheticInputStage;
boolean mWindowAttributesChanged = false;
int mWindowAttributesChangesFlag = 0;
@@ -599,8 +600,8 @@
// Set up the input pipeline.
CharSequence counterSuffix = attrs.getTitle();
- InputStage syntheticInputStage = new SyntheticInputStage();
- InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticInputStage);
+ mSyntheticInputStage = new SyntheticInputStage();
+ InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
@@ -664,18 +665,9 @@
mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG_FLUSH_LAYER_UPDATES));
}
- public void attachFunctor(long functor) {
- //noinspection SimplifiableIfStatement
- if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
- mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
- }
- }
-
public void detachFunctor(long functor) {
+ // TODO: Make the resize buffer some other way to not need this block
mBlockResizeBuffer = true;
- if (mAttachInfo.mHardwareRenderer != null) {
- mAttachInfo.mHardwareRenderer.detachFunctor(functor);
- }
}
public boolean invokeFunctor(long functor, boolean waitForCompletion) {
@@ -718,12 +710,15 @@
if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
&& forceHwAccelerated)) {
- // Don't enable hardware acceleration when we're not on the main thread
- if (!HardwareRenderer.sSystemRendererDisabled &&
- Looper.getMainLooper() != Looper.myLooper()) {
- Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
- + "acceleration outside of the main thread, aborting");
- return;
+ if (!HardwareRenderer.sUseRenderThread) {
+ // TODO: Delete
+ // Don't enable hardware acceleration when we're not on the main thread
+ if (!HardwareRenderer.sSystemRendererDisabled &&
+ Looper.getMainLooper() != Looper.myLooper()) {
+ Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
+ + "acceleration outside of the main thread, aborting");
+ return;
+ }
}
if (mAttachInfo.mHardwareRenderer != null) {
@@ -2587,10 +2582,6 @@
* @param canvas The canvas on which to draw.
*/
private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
- if (!mAttachInfo.mHasWindowFocus) {
- return;
- }
-
final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
return;
@@ -3007,6 +2998,7 @@
private final static int MSG_INVALIDATE_WORLD = 23;
private final static int MSG_WINDOW_MOVED = 24;
private final static int MSG_FLUSH_LAYER_UPDATES = 25;
+ private final static int MSG_SYNTHESIZE_INPUT_EVENT = 26;
final class ViewRootHandler extends Handler {
@Override
@@ -3056,6 +3048,8 @@
return "MSG_WINDOW_MOVED";
case MSG_FLUSH_LAYER_UPDATES:
return "MSG_FLUSH_LAYER_UPDATES";
+ case MSG_SYNTHESIZE_INPUT_EVENT:
+ return "MSG_SYNTHESIZE_INPUT_EVENT";
}
return super.getMessageName(message);
}
@@ -3218,6 +3212,10 @@
enqueueInputEvent(event, receiver, 0, true);
args.recycle();
} break;
+ case MSG_SYNTHESIZE_INPUT_EVENT: {
+ InputEvent event = (InputEvent)msg.obj;
+ enqueueInputEvent(event, null, QueuedInputEvent.FLAG_UNHANDLED, true);
+ } break;
case MSG_DISPATCH_KEY_FROM_IME: {
if (LOCAL_LOGV) Log.v(
TAG, "Dispatching key "
@@ -3227,7 +3225,8 @@
// The IME is trying to say this event is from the
// system! Bad bad bad!
//noinspection UnusedAssignment
- event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
+ event = KeyEvent.changeFlags(event, event.getFlags() &
+ ~KeyEvent.FLAG_FROM_SYSTEM);
}
enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
} break;
@@ -4023,6 +4022,7 @@
private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
private final SyntheticTouchNavigationHandler mTouchNavigation =
new SyntheticTouchNavigationHandler();
+ private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler();
public SyntheticInputStage() {
super(null);
@@ -4045,7 +4045,11 @@
mTouchNavigation.process(event);
return FINISH_HANDLED;
}
+ } else if ((q.mFlags & QueuedInputEvent.FLAG_UNHANDLED) != 0) {
+ mKeyboard.process((KeyEvent)q.mEvent);
+ return FINISH_HANDLED;
}
+
return FORWARD;
}
@@ -4882,6 +4886,33 @@
};
}
+ final class SyntheticKeyboardHandler {
+ public void process(KeyEvent event) {
+ if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
+ return;
+ }
+
+ final KeyCharacterMap kcm = event.getKeyCharacterMap();
+ final int keyCode = event.getKeyCode();
+ final int metaState = event.getMetaState();
+
+ // Check for fallback actions specified by the key character map.
+ KeyCharacterMap.FallbackAction fallbackAction =
+ kcm.getFallbackAction(keyCode, metaState);
+ if (fallbackAction != null) {
+ final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
+ KeyEvent fallbackEvent = KeyEvent.obtain(
+ event.getDownTime(), event.getEventTime(),
+ event.getAction(), fallbackAction.keyCode,
+ event.getRepeatCount(), fallbackAction.metaState,
+ event.getDeviceId(), event.getScanCode(),
+ flags, event.getSource(), null);
+ fallbackAction.recycle();
+ enqueueInputEvent(fallbackEvent);
+ }
+ }
+ }
+
/**
* Returns true if the key is used for keyboard navigation.
* @param keyEvent The key event.
@@ -5461,6 +5492,7 @@
public static final int FLAG_FINISHED = 1 << 2;
public static final int FLAG_FINISHED_HANDLED = 1 << 3;
public static final int FLAG_RESYNTHESIZED = 1 << 4;
+ public static final int FLAG_UNHANDLED = 1 << 5;
public QueuedInputEvent mNext;
@@ -5475,6 +5507,14 @@
return mEvent instanceof MotionEvent
&& mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
}
+
+ public boolean shouldSendToSynthesizer() {
+ if ((mFlags & FLAG_UNHANDLED) != 0) {
+ return true;
+ }
+
+ return false;
+ }
}
private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
@@ -5578,7 +5618,13 @@
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
- InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
+ InputStage stage;
+ if (q.shouldSendToSynthesizer()) {
+ stage = mSyntheticInputStage;
+ } else {
+ stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
+ }
+
if (stage != null) {
stage.deliver(q);
} else {
@@ -5810,43 +5856,29 @@
mHandler.sendMessage(msg);
}
+ public void synthesizeInputEvent(InputEvent event) {
+ Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, event);
+ msg.setAsynchronous(true);
+ mHandler.sendMessage(msg);
+ }
+
public void dispatchKeyFromIme(KeyEvent event) {
Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
- public void dispatchUnhandledKey(KeyEvent event) {
- if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
- // Some fallback keys are decided by the ViewRoot as they might have special
- // properties (e.g. are locale aware). These take precedence over fallbacks defined by
- // the kcm.
- final KeyCharacterMap kcm = event.getKeyCharacterMap();
- final int keyCode = event.getKeyCode();
- final int metaState = event.getMetaState();
-
- // Check for fallback actions specified by the key character map.
- KeyCharacterMap.FallbackAction fallbackAction =
- kcm.getFallbackAction(keyCode, metaState);
- if (fallbackAction != null) {
- final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
- KeyEvent fallbackEvent = KeyEvent.obtain(
- event.getDownTime(), event.getEventTime(),
- event.getAction(), fallbackAction.keyCode,
- event.getRepeatCount(), fallbackAction.metaState,
- event.getDeviceId(), event.getScanCode(),
- flags, event.getSource(), null);
- fallbackAction.recycle();
- dispatchInputEvent(fallbackEvent);
- }
- }
- }
-
+ /**
+ * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
+ *
+ * Note that it is the responsibility of the caller of this API to recycle the InputEvent it
+ * passes in.
+ */
public void dispatchUnhandledInputEvent(InputEvent event) {
- if (event instanceof KeyEvent) {
- dispatchUnhandledKey((KeyEvent) event);
- return;
+ if (event instanceof MotionEvent) {
+ event = MotionEvent.obtain((MotionEvent) event);
}
+ synthesizeInputEvent(event);
}
public void dispatchAppVisibility(boolean visible) {
@@ -6131,13 +6163,15 @@
}
@Override
- public boolean onNestedFling(View target, float velocityX, float velocityY) {
+ public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
return false;
}
void changeCanvasOpacity(boolean opaque) {
- // TODO(romainguy): recreate Canvas (software or hardware) to reflect the opacity change.
Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
+ if (mAttachInfo.mHardwareRenderer != null) {
+ mAttachInfo.mHardwareRenderer.setOpaque(opaque);
+ }
}
class TakenSurfaceHolder extends BaseSurfaceHolder {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 9c44bd1..375f5e3 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -147,6 +147,7 @@
private TypedArray mWindowStyle;
private Callback mCallback;
+ private OnWindowDismissedCallback mOnWindowDismissedCallback;
private WindowManager mWindowManager;
private IBinder mAppToken;
private String mAppName;
@@ -405,7 +406,10 @@
* @param mode The mode that was just finished.
*/
public void onActionModeFinished(ActionMode mode);
+ }
+ /** @hide */
+ public interface OnWindowDismissedCallback {
/**
* Called when a window is dismissed. This informs the callback that the
* window is gone, and it should finish itself.
@@ -586,6 +590,18 @@
return mCallback;
}
+ /** @hide */
+ public final void setOnWindowDismissedCallback(OnWindowDismissedCallback dcb) {
+ mOnWindowDismissedCallback = dcb;
+ }
+
+ /** @hide */
+ public final void dispatchOnWindowDismissed() {
+ if (mOnWindowDismissedCallback != null) {
+ mOnWindowDismissedCallback.onWindowDismissed();
+ }
+ }
+
/**
* Take ownership of this window's surface. The window's view hierarchy
* will no longer draw into the surface, though it will otherwise continue
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 2160efe..294f472 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -29,7 +29,7 @@
* @see View.OnApplyWindowInsetsListener
* @see View#onApplyWindowInsets(WindowInsets)
*/
-public class WindowInsets {
+public final class WindowInsets {
private Rect mSystemWindowInsets;
private Rect mWindowDecorInsets;
private Rect mTempRect;
@@ -151,6 +151,7 @@
* This can include action bars, title bars, toolbars, etc.</p>
*
* @return The left window decor inset
+ * @hide pending API
*/
public int getWindowDecorInsetLeft() {
return mWindowDecorInsets.left;
@@ -164,6 +165,7 @@
* This can include action bars, title bars, toolbars, etc.</p>
*
* @return The top window decor inset
+ * @hide pending API
*/
public int getWindowDecorInsetTop() {
return mWindowDecorInsets.top;
@@ -177,6 +179,7 @@
* This can include action bars, title bars, toolbars, etc.</p>
*
* @return The right window decor inset
+ * @hide pending API
*/
public int getWindowDecorInsetRight() {
return mWindowDecorInsets.right;
@@ -190,6 +193,7 @@
* This can include action bars, title bars, toolbars, etc.</p>
*
* @return The bottom window decor inset
+ * @hide pending API
*/
public int getWindowDecorInsetBottom() {
return mWindowDecorInsets.bottom;
@@ -217,6 +221,7 @@
* This can include action bars, title bars, toolbars, etc.</p>
*
* @return true if any of the window decor inset values are nonzero
+ * @hide pending API
*/
public boolean hasWindowDecorInsets() {
return mWindowDecorInsets.left != 0 || mWindowDecorInsets.top != 0 ||
@@ -246,13 +251,28 @@
return mIsRound;
}
- public WindowInsets cloneWithSystemWindowInsetsConsumed() {
+ /**
+ * Returns a copy of this WindowInsets with the system window insets fully consumed.
+ *
+ * @return A modified copy of this WindowInsets
+ */
+ public WindowInsets consumeSystemWindowInsets() {
final WindowInsets result = new WindowInsets(this);
result.mSystemWindowInsets = new Rect(0, 0, 0, 0);
return result;
}
- public WindowInsets cloneWithSystemWindowInsetsConsumed(boolean left, boolean top,
+ /**
+ * Returns a copy of this WindowInsets with selected system window insets fully consumed.
+ *
+ * @param left true to consume the left system window inset
+ * @param top true to consume the top system window inset
+ * @param right true to consume the right system window inset
+ * @param bottom true to consume the bottom system window inset
+ * @return A modified copy of this WindowInsets
+ * @hide pending API
+ */
+ public WindowInsets consumeSystemWindowInsets(boolean left, boolean top,
boolean right, boolean bottom) {
if (left || top || right || bottom) {
final WindowInsets result = new WindowInsets(this);
@@ -265,19 +285,36 @@
return this;
}
- public WindowInsets cloneWithSystemWindowInsets(int left, int top, int right, int bottom) {
+ /**
+ * Returns a copy of this WindowInsets with selected system window insets replaced
+ * with new values.
+ *
+ * @param left New left inset in pixels
+ * @param top New top inset in pixels
+ * @param right New right inset in pixels
+ * @param bottom New bottom inset in pixels
+ * @return A modified copy of this WindowInsets
+ */
+ public WindowInsets replaceSystemWindowInsets(int left, int top,
+ int right, int bottom) {
final WindowInsets result = new WindowInsets(this);
result.mSystemWindowInsets = new Rect(left, top, right, bottom);
return result;
}
- public WindowInsets cloneWithWindowDecorInsetsConsumed() {
+ /**
+ * @hide
+ */
+ public WindowInsets consumeWindowDecorInsets() {
final WindowInsets result = new WindowInsets(this);
result.mWindowDecorInsets.set(0, 0, 0, 0);
return result;
}
- public WindowInsets cloneWithWindowDecorInsetsConsumed(boolean left, boolean top,
+ /**
+ * @hide
+ */
+ public WindowInsets consumeWindowDecorInsets(boolean left, boolean top,
boolean right, boolean bottom) {
if (left || top || right || bottom) {
final WindowInsets result = new WindowInsets(this);
@@ -290,7 +327,10 @@
return this;
}
- public WindowInsets cloneWithWindowDecorInsets(int left, int top, int right, int bottom) {
+ /**
+ * @hide
+ */
+ public WindowInsets replaceWindowDecorInsets(int left, int top, int right, int bottom) {
final WindowInsets result = new WindowInsets(this);
result.mWindowDecorInsets = new Rect(left, top, right, bottom);
return result;
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index c524611..4fde1e4 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -443,8 +443,6 @@
public final int OFF_BECAUSE_OF_USER = 2;
/** Screen turned off because of timeout */
public final int OFF_BECAUSE_OF_TIMEOUT = 3;
- /** Screen turned off because of proximity sensor */
- public final int OFF_BECAUSE_OF_PROX_SENSOR = 4;
/** @hide */
@IntDef({USER_ROTATION_FREE, USER_ROTATION_LOCKED})
@@ -900,23 +898,23 @@
public int focusChangedLw(WindowState lastFocus, WindowState newFocus);
/**
- * Called after the screen turns off.
+ * Called when the device is going to sleep.
*
* @param why {@link #OFF_BECAUSE_OF_USER} or
* {@link #OFF_BECAUSE_OF_TIMEOUT}.
*/
- public void screenTurnedOff(int why);
+ public void goingToSleep(int why);
public interface ScreenOnListener {
void onScreenOn();
}
/**
- * Called when the power manager would like to turn the screen on.
+ * Called when the device is waking up.
* Must call back on the listener to tell it when the higher-level system
* is ready for the screen to go on (i.e. the lock screen is shown).
*/
- public void screenTurningOn(ScreenOnListener screenOnListener);
+ public void wakingUp(ScreenOnListener screenOnListener);
/**
* Return whether the screen is about to turn on or is currently on.
diff --git a/core/java/android/webkit/ClientCertRequest.java b/core/java/android/webkit/ClientCertRequest.java
index 8951786..588b868 100644
--- a/core/java/android/webkit/ClientCertRequest.java
+++ b/core/java/android/webkit/ClientCertRequest.java
@@ -36,8 +36,6 @@
* host/port pair. The user can clear the cached data using
* {@link WebView#clearClientCertPreferences}.
*
- * TODO(sgurun) unhide
- * @hide
*/
public interface ClientCertRequest {
/**
diff --git a/core/java/android/webkit/PermissionRequest.java b/core/java/android/webkit/PermissionRequest.java
index 2f8850b..3e33498 100644
--- a/core/java/android/webkit/PermissionRequest.java
+++ b/core/java/android/webkit/PermissionRequest.java
@@ -19,14 +19,11 @@
import android.net.Uri;
/**
- * This class wraps a permission request, and is used to request permission for
- * the web content to access the resources.
+ * This interface defines a permission request and is used when web content
+ * requests access to protected resources.
*
- * Either {@link #grant(long) grant()} or {@link #deny()} must be called to response the
- * request, otherwise, {@link WebChromeClient#onPermissionRequest(PermissionRequest)} will
- * not be invoked again if there is other permission request in this WebView.
- *
- * @hide
+ * Either {@link #grant(long) grant()} or {@link #deny()} must be called in UI
+ * thread to respond to the request.
*/
public interface PermissionRequest {
/**
@@ -62,8 +59,6 @@
* must be equals or a subset of granted resources.
* This parameter is designed to avoid granting permission by accident
* especially when new resources are requested by web content.
- * Calling grant(getResources()) has security issue, the new permission
- * will be granted without being noticed.
*/
public void grant(long resources);
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 60cba86..d630a9a 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -304,7 +304,6 @@
* If this method isn't overridden, the permission is denied.
*
* @param request the PermissionRequest from current web content.
- * @hide
*/
public void onPermissionRequest(PermissionRequest request) {
request.deny();
@@ -314,8 +313,7 @@
* Notify the host application that the given permission request
* has been canceled. Any related UI should therefore be hidden.
*
- * @param request the PermissionRequest need be canceled.
- * @hide
+ * @param request the PermissionRequest that needs be canceled.
*/
public void onPermissionRequestCanceled(PermissionRequest request) {}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 98ef66e..7c32c5b 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -171,6 +171,38 @@
}
/**
+ * Used with {@link #setMixedContentMode}
+ *
+ * In this mode, the WebView will allow a secure origin to load content from any other origin,
+ * even if that origin is insecure. This is the least secure mode of operation for the WebView,
+ * and where possible apps should not set this mode.
+ */
+ public static final int MIXED_CONTENT_ALWAYS_ALLOW = 0;
+
+ /**
+ * Used with {@link #setMixedContentMode}
+ *
+ * In this mode, the WebView will not allow a secure origin to load content from an insecure
+ * origin. This is the preferred and most secure mode of operation for the WebView and apps are
+ * strongly advised to use this mode.
+ */
+ public static final int MIXED_CONTENT_NEVER_ALLOW = 1;
+
+ /**
+ * Used with {@link #setMixedContentMode}
+ *
+ * In this mode, the WebView will attempt to be compatible with the approach of a modern web
+ * browser with regard to mixed content. Some insecure content may be allowed to be loaded by
+ * a secure origin and other types of content will be blocked. The types of content are allowed
+ * or blocked may change release to release and are not explicitly defined.
+ *
+ * This mode is intended to be used by apps that are not in control of the content that they
+ * render but desire to operate in a reasonably secure environment. For highest security, apps
+ * are recommended to use {@link #MIXED_CONTENT_NEVER_ALLOW}.
+ */
+ public static final int MIXED_CONTENT_COMPATIBILITY_MODE = 2;
+
+ /**
* Hidden constructor to prevent clients from creating a new settings
* instance or deriving the class.
*
@@ -1403,4 +1435,29 @@
public int getCacheMode() {
throw new MustOverrideException();
}
+
+ /**
+ * Configures the WebView's behavior when a secure origin attempts to load a resource from an
+ * insecure origin.
+ *
+ * By default, apps that target {@link android.os.Build.VERSION_CODES#KITKAT} or below default
+ * to {@link #MIXED_CONTENT_ALWAYS_ALLOW}. Apps targeting
+ * {@link android.os.Build.VERSION_CODES#L} default to {@link #MIXED_CONTENT_NEVER_ALLOW}.
+ *
+ * The preferred and most secure mode of operation for the WebView is
+ * {@link #MIXED_CONTENT_NEVER_ALLOW} and use of {@link #MIXED_CONTENT_ALWAYS_ALLOW} is
+ * strongly discouraged.
+ *
+ * @param mode The mixed content mode to use. One of {@link #MIXED_CONTENT_NEVER_ALLOW},
+ * {@link #MIXED_CONTENT_NEVER_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
+ */
+ public abstract void setMixedContentMode(int mode);
+
+ /**
+ * Gets the current behavior of the WebView with regard to loading insecure content from a
+ * secure origin.
+ * @return The current setting, one of {@link #MIXED_CONTENT_NEVER_ALLOW},
+ * {@link #MIXED_CONTENT_NEVER_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
+ */
+ public abstract int getMixedContentMode();
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index efb246a..91ca7b4 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -33,6 +33,7 @@
import android.os.Message;
import android.os.StrictMode;
import android.print.PrintDocumentAdapter;
+import android.security.KeyChain;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
@@ -250,6 +251,15 @@
implements ViewTreeObserver.OnGlobalFocusChangeListener,
ViewGroup.OnHierarchyChangeListener, ViewDebug.HierarchyHandler {
+ /**
+ * Broadcast Action: Indicates the data reduction proxy setting changed.
+ * Sent by the settings app when user changes the data reduction proxy value. This intent will
+ * always stay as a hidden API.
+ * @hide
+ */
+ public static final String DATA_REDUCTION_PROXY_SETTING_CHANGED =
+ "android.webkit.DATA_REDUCTION_PROXY_SETTING_CHANGED";
+
private static final String LOGTAG = "WebView";
// Throwing an exception for incorrect thread usage if the
@@ -1479,18 +1489,16 @@
* Clears the client certificate preferences table stored in response
* to proceeding/cancelling client cert requests. Note that webview
* automatically clears these preferences when it receives a
- * {@link KeyChain.ACTION_STORAGE_CHANGED}
+ * {@link KeyChain#ACTION_STORAGE_CHANGED} intent. The client certificate
+ * preferences are global for all Webviews.
*
- * @param resultCallback A callback to be invoked when client certs are cleared.
- * The embedder can pass null if not interested in the callback.
- *
- * TODO(sgurun) unhide
- * @hide
+ * @param onCleared A runnable to be invoked when client certs are cleared.
+ * The embedder can pass null if not interested in the
+ * callback. The runnable will be called in UI thread.
*/
- public void clearClientCertPreferences(ValueCallback<Void> resultCallback) {
- checkThread();
+ public static void clearClientCertPreferences(Runnable onCleared) {
if (DebugFlags.TRACE_API) Log.d(LOGTAG, "clearClientCertPreferences");
- mProvider.clearClientCertPreferences(resultCallback);
+ getFactory().getStatics().clearClientCertPreferences(onCleared);
}
/**
@@ -1674,13 +1682,15 @@
/**
* Preauthorize the given origin to access resources.
- * This authorization only valid for this WebView instance life cycle and
+ * The authorization only valid for this WebView instance's life cycle and
* will not retained.
*
+ * In the case that an origin has had resources preauthorized, calls to
+ * {@link WebChromeClient#onPermissionRequest(PermissionRequest)} will not be
+ * made for those resources from that origin.
+ *
* @param origin the origin authorized to access resources
* @param resources the resource authorized to be accessed by origin.
- *
- * @hide
*/
public void preauthorizePermission(Uri origin, long resources) {
checkThread();
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 688c251..62b80c4a 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -19,6 +19,7 @@
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.os.Message;
+import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.ViewRootImpl;
@@ -223,8 +224,6 @@
* @param view The WebView that is initiating the callback
* @param request An instance of a {@link ClientCertRequest}
*
- * TODO(sgurun) unhide
- * @hide
*/
public void onReceivedClientCertRequest(WebView view, ClientCertRequest request) {
request.cancel();
@@ -272,11 +271,43 @@
*
* @param view The WebView that is initiating the callback.
* @param event The key event.
+ * @deprecated This method is subsumed by the more generic onUnhandledInputEvent.
*/
+ @Deprecated
public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
+ onUnhandledInputEventInternal(view, event);
+ }
+
+ /**
+ * Notify the host application that a input event was not handled by the WebView.
+ * Except system keys, WebView always consumes input events in the normal flow
+ * or if shouldOverrideKeyEvent returns true. This is called asynchronously
+ * from where the event is dispatched. It gives the host application a chance
+ * to handle the unhandled input events.
+ *
+ * Note that if the event is a {@link android.view.MotionEvent}, then it's lifetime is only
+ * that of the function call. If the WebViewClient wishes to use the event beyond that, then it
+ * <i>must</i> create a copy of the event.
+ *
+ * It is the responsibility of overriders of this method to call
+ * {@link #onUnhandledKeyEvent(WebView, KeyEvent)}
+ * when appropriate if they wish to continue receiving events through it.
+ *
+ * @param view The WebView that is initiating the callback.
+ * @param event The input event.
+ */
+ public void onUnhandledInputEvent(WebView view, InputEvent event) {
+ if (event instanceof KeyEvent) {
+ onUnhandledKeyEvent(view, (KeyEvent) event);
+ return;
+ }
+ onUnhandledInputEventInternal(view, event);
+ }
+
+ private void onUnhandledInputEventInternal(WebView view, InputEvent event) {
ViewRootImpl root = view.getViewRootImpl();
if (root != null) {
- root.dispatchUnhandledKey(event);
+ root.dispatchUnhandledInputEvent(event);
}
}
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index e391aaf..945e0e3 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -59,6 +59,13 @@
* {@link android.webkit.WebView#setWebContentsDebuggingEnabled(boolean) }
*/
void setWebContentsDebuggingEnabled(boolean enable);
+
+ /**
+ * Implements the API method:
+ * {@link android.webkit.WebView#clearClientCertPreferences(Runnable) }
+ */
+ void clearClientCertPreferences(Runnable onCleared);
+
}
Statics getStatics();
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index efa5497..5081ff5 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -198,8 +198,6 @@
public void clearSslPreferences();
- public void clearClientCertPreferences(ValueCallback<Void> resultCallback);
-
public WebBackForwardList copyBackForwardList();
public void setFindListener(WebView.FindListener listener);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index becda67..f4cd5fc 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -110,6 +110,7 @@
* @see #setTranscriptMode(int)
*/
public static final int TRANSCRIPT_MODE_DISABLED = 0;
+
/**
* The list will automatically scroll to the bottom when a data set change
* notification is received and only if the last item is already visible
@@ -118,6 +119,7 @@
* @see #setTranscriptMode(int)
*/
public static final int TRANSCRIPT_MODE_NORMAL = 1;
+
/**
* The list will automatically scroll to the bottom, no matter what items
* are currently visible.
@@ -609,6 +611,9 @@
final boolean[] mIsScrap = new boolean[1];
+ private final int[] mScrollOffset = new int[2];
+ private final int[] mScrollConsumed = new int[2];
+
// True when the popup should be hidden because of a call to
// dispatchDisplayHint()
private boolean mPopupHidden;
@@ -2489,8 +2494,30 @@
}
}
+ /**
+ * Positions the selector in a way that mimics keyboard focus. If the
+ * selector drawable supports hotspots, this manages the focus hotspot.
+ */
+ void positionSelectorLikeFocus(int position, View sel) {
+ positionSelector(position, sel);
+
+ final Drawable selector = mSelector;
+ if (selector != null && selector.supportsHotspots() && position != INVALID_POSITION) {
+ final Rect bounds = mSelectorRect;
+ final float x = bounds.exactCenterX();
+ final float y = bounds.exactCenterY();
+ selector.setHotspot(R.attr.state_focused, x, y);
+ }
+ }
+
void positionSelector(int position, View sel) {
if (position != INVALID_POSITION) {
+ if (mSelectorPosition != position) {
+ final Drawable selector = mSelector;
+ if (selector != null && selector.supportsHotspots()) {
+ selector.clearHotspots();
+ }
+ }
mSelectorPosition = position;
}
@@ -3240,13 +3267,14 @@
}
}
- private boolean startScrollIfNeeded(int y) {
+ private boolean startScrollIfNeeded(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;
final int distance = Math.abs(deltaY);
final boolean overscroll = mScrollY != 0;
- if (overscroll || distance > mTouchSlop) {
+ if ((overscroll || distance > mTouchSlop) &&
+ (getNestedScrollAxes() & SCROLL_AXIS_VERTICAL) == 0) {
createScrollingCache();
if (overscroll) {
mTouchMode = TOUCH_MODE_OVERSCROLL;
@@ -3268,17 +3296,28 @@
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
- scrollIfNeeded(y);
+ scrollIfNeeded(y, vtev);
return true;
}
return false;
}
- private void scrollIfNeeded(int y) {
- final int rawDeltaY = y - mMotionY;
+ private void scrollIfNeeded(int y, MotionEvent vtev) {
+ int rawDeltaY = y - mMotionY;
+ if (dispatchNestedPreScroll(0, rawDeltaY, mScrollConsumed, mScrollOffset)) {
+ rawDeltaY -= mScrollConsumed[1];
+ mMotionCorrection -= mScrollOffset[1];
+ if (mLastY != Integer.MIN_VALUE) {
+ mLastY -= mScrollOffset[1] + mScrollConsumed[1];
+ }
+ if (vtev != null) {
+ vtev.offsetLocation(0, mScrollOffset[1]);
+ }
+ }
final int deltaY = rawDeltaY - mMotionCorrection;
int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
+ int lastYCorrection = 0;
if (mTouchMode == TOUCH_MODE_SCROLL) {
if (PROFILE_SCROLLING) {
@@ -3337,39 +3376,48 @@
int overscroll = -incrementalDeltaY -
(motionViewRealTop - motionViewPrevTop);
- 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();
+ 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 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 (rawDeltaY > 0) {
- mEdgeGlowTop.onPull((float) overscroll / getHeight());
- if (!mEdgeGlowBottom.isFinished()) {
- mEdgeGlowBottom.onRelease();
+ 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 (!mEdgeGlowBottom.isFinished()) {
+ mEdgeGlowBottom.onRelease();
+ }
+ invalidate(mEdgeGlowTop.getBounds(false));
+ } else if (deltaY < 0) {
+ mEdgeGlowBottom.onPull((float) overscroll / getHeight());
+ if (!mEdgeGlowTop.isFinished()) {
+ mEdgeGlowTop.onRelease();
+ }
+ invalidate(mEdgeGlowBottom.getBounds(true));
}
- invalidate(mEdgeGlowTop.getBounds(false));
- } else if (rawDeltaY < 0) {
- mEdgeGlowBottom.onPull((float) overscroll / getHeight());
- if (!mEdgeGlowTop.isFinished()) {
- mEdgeGlowTop.onRelease();
- }
- invalidate(mEdgeGlowBottom.getBounds(true));
}
}
}
mMotionY = y;
}
- mLastY = y;
+ mLastY = y + lastYCorrection;
}
} else if (mTouchMode == TOUCH_MODE_OVERSCROLL) {
if (y != mLastY) {
@@ -3493,6 +3541,8 @@
return false;
}
+ startNestedScroll(SCROLL_AXIS_VERTICAL);
+
if (mFastScroll != null) {
boolean intercepted = mFastScroll.onTouchEvent(ev);
if (intercepted) {
@@ -3501,7 +3551,7 @@
}
initVelocityTrackerIfNotExists();
- mVelocityTracker.addMovement(ev);
+ final MotionEvent vtev = MotionEvent.obtain(ev);
final int actionMasked = ev.getActionMasked();
switch (actionMasked) {
@@ -3511,7 +3561,7 @@
}
case MotionEvent.ACTION_MOVE: {
- onTouchMove(ev);
+ onTouchMove(ev, vtev);
break;
}
@@ -3562,6 +3612,10 @@
}
}
+ if (mVelocityTracker != null) {
+ mVelocityTracker.addMovement(vtev);
+ }
+ vtev.recycle();
return true;
}
@@ -3628,7 +3682,7 @@
}
}
- private void onTouchMove(MotionEvent ev) {
+ private void onTouchMove(MotionEvent ev, MotionEvent vtev) {
int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) {
pointerIndex = 0;
@@ -3649,7 +3703,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)) {
+ if (startScrollIfNeeded(y, vtev)) {
break;
}
// Otherwise, check containment within list bounds. If we're
@@ -3669,7 +3723,7 @@
break;
case TOUCH_MODE_SCROLL:
case TOUCH_MODE_OVERSCROLL:
- scrollIfNeeded(y);
+ scrollIfNeeded(y, vtev);
break;
}
}
@@ -3911,6 +3965,49 @@
}
@Override
+ public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
+ return ((nestedScrollAxes & SCROLL_AXIS_VERTICAL) != 0);
+ }
+
+ @Override
+ public void onNestedScrollAccepted(View child, View target, int axes) {
+ super.onNestedScrollAccepted(child, target, axes);
+ startNestedScroll(SCROLL_AXIS_VERTICAL);
+ }
+
+ @Override
+ public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
+ int dxUnconsumed, int dyUnconsumed) {
+ final int motionIndex = getChildCount() / 2;
+ final View motionView = getChildAt(motionIndex);
+ final int oldTop = motionView != null ? motionView.getTop() : 0;
+ if (motionView == null || trackMotionScroll(-dyUnconsumed, -dyUnconsumed)) {
+ int myUnconsumed = dyUnconsumed;
+ int myConsumed = 0;
+ if (motionView != null) {
+ myConsumed = motionView.getTop() - oldTop;
+ myUnconsumed -= myConsumed;
+ }
+ dispatchNestedScroll(0, myConsumed, 0, myUnconsumed, null);
+ }
+ }
+
+ @Override
+ public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
+ final int childCount = getChildCount();
+ if (!consumed && childCount > 0 && canScrollList((int) velocityY) &&
+ Math.abs(velocityY) > mMinimumVelocity) {
+ reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
+ if (mFlingRunnable == null) {
+ mFlingRunnable = new FlingRunnable();
+ }
+ mFlingRunnable.start((int) velocityY);
+ return true;
+ }
+ return dispatchNestedFling(velocityX, velocityY, consumed);
+ }
+
+ @Override
public void draw(Canvas canvas) {
super.draw(canvas);
if (mEdgeGlowTop != null) {
@@ -4046,6 +4143,7 @@
mLastY = Integer.MIN_VALUE;
initOrResetVelocityTracker();
mVelocityTracker.addMovement(ev);
+ startNestedScroll(SCROLL_AXIS_VERTICAL);
if (touchMode == TOUCH_MODE_FLING) {
return true;
}
@@ -4063,7 +4161,7 @@
final int y = (int) ev.getY(pointerIndex);
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
- if (startScrollIfNeeded(y)) {
+ if (startScrollIfNeeded(y, null)) {
return true;
}
break;
@@ -4077,6 +4175,7 @@
mActivePointerId = INVALID_POINTER;
recycleVelocityTracker();
reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
+ stopNestedScroll();
break;
}
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index e4575e5..51759c5 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -649,7 +649,8 @@
private class OverflowPopup extends MenuPopupHelper {
public OverflowPopup(Context context, MenuBuilder menu, View anchorView,
boolean overflowOnly) {
- super(context, menu, anchorView, overflowOnly);
+ super(context, menu, anchorView, overflowOnly,
+ com.android.internal.R.attr.actionOverflowMenuStyle);
setGravity(Gravity.END);
setCallback(mPopupPresenterCallback);
}
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index b47177a..f91865b 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -622,8 +622,8 @@
// only set this if the dropdown is not always visible
mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
mPopup.setTouchInterceptor(mTouchInterceptor);
- mPopup.showAsDropDown(getAnchorView(),
- mDropDownHorizontalOffset, mDropDownVerticalOffset, mDropDownGravity);
+ mPopup.showAsDropDown(getAnchorView(), mDropDownHorizontalOffset,
+ mDropDownVerticalOffset, mDropDownGravity);
mDropDownList.setSelection(ListView.INVALID_POSITION);
if (!mModal || mDropDownList.isInTouchMode()) {
@@ -1565,7 +1565,7 @@
// Ensure that keyboard focus starts from the last touched position.
setSelectedPositionInt(position);
- positionSelector(position, child);
+ positionSelectorLikeFocus(position, child);
// Refresh the drawable state to reflect the new pressed state,
// which will also update the selector state.
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 5de67c8..eeb8015 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -2564,7 +2564,7 @@
if (needToRedraw) {
if (selectedView != null) {
- positionSelector(selectedPos, selectedView);
+ positionSelectorLikeFocus(selectedPos, selectedView);
mSelectedTop = selectedView.getTop();
}
if (!awakenScrollBars()) {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 6e71a5c..01632ae 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -18,6 +18,7 @@
import com.android.internal.R;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -116,6 +117,10 @@
private Drawable mAboveAnchorBackgroundDrawable;
private Drawable mBelowAnchorBackgroundDrawable;
+ // Temporary animation centers. Should be moved into window params?
+ private int mAnchorRelativeX;
+ private int mAnchorRelativeY;
+
private boolean mAboveAnchor;
private int mWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
@@ -129,12 +134,14 @@
};
private WeakReference<View> mAnchor;
- private OnScrollChangedListener mOnScrollChangedListener =
+
+ private final OnScrollChangedListener mOnScrollChangedListener =
new OnScrollChangedListener() {
+ @Override
public void onScrollChanged() {
- View anchor = mAnchor != null ? mAnchor.get() : null;
+ final View anchor = mAnchor != null ? mAnchor.get() : null;
if (anchor != null && mPopupView != null) {
- WindowManager.LayoutParams p = (WindowManager.LayoutParams)
+ final WindowManager.LayoutParams p = (WindowManager.LayoutParams)
mPopupView.getLayoutParams();
updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
@@ -143,7 +150,9 @@
}
}
};
+
private int mAnchorXoff, mAnchorYoff, mAnchoredGravity;
+ private boolean mOverlapAnchor;
private boolean mPopupViewInitialLayoutDirectionInherited;
@@ -187,6 +196,7 @@
attrs, com.android.internal.R.styleable.PopupWindow, defStyleAttr, defStyleRes);
mBackground = a.getDrawable(R.styleable.PopupWindow_popupBackground);
+ mOverlapAnchor = a.getBoolean(R.styleable.PopupWindow_overlapAnchor, false);
final int animStyle = a.getResourceId(R.styleable.PopupWindow_popupAnimationStyle, -1);
mAnimationStyle = animStyle == com.android.internal.R.style.Animation_PopupWindow ? -1 :
@@ -934,9 +944,9 @@
// do the job.
if (mAboveAnchorBackgroundDrawable != null) {
if (mAboveAnchor) {
- mPopupView.setBackgroundDrawable(mAboveAnchorBackgroundDrawable);
+ mPopupView.setBackground(mAboveAnchorBackgroundDrawable);
} else {
- mPopupView.setBackgroundDrawable(mBelowAnchorBackgroundDrawable);
+ mPopupView.setBackground(mBelowAnchorBackgroundDrawable);
}
} else {
mPopupView.refreshDrawableState();
@@ -1114,36 +1124,43 @@
}
return mAnimationStyle;
}
-
+
/**
- * <p>Positions the popup window on screen. When the popup window is too
- * tall to fit under the anchor, a parent scroll view is seeked and scrolled
- * up to reclaim space. If scrolling is not possible or not enough, the
- * popup window gets moved on top of the anchor.</p>
- *
- * <p>The height must have been set on the layout parameters prior to
- * calling this method.</p>
- *
+ * Positions the popup window on screen. When the popup window is too tall
+ * to fit under the anchor, a parent scroll view is seeked and scrolled up
+ * to reclaim space. If scrolling is not possible or not enough, the popup
+ * window gets moved on top of the anchor.
+ * <p>
+ * The height must have been set on the layout parameters prior to calling
+ * this method.
+ *
* @param anchor the view on which the popup window must be anchored
* @param p the layout parameters used to display the drop down
- *
+ * @param xoff horizontal offset used to adjust for background padding
+ * @param yoff vertical offset used to adjust for background padding
+ * @param gravity horizontal gravity specifying popup alignment
* @return true if the popup is translated upwards to fit on screen
*/
- private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
- int xoff, int yoff, int gravity) {
-
+ private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p, int xoff,
+ int yoff, int gravity) {
final int anchorHeight = anchor.getHeight();
+ final int anchorWidth = anchor.getWidth();
+ if (mOverlapAnchor) {
+ yoff -= anchorHeight;
+ }
+
anchor.getLocationInWindow(mDrawingLocation);
p.x = mDrawingLocation[0] + xoff;
p.y = mDrawingLocation[1] + anchorHeight + yoff;
- final int hgrav = Gravity.getAbsoluteGravity(gravity, anchor.getLayoutDirection()) &
- Gravity.HORIZONTAL_GRAVITY_MASK;
+ final int hgrav = Gravity.getAbsoluteGravity(gravity, anchor.getLayoutDirection())
+ & Gravity.HORIZONTAL_GRAVITY_MASK;
if (hgrav == Gravity.RIGHT) {
- // Flip the location to align the right sides of the popup and anchor instead of left
- p.x -= mPopupWidth - anchor.getWidth();
+ // Flip the location to align the right sides of the popup and
+ // anchor instead of left.
+ p.x -= mPopupWidth - anchorWidth;
}
-
+
boolean onTop = false;
p.gravity = Gravity.LEFT | Gravity.TOP;
@@ -1152,60 +1169,58 @@
final Rect displayFrame = new Rect();
anchor.getWindowVisibleDisplayFrame(displayFrame);
- int screenY = mScreenLocation[1] + anchorHeight + yoff;
-
+ final int screenY = mScreenLocation[1] + anchorHeight + yoff;
final View root = anchor.getRootView();
- if (screenY + mPopupHeight > displayFrame.bottom ||
- p.x + mPopupWidth - root.getWidth() > 0) {
- // if the drop down disappears at the bottom of the screen. we try to
- // scroll a parent scrollview or move the drop down back up on top of
- // the edit box
+ if (screenY + mPopupHeight > displayFrame.bottom
+ || p.x + mPopupWidth - root.getWidth() > 0) {
+ // If the drop down disappears at the bottom of the screen, we try
+ // to scroll a parent scrollview or move the drop down back up on
+ // top of the edit box.
if (mAllowScrollingAnchorParent) {
- int scrollX = anchor.getScrollX();
- int scrollY = anchor.getScrollY();
- Rect r = new Rect(scrollX, scrollY, scrollX + mPopupWidth + xoff,
- scrollY + mPopupHeight + anchor.getHeight() + yoff);
+ final int scrollX = anchor.getScrollX();
+ final int scrollY = anchor.getScrollY();
+ final Rect r = new Rect(scrollX, scrollY, scrollX + mPopupWidth + xoff,
+ scrollY + mPopupHeight + anchorHeight + yoff);
anchor.requestRectangleOnScreen(r, true);
}
- // now we re-evaluate the space available, and decide from that
+ // Now we re-evaluate the space available, and decide from that
// whether the pop-up will go above or below the anchor.
anchor.getLocationInWindow(mDrawingLocation);
p.x = mDrawingLocation[0] + xoff;
- p.y = mDrawingLocation[1] + anchor.getHeight() + yoff;
+ p.y = mDrawingLocation[1] + anchorHeight + yoff;
- // Preserve the gravity adjustment
+ // Preserve the gravity adjustment.
if (hgrav == Gravity.RIGHT) {
- p.x -= mPopupWidth - anchor.getWidth();
+ p.x -= mPopupWidth - anchorWidth;
}
-
- // determine whether there is more space above or below the anchor
+
+ // Determine whether there is more space above or below the anchor.
anchor.getLocationOnScreen(mScreenLocation);
-
- onTop = (displayFrame.bottom - mScreenLocation[1] - anchor.getHeight() - yoff) <
+ onTop = (displayFrame.bottom - mScreenLocation[1] - anchorHeight - yoff) <
(mScreenLocation[1] - yoff - displayFrame.top);
if (onTop) {
p.gravity = Gravity.LEFT | Gravity.BOTTOM;
p.y = root.getHeight() - mDrawingLocation[1] + yoff;
} else {
- p.y = mDrawingLocation[1] + anchor.getHeight() + yoff;
+ p.y = mDrawingLocation[1] + anchorHeight + yoff;
}
}
if (mClipToScreen) {
final int displayFrameWidth = displayFrame.right - displayFrame.left;
-
- int right = p.x + p.width;
+ final int right = p.x + p.width;
if (right > displayFrameWidth) {
p.x -= right - displayFrameWidth;
}
+
if (p.x < displayFrame.left) {
p.x = displayFrame.left;
p.width = Math.min(p.width, displayFrameWidth);
}
if (onTop) {
- int popupTop = mScreenLocation[1] + yoff - mPopupHeight;
+ final int popupTop = mScreenLocation[1] + yoff - mPopupHeight;
if (popupTop < 0) {
p.y += popupTop;
}
@@ -1215,7 +1230,11 @@
}
p.gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
-
+
+ // Compute the position of the anchor relative to the popup.
+ mAnchorRelativeX = mDrawingLocation[0] - p.x + anchorHeight / 2;
+ mAnchorRelativeY = mDrawingLocation[1] - p.y + anchorWidth / 2;
+
return onTop;
}
@@ -1503,7 +1522,8 @@
}
WeakReference<View> oldAnchor = mAnchor;
- final boolean needsUpdate = updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff);
+ final boolean needsUpdate = updateLocation
+ && (mAnchorXoff != xoff || mAnchorYoff != yoff);
if (oldAnchor == null || oldAnchor.get() != anchor || (needsUpdate && !mIsDropdown)) {
registerForScrollChanged(anchor, xoff, yoff, gravity);
} else if (needsUpdate) {
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 7e8f6b4..0fa75a6f 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -583,7 +583,8 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
initVelocityTrackerIfNotExists();
- mVelocityTracker.addMovement(ev);
+
+ MotionEvent vtev = MotionEvent.obtain(ev);
final int action = ev.getAction();
@@ -627,7 +628,8 @@
final int y = (int) ev.getY(activePointerIndex);
int deltaY = mLastMotionY - y;
if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
- deltaY -= mScrollConsumed[1] + mScrollOffset[1];
+ deltaY -= mScrollConsumed[1];
+ vtev.offsetLocation(0, mScrollOffset[1]);
}
if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) {
final ViewParent parent = getParent();
@@ -643,7 +645,7 @@
}
if (mIsBeingDragged) {
// Scroll to follow the motion event
- mLastMotionY = y;
+ mLastMotionY = y - mScrollOffset[1];
final int oldY = mScrollY;
final int range = getScrollRange();
@@ -663,6 +665,7 @@
final int unconsumedY = deltaY - scrolledDeltaY;
if (dispatchNestedScroll(0, scrolledDeltaY, 0, unconsumedY, mScrollOffset)) {
mLastMotionY -= mScrollOffset[1];
+ vtev.offsetLocation(0, mScrollOffset[1]);
} else if (canOverscroll) {
final int pulledToY = oldY + deltaY;
if (pulledToY < 0) {
@@ -720,6 +723,11 @@
mLastMotionY = (int) ev.getY(ev.findPointerIndex(mActivePointerId));
break;
}
+
+ if (mVelocityTracker != null) {
+ mVelocityTracker.addMovement(vtev);
+ }
+ vtev.recycle();
return true;
}
@@ -1565,10 +1573,10 @@
}
private void flingWithNestedDispatch(int velocityY) {
- if (mScrollY == 0 && velocityY < 0 ||
- mScrollY == getScrollRange() && velocityY > 0) {
- dispatchNestedFling(0, velocityY);
- } else {
+ final boolean canFling = (mScrollY > 0 || velocityY > 0) &&
+ (mScrollY < getScrollRange() || velocityY < 0);
+ dispatchNestedFling(0, velocityY, canFling);
+ if (canFling) {
fling(velocityY);
}
}
@@ -1627,6 +1635,12 @@
return (nestedScrollAxes & SCROLL_AXIS_VERTICAL) != 0;
}
+ @Override
+ public void onNestedScrollAccepted(View child, View target, int axes) {
+ super.onNestedScrollAccepted(child, target, axes);
+ startNestedScroll(SCROLL_AXIS_VERTICAL);
+ }
+
/**
* @inheritDoc
*/
@@ -1638,16 +1652,23 @@
@Override
public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed) {
+ final int oldScrollY = mScrollY;
scrollBy(0, dyUnconsumed);
+ final int myConsumed = mScrollY - oldScrollY;
+ final int myUnconsumed = dyUnconsumed - myConsumed;
+ dispatchNestedScroll(0, myConsumed, 0, myUnconsumed, null);
}
/**
* @inheritDoc
*/
@Override
- public boolean onNestedFling(View target, float velocityX, float velocityY) {
- flingWithNestedDispatch((int) velocityY);
- return true;
+ public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
+ if (!consumed) {
+ flingWithNestedDispatch((int) velocityY);
+ return true;
+ }
+ return false;
}
@Override
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index cde8080..e4ad354 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -276,6 +276,8 @@
* @see Intent#ACTION_SEND_MULTIPLE
*/
public void setShareIntent(Intent shareIntent) {
+ shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
+ Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext,
mShareHistoryFileName);
dataModel.setIntent(shareIntent);
@@ -292,7 +294,8 @@
final int itemId = item.getItemId();
Intent launchIntent = dataModel.chooseActivity(itemId);
if (launchIntent != null) {
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
+ Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
mContext.startActivity(launchIntent);
}
return true;
@@ -308,7 +311,7 @@
return;
}
if (mOnChooseActivityListener == null) {
- mOnChooseActivityListener = new ShareAcitivityChooserModelPolicy();
+ mOnChooseActivityListener = new ShareActivityChooserModelPolicy();
}
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
dataModel.setOnChooseActivityListener(mOnChooseActivityListener);
@@ -317,7 +320,7 @@
/**
* Policy that delegates to the {@link OnShareTargetSelectedListener}, if such.
*/
- private class ShareAcitivityChooserModelPolicy implements OnChooseActivityListener {
+ private class ShareActivityChooserModelPolicy implements OnChooseActivityListener {
@Override
public boolean onChooseActivity(ActivityChooserModel host, Intent intent) {
if (mOnShareTargetSelectedListener != null) {
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 1bb577b..04547495 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -59,11 +59,10 @@
void noteVibratorOff(int uid);
void noteStartGps(int uid);
void noteStopGps(int uid);
- void noteScreenOn();
+ void noteScreenState(int state);
void noteScreenBrightness(int brightness);
- void noteScreenOff();
- void noteInputEvent();
void noteUserActivity(int uid, int event);
+ void noteInteractive(boolean interactive);
void noteMobileRadioPowerState(int powerState, long timestampNs);
void notePhoneOn();
void notePhoneOff();
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 3219ddd..98e35dd 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -24,8 +24,9 @@
import android.service.voice.IVoiceInteractionSession;
interface IVoiceInteractionManagerService {
- void startVoiceActivity(in Intent intent, String resolvedType, IVoiceInteractionService service,
- in Bundle sessionArgs);
- int deliverNewSession(IBinder token, IVoiceInteractionSession session,
+ void startSession(IVoiceInteractionService service, in Bundle sessionArgs);
+ boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
IVoiceInteractor interactor);
+ int startVoiceActivity(IBinder token, in Intent intent, String resolvedType);
+ void finish(IBinder token);
}
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index 8cdaf91..abd1791 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -18,156 +18,122 @@
import android.app.Activity;
import android.content.ActivityNotFoundException;
+import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
+import android.graphics.Color;
import android.graphics.Typeface;
-import android.provider.Settings;
import android.os.Build;
import android.os.Bundle;
-import android.os.Handler;
-import android.text.method.AllCapsTransformationMethod;
+import android.provider.Settings;
+import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AnticipateOvershootInterpolator;
-import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
-import android.widget.ImageView;
import android.widget.TextView;
public class PlatLogoActivity extends Activity {
- FrameLayout mContent;
- int mCount;
- final Handler mHandler = new Handler();
- static final int BGCOLOR = 0xffed1d24;
+ private static class Torso extends FrameLayout {
+ boolean mAnimate = false;
+ TextView mText;
+
+ public Torso(Context context) {
+ this(context, null);
+ }
+ public Torso(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+ public Torso(Context context, AttributeSet attrs, int flags) {
+ super(context, attrs, flags);
+
+ for (int i=0; i<2; i++) {
+ final View v = new View(context);
+ v.setBackgroundColor(i % 2 == 0 ? Color.BLUE : Color.RED);
+ addView(v);
+ }
+
+ mText = new TextView(context);
+ mText.setTextColor(Color.BLACK);
+ mText.setTextSize(14 /* sp */);
+ mText.setTypeface(Typeface.create("monospace", Typeface.BOLD));
+
+ addView(mText, new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.WRAP_CONTENT,
+ Gravity.BOTTOM | Gravity.LEFT
+ ));
+ }
+
+ private Runnable mRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mText.setText(String.format("android_%s.flv - build %s",
+ Build.VERSION.CODENAME,
+ Build.VERSION.INCREMENTAL));
+ final int N = getChildCount();
+ final float parentw = getMeasuredWidth();
+ final float parenth = getMeasuredHeight();
+ for (int i=0; i<N; i++) {
+ final View v = getChildAt(i);
+ if (v instanceof TextView) continue;
+
+ final int w = (int) (Math.random() * parentw);
+ final int h = (int) (Math.random() * parenth);
+ v.setLayoutParams(new FrameLayout.LayoutParams(w, h));
+
+ v.setX((float) Math.random() * (parentw - w));
+ v.setY((float) Math.random() * (parenth - h));
+ }
+
+ if (mAnimate) postDelayed(this, 1000);
+ }
+ };
+ @Override
+ protected void onAttachedToWindow() {
+ mAnimate = true;
+ post(mRunnable);
+ }
+ @Override
+ protected void onDetachedFromWindow() {
+ mAnimate = false;
+ removeCallbacks(mRunnable);
+ }
+ }
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- DisplayMetrics metrics = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ final Torso t = new Torso(this);
+ t.setBackgroundColor(Color.WHITE);
- Typeface bold = Typeface.create("sans-serif", Typeface.BOLD);
- Typeface light = Typeface.create("sans-serif-light", Typeface.NORMAL);
+ t.getChildAt(0)
+ .setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ final ContentResolver cr = getContentResolver();
+ if (Settings.System.getLong(cr, Settings.System.EGG_MODE, 0)
+ == 0) {
+ // For posterity: the moment this user unlocked the easter egg
+ Settings.System.putLong(cr,
+ Settings.System.EGG_MODE,
+ System.currentTimeMillis());
+ }
+ try {
+ startActivity(new Intent(Intent.ACTION_MAIN)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_CLEAR_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+ .addCategory("com.android.internal.category.PLATLOGO"));
+ } catch (ActivityNotFoundException ex) {
+ android.util.Log.e("PlatLogoActivity", "Couldn't catch a break.");
+ }
+ finish();
+ return true;
+ }
+ });
- mContent = new FrameLayout(this);
- mContent.setBackgroundColor(0xC0000000);
-
- final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.WRAP_CONTENT,
- FrameLayout.LayoutParams.WRAP_CONTENT);
- lp.gravity = Gravity.CENTER;
-
- final ImageView logo = new ImageView(this);
- logo.setImageResource(com.android.internal.R.drawable.platlogo);
- logo.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
- logo.setVisibility(View.INVISIBLE);
-
- final View bg = new View(this);
- bg.setBackgroundColor(BGCOLOR);
- bg.setAlpha(0f);
-
- final TextView letter = new TextView(this);
-
- letter.setTypeface(bold);
- letter.setTextSize(300);
- letter.setTextColor(0xFFFFFFFF);
- letter.setGravity(Gravity.CENTER);
- letter.setText(String.valueOf(Build.ID).substring(0, 1));
-
- final int p = (int)(4 * metrics.density);
-
- final TextView tv = new TextView(this);
- if (light != null) tv.setTypeface(light);
- tv.setTextSize(30);
- tv.setPadding(p, p, p, p);
- tv.setTextColor(0xFFFFFFFF);
- tv.setGravity(Gravity.CENTER);
- tv.setTransformationMethod(new AllCapsTransformationMethod(this));
- tv.setText("Android " + Build.VERSION.RELEASE);
- tv.setVisibility(View.INVISIBLE);
-
- mContent.addView(bg);
- mContent.addView(letter, lp);
- mContent.addView(logo, lp);
-
- final FrameLayout.LayoutParams lp2 = new FrameLayout.LayoutParams(lp);
- lp2.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
- lp2.bottomMargin = 10*p;
-
- mContent.addView(tv, lp2);
-
- mContent.setOnClickListener(new View.OnClickListener() {
- int clicks;
- @Override
- public void onClick(View v) {
- clicks++;
- if (clicks >= 6) {
- mContent.performLongClick();
- return;
- }
- letter.animate().cancel();
- final float offset = (int)letter.getRotation() % 360;
- letter.animate()
- .rotationBy((Math.random() > 0.5f ? 360 : -360) - offset)
- .setInterpolator(new DecelerateInterpolator())
- .setDuration(700).start();
- }
- });
-
- mContent.setOnLongClickListener(new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- if (logo.getVisibility() != View.VISIBLE) {
- bg.setScaleX(0.01f);
- bg.animate().alpha(1f).scaleX(1f).setStartDelay(500).start();
- letter.animate().alpha(0f).scaleY(0.5f).scaleX(0.5f)
- .rotationBy(360)
- .setInterpolator(new AccelerateInterpolator())
- .setDuration(1000)
- .start();
- logo.setAlpha(0f);
- logo.setVisibility(View.VISIBLE);
- logo.setScaleX(0.5f);
- logo.setScaleY(0.5f);
- logo.animate().alpha(1f).scaleX(1f).scaleY(1f)
- .setDuration(1000).setStartDelay(500)
- .setInterpolator(new AnticipateOvershootInterpolator())
- .start();
- tv.setAlpha(0f);
- tv.setVisibility(View.VISIBLE);
- tv.animate().alpha(1f).setDuration(1000).setStartDelay(1000).start();
- return true;
- }
- return false;
- }
- });
-
- logo.setOnLongClickListener(new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- if (Settings.System.getLong(getContentResolver(), Settings.System.EGG_MODE, 0)
- == 0) {
- // For posterity: the moment this user unlocked the easter egg
- Settings.System.putLong(getContentResolver(),
- Settings.System.EGG_MODE,
- System.currentTimeMillis());
- }
- try {
- startActivity(new Intent(Intent.ACTION_MAIN)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_CLEAR_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
- .addCategory("com.android.internal.category.PLATLOGO"));
- } catch (ActivityNotFoundException ex) {
- android.util.Log.e("PlatLogoActivity", "Couldn't catch a break.");
- }
- finish();
- return true;
- }
- });
-
- setContentView(mContent);
+ setContentView(t);
}
}
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index 131f8281..66548f0 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -17,7 +17,9 @@
package com.android.internal.app;
import android.animation.ValueAnimator;
+import android.content.res.TypedArray;
import android.view.ViewParent;
+import com.android.internal.R;
import com.android.internal.view.ActionBarPolicy;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuPopupHelper;
@@ -41,7 +43,6 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
-import android.os.Handler;
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.ContextThemeWrapper;
@@ -57,7 +58,6 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Map;
/**
* WindowDecorActionBar is the ActionBar implementation used
@@ -66,7 +66,8 @@
* across both the ActionBarView at the top of the screen and
* a horizontal LinearLayout at the bottom which is normally hidden.
*/
-public class WindowDecorActionBar extends ActionBar {
+public class WindowDecorActionBar extends ActionBar implements
+ ActionBarOverlayLayout.ActionBarVisibilityCallback {
private static final String TAG = "WindowDecorActionBar";
private Context mContext;
@@ -116,6 +117,7 @@
private Animator mCurrentShowAnim;
private boolean mShowHideAnimationEnabled;
+ boolean mHideOnContentScroll;
final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
@Override
@@ -132,7 +134,7 @@
mCurrentShowAnim = null;
completeDeferredDestroyActionMode();
if (mOverlayLayout != null) {
- mOverlayLayout.requestFitSystemWindows();
+ mOverlayLayout.requestApplyInsets();
}
}
};
@@ -183,7 +185,7 @@
mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
com.android.internal.R.id.action_bar_overlay_layout);
if (mOverlayLayout != null) {
- mOverlayLayout.setActionBar(this);
+ mOverlayLayout.setActionBarVisibilityCallback(this);
}
mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
mContextView = (ActionBarContextView) decor.findViewById(
@@ -213,6 +215,14 @@
ActionBarPolicy abp = ActionBarPolicy.get(mContext);
setHomeButtonEnabled(abp.enableHomeButtonByDefault() || homeAsUp);
setHasEmbeddedTabs(abp.hasEmbeddedTabs());
+
+ final TypedArray a = mContext.obtainStyledAttributes(null,
+ com.android.internal.R.styleable.ActionBar,
+ com.android.internal.R.attr.actionBarStyle, 0);
+ if (a.getBoolean(R.styleable.ActionBar_hideOnContentScroll, false)) {
+ setHideOnContentScrollEnabled(true);
+ }
+ a.recycle();
}
public void onConfigurationChanged(Configuration newConfig) {
@@ -234,17 +244,14 @@
if (isInTabMode) {
mTabScrollView.setVisibility(View.VISIBLE);
if (mOverlayLayout != null) {
- mOverlayLayout.requestFitSystemWindows();
+ mOverlayLayout.requestApplyInsets();
}
} else {
mTabScrollView.setVisibility(View.GONE);
}
}
mActionView.setCollapsable(!mHasEmbeddedTabs && isInTabMode);
- }
-
- public boolean hasNonEmbeddedTabs() {
- return !mHasEmbeddedTabs && getNavigationMode() == NAVIGATION_MODE_TABS;
+ mOverlayLayout.setHasNonEmbeddedTabs(!mHasEmbeddedTabs && isInTabMode);
}
private void ensureTabsExist() {
@@ -279,7 +286,7 @@
}
}
- public void setWindowVisibility(int visibility) {
+ public void onWindowVisibilityChanged(int visibility) {
mCurWindowVisibility = visibility;
}
@@ -453,6 +460,7 @@
mActionMode.finish();
}
+ mOverlayLayout.setHideOnContentScrollEnabled(false);
mContextView.killMode();
ActionModeImpl mode = new ActionModeImpl(callback);
if (mode.dispatchOnCreate()) {
@@ -464,7 +472,7 @@
if (mSplitView.getVisibility() != View.VISIBLE) {
mSplitView.setVisibility(View.VISIBLE);
if (mOverlayLayout != null) {
- mOverlayLayout.requestFitSystemWindows();
+ mOverlayLayout.requestApplyInsets();
}
}
}
@@ -652,6 +660,35 @@
}
}
+ @Override
+ public void setHideOnContentScrollEnabled(boolean hideOnContentScroll) {
+ if (hideOnContentScroll && !mOverlayLayout.isInOverlayMode()) {
+ throw new IllegalStateException("Action bar must be in overlay mode " +
+ "(Window.FEATURE_OVERLAY_ACTION_BAR) to enable hide on content scroll");
+ }
+ mHideOnContentScroll = hideOnContentScroll;
+ mOverlayLayout.setHideOnContentScrollEnabled(hideOnContentScroll);
+ }
+
+ @Override
+ public boolean isHideOnContentScrollEnabled() {
+ return mOverlayLayout.isHideOnContentScrollEnabled();
+ }
+
+ @Override
+ public int getHideOffset() {
+ return mOverlayLayout.getActionBarHideOffset();
+ }
+
+ @Override
+ public void setHideOffset(int offset) {
+ if (offset != 0 && !mOverlayLayout.isInOverlayMode()) {
+ throw new IllegalStateException("Action bar must be in overlay mode " +
+ "(Window.FEATURE_OVERLAY_ACTION_BAR) to set a non-zero hide offset");
+ }
+ mOverlayLayout.setActionBarHideOffset(offset);
+ }
+
private static boolean checkShowingFlags(boolean hiddenByApp, boolean hiddenBySystem,
boolean showingForMode) {
if (showingForMode) {
@@ -737,7 +774,7 @@
mShowListener.onAnimationEnd(null);
}
if (mOverlayLayout != null) {
- mOverlayLayout.requestFitSystemWindows();
+ mOverlayLayout.requestApplyInsets();
}
}
@@ -781,11 +818,7 @@
}
public boolean isShowing() {
- return mNowShowing;
- }
-
- public boolean isSystemShowing() {
- return !mHiddenBySystem;
+ return mNowShowing && getHideOffset() < getHeight();
}
void animateToMode(boolean toActionMode) {
@@ -844,6 +877,18 @@
mActionView.setHomeActionContentDescription(resId);
}
+ @Override
+ public void onContentScrollStarted() {
+ if (mCurrentShowAnim != null) {
+ mCurrentShowAnim.cancel();
+ mCurrentShowAnim = null;
+ }
+ }
+
+ @Override
+ public void onContentScrollStopped() {
+ }
+
/**
* @hide
*/
@@ -894,6 +939,7 @@
// Clear out the context mode views after the animation finishes
mContextView.closeMode();
mActionView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+ mOverlayLayout.setHideOnContentScrollEnabled(mHideOnContentScroll);
mActionMode = null;
}
@@ -1204,6 +1250,7 @@
break;
}
mActionView.setCollapsable(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
+ mOverlayLayout.setHasNonEmbeddedTabs(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
}
@Override
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
index cba09d1..e3f21cf 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -227,25 +227,39 @@
if (imList.size() <= 1) {
return null;
}
+ // Here we have two rotation groups, depending on the returned boolean value of
+ // {@link InputMethodInfo#supportsSwitchingToNextInputMethod()}.
+ final boolean expectedValueOfSupportsSwitchingToNextInputMethod =
+ imi.supportsSwitchingToNextInputMethod();
final int N = imList.size();
final int currentSubtypeId =
subtype != null ? InputMethodUtils.getSubtypeIdFromHashCode(imi,
subtype.hashCode()) : NOT_A_SUBTYPE_ID;
for (int i = 0; i < N; ++i) {
final ImeSubtypeListItem isli = imList.get(i);
- if (isli.mImi.equals(imi) && isli.mSubtypeId == currentSubtypeId) {
- if (!onlyCurrentIme) {
- return imList.get((i + 1) % N);
- }
- for (int j = 0; j < N - 1; ++j) {
- final ImeSubtypeListItem candidate = imList.get((i + j + 1) % N);
- if (candidate.mImi.equals(imi)) {
- return candidate;
- }
- }
- return null;
+ // Skip until the current IME/subtype is found.
+ if (!isli.mImi.equals(imi) || isli.mSubtypeId != currentSubtypeId) {
+ continue;
}
+ // Found the current IME/subtype. Start searching the next IME/subtype from here.
+ for (int j = 0; j < N - 1; ++j) {
+ final ImeSubtypeListItem candidate = imList.get((i + j + 1) % N);
+ // Skip if the candidate doesn't belong to the expected rotation group.
+ if (expectedValueOfSupportsSwitchingToNextInputMethod !=
+ candidate.mImi.supportsSwitchingToNextInputMethod()) {
+ continue;
+ }
+ // Skip if searching inside the current IME only, but the candidate is not
+ // the current IME.
+ if (onlyCurrentIme && !candidate.mImi.equals(imi)) {
+ continue;
+ }
+ return candidate;
+ }
+ // No appropriate IME/subtype is found in the list. Give up.
+ return null;
}
+ // The current IME/subtype is not found in the list. Give up.
return null;
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index f63fa8a..1aff190 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -51,6 +51,7 @@
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
+import android.view.Display;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.net.NetworkStatsFactory;
@@ -88,7 +89,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 104 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 105 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -237,13 +238,14 @@
int mWakeLockNesting;
boolean mWakeLockImportant;
- boolean mScreenOn;
+ int mScreenState = Display.STATE_UNKNOWN;
StopwatchTimer mScreenOnTimer;
int mScreenBrightnessBin = -1;
final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
- Counter mInputEventCounter;
+ boolean mInteractive;
+ StopwatchTimer mInteractiveTimer;
boolean mPhoneOn;
StopwatchTimer mPhoneOnTimer;
@@ -2661,58 +2663,61 @@
getUidStatsLocked(uid).noteStopGps(elapsedRealtime);
}
- public void noteScreenOnLocked() {
- if (!mScreenOn) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
- mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
- if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
- + Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(elapsedRealtime, uptime);
- mScreenOn = true;
- mScreenOnTimer.startRunningLocked(elapsedRealtime);
- if (mScreenBrightnessBin >= 0) {
- mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(elapsedRealtime);
- }
+ public void noteScreenStateLocked(int state) {
+ if (mScreenState != state) {
+ final int oldState = mScreenState;
+ mScreenState = state;
+ if (DEBUG) Slog.v(TAG, "Screen state: oldState=" + Display.stateToString(oldState)
+ + ", newState=" + Display.stateToString(state));
- updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), false,
- SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
+ if (state == Display.STATE_ON) {
+ // Screen turning on.
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ mScreenOnTimer.startRunningLocked(elapsedRealtime);
+ if (mScreenBrightnessBin >= 0) {
+ mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(elapsedRealtime);
+ }
- // Fake a wake lock, so we consider the device waked as long
- // as the screen is on.
- noteStartWakeLocked(-1, -1, "screen", null, WAKE_TYPE_PARTIAL, false,
- elapsedRealtime, uptime);
+ updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), false,
+ SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
- // Update discharge amounts.
- if (mOnBatteryInternal) {
- updateDischargeScreenLevelsLocked(false, true);
- }
- }
- }
+ // Fake a wake lock, so we consider the device waked as long
+ // as the screen is on.
+ noteStartWakeLocked(-1, -1, "screen", null, WAKE_TYPE_PARTIAL, false,
+ elapsedRealtime, uptime);
- public void noteScreenOffLocked() {
- if (mScreenOn) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
- mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
- if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
- + Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(elapsedRealtime, uptime);
- mScreenOn = false;
- mScreenOnTimer.stopRunningLocked(elapsedRealtime);
- if (mScreenBrightnessBin >= 0) {
- mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime);
- }
+ // Update discharge amounts.
+ if (mOnBatteryInternal) {
+ updateDischargeScreenLevelsLocked(false, true);
+ }
+ } else if (oldState == Display.STATE_ON) {
+ // Screen turning off or dozing.
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ mScreenOnTimer.stopRunningLocked(elapsedRealtime);
+ if (mScreenBrightnessBin >= 0) {
+ mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime);
+ }
- noteStopWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL,
- elapsedRealtime, uptime);
+ noteStopWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL,
+ elapsedRealtime, uptime);
- updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), true,
- SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
+ updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), true,
+ SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000);
- // Update discharge amounts.
- if (mOnBatteryInternal) {
- updateDischargeScreenLevelsLocked(true, false);
+ // Update discharge amounts.
+ if (mOnBatteryInternal) {
+ updateDischargeScreenLevelsLocked(true, false);
+ }
}
}
}
@@ -2730,7 +2735,7 @@
if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
- if (mScreenOn) {
+ if (mScreenState == Display.STATE_ON) {
if (mScreenBrightnessBin >= 0) {
mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime);
}
@@ -2740,10 +2745,6 @@
}
}
- public void noteInputEventAtomic() {
- mInputEventCounter.stepAtomic();
- }
-
public void noteUserActivityLocked(int uid, int event) {
if (mOnBatteryInternal) {
uid = mapUid(uid);
@@ -2751,6 +2752,19 @@
}
}
+ public void noteInteractiveLocked(boolean interactive) {
+ if (mInteractive != interactive) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ mInteractive = interactive;
+ if (DEBUG) Slog.v(TAG, "Interactive: " + interactive);
+ if (interactive) {
+ mInteractiveTimer.startRunningLocked(elapsedRealtime);
+ } else {
+ mInteractiveTimer.stopRunningLocked(elapsedRealtime);
+ }
+ }
+ }
+
public void noteMobileRadioPowerState(int powerState, long timestampNs) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
@@ -3449,8 +3463,8 @@
elapsedRealtimeUs, which);
}
- @Override public int getInputEventCount(int which) {
- return mInputEventCounter.getCountLocked(which);
+ @Override public long getInteractiveTime(long elapsedRealtimeUs, int which) {
+ return mInteractiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@Override public long getPhoneOnTime(long elapsedRealtimeUs, int which) {
@@ -5499,7 +5513,6 @@
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase);
}
- mInputEventCounter = new Counter(mOnBatteryTimeBase);
mPhoneOnTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null,
@@ -5530,6 +5543,7 @@
}
mAudioOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase);
mVideoOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
+ mInteractiveTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
mOnBattery = mOnBatteryInternal = false;
long uptime = SystemClock.uptimeMillis() * 1000;
long realtime = SystemClock.elapsedRealtime() * 1000;
@@ -5713,7 +5727,7 @@
}
public boolean isScreenOn() {
- return mScreenOn;
+ return mScreenState == Display.STATE_ON;
}
void initTimes(long uptime, long realtime) {
@@ -5753,7 +5767,7 @@
mOnBatteryTimeBase.reset(uptime, realtime);
mOnBatteryScreenOffTimeBase.reset(uptime, realtime);
if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) == 0) {
- if (mScreenOn) {
+ if (mScreenState == Display.STATE_ON) {
mDischargeScreenOnUnplugLevel = mHistoryCur.batteryLevel;
mDischargeScreenOffUnplugLevel = 0;
} else {
@@ -5773,7 +5787,7 @@
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].reset(false);
}
- mInputEventCounter.reset(false);
+ mInteractiveTimer.reset(false);
mPhoneOnTimer.reset(false);
mAudioOnTimer.reset(false);
mVideoOnTimer.reset(false);
@@ -5874,7 +5888,8 @@
updateKernelWakelocksLocked();
updateNetworkActivityLocked(NET_UPDATE_ALL, SystemClock.elapsedRealtime());
if (mOnBatteryInternal) {
- updateDischargeScreenLevelsLocked(mScreenOn, mScreenOn);
+ final boolean screenOn = mScreenState == Display.STATE_ON;
+ updateDischargeScreenLevelsLocked(screenOn, screenOn);
}
}
@@ -5888,6 +5903,7 @@
final long uptime = mSecUptime * 1000;
final long realtime = mSecRealtime * 1000;
+ final boolean screenOn = mScreenState == Display.STATE_ON;
if (onBattery) {
// We will reset our status if we are unplugging after the
// battery was last full, or the level is at 100, or
@@ -5916,7 +5932,7 @@
}
addHistoryRecordLocked(mSecRealtime, mSecUptime);
mDischargeCurrentLevel = mDischargeUnplugLevel = level;
- if (mScreenOn) {
+ if (screenOn) {
mDischargeScreenOnUnplugLevel = level;
mDischargeScreenOffUnplugLevel = 0;
} else {
@@ -5925,7 +5941,7 @@
}
mDischargeAmountScreenOn = 0;
mDischargeAmountScreenOff = 0;
- updateTimeBasesLocked(true, !mScreenOn, uptime, realtime);
+ updateTimeBasesLocked(true, !screenOn, uptime, realtime);
} else {
pullPendingStateUpdatesLocked();
mHistoryCur.batteryLevel = (byte)level;
@@ -5938,8 +5954,8 @@
mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
}
- updateDischargeScreenLevelsLocked(mScreenOn, mScreenOn);
- updateTimeBasesLocked(false, !mScreenOn, uptime, realtime);
+ updateDischargeScreenLevelsLocked(screenOn, screenOn);
+ updateTimeBasesLocked(false, !screenOn, uptime, realtime);
mNumChargeStepDurations = 0;
mLastChargeStepLevel = level;
mLastChargeStepTime = -1;
@@ -6475,7 +6491,7 @@
public int getDischargeAmountScreenOn() {
synchronized(this) {
int val = mDischargeAmountScreenOn;
- if (mOnBattery && mScreenOn
+ if (mOnBattery && mScreenState == Display.STATE_ON
&& mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
}
@@ -6486,7 +6502,7 @@
public int getDischargeAmountScreenOnSinceCharge() {
synchronized(this) {
int val = mDischargeAmountScreenOnSinceCharge;
- if (mOnBattery && mScreenOn
+ if (mOnBattery && mScreenState == Display.STATE_ON
&& mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
}
@@ -6497,7 +6513,7 @@
public int getDischargeAmountScreenOff() {
synchronized(this) {
int val = mDischargeAmountScreenOff;
- if (mOnBattery && !mScreenOn
+ if (mOnBattery && mScreenState != Display.STATE_ON
&& mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
}
@@ -6508,7 +6524,7 @@
public int getDischargeAmountScreenOffSinceCharge() {
synchronized(this) {
int val = mDischargeAmountScreenOffSinceCharge;
- if (mOnBattery && !mScreenOn
+ if (mOnBattery && mScreenState != Display.STATE_ON
&& mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
}
@@ -6915,12 +6931,13 @@
mStartCount++;
- mScreenOn = false;
+ mScreenState = Display.STATE_UNKNOWN;
mScreenOnTimer.readSummaryFromParcelLocked(in);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
}
- mInputEventCounter.readSummaryFromParcelLocked(in);
+ mInteractive = false;
+ mInteractiveTimer.readSummaryFromParcelLocked(in);
mPhoneOn = false;
mPhoneOnTimer.readSummaryFromParcelLocked(in);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
@@ -7175,7 +7192,7 @@
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
- mInputEventCounter.writeSummaryFromParcelLocked(out);
+ mInteractiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -7431,13 +7448,12 @@
mOnBatteryTimeBase.readFromParcel(in);
mOnBatteryScreenOffTimeBase.readFromParcel(in);
- mScreenOn = false;
+ mScreenState = Display.STATE_UNKNOWN;
mScreenOnTimer = new StopwatchTimer(null, -1, null, mOnBatteryTimeBase, in);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase,
in);
}
- mInputEventCounter = new Counter(mOnBatteryTimeBase, in);
mPhoneOn = false;
mPhoneOnTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
@@ -7461,19 +7477,25 @@
mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
mWifiOn = false;
- mWifiOnTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+ mWifiOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase, in);
mGlobalWifiRunning = false;
- mGlobalWifiRunningTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+ mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase, in);
for (int i=0; i<NUM_WIFI_STATES; i++) {
mWifiStateTimer[i] = new StopwatchTimer(null, -600-i,
null, mOnBatteryTimeBase, in);
}
mBluetoothOn = false;
- mBluetoothOnTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+ mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase, in);
for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i,
null, mOnBatteryTimeBase, in);
}
+ mAudioOn = false;
+ mAudioOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase);
+ mVideoOn = false;
+ mVideoOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
+ mInteractive = false;
+ mInteractiveTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase, in);
mDischargeUnplugLevel = in.readInt();
mDischargePlugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
@@ -7571,7 +7593,7 @@
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].writeToParcel(out, uSecRealtime);
}
- mInputEventCounter.writeToParcel(out);
+ mInteractiveTimer.writeToParcel(out, uSecRealtime);
mPhoneOnTimer.writeToParcel(out, uSecRealtime);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
@@ -7688,8 +7710,8 @@
pr.println("*** Screen brightness #" + i + ":");
mScreenBrightnessTimer[i].logState(pr, " ");
}
- pr.println("*** Input event counter:");
- mInputEventCounter.logState(pr, " ");
+ pr.println("*** Interactive timer:");
+ mInteractiveTimer.logState(pr, " ");
pr.println("*** Phone timer:");
mPhoneOnTimer.logState(pr, " ");
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index d1d1a52..75feb5d 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -33,7 +33,8 @@
void animateCollapsePanels();
void setSystemUiVisibility(int vis, int mask);
void topAppWindowChanged(boolean menuVisible);
- void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
+ void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher);
void setHardKeyboardStatus(boolean available, boolean enabled);
void toggleRecentApps();
void preloadRecentApps();
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 6428e15..cf334c3 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -31,7 +31,8 @@
void setIconVisibility(String slot, boolean visible);
void removeIcon(String slot);
void topAppWindowChanged(boolean menuVisible);
- void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
+ void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher);
void expandSettingsPanel();
void setCurrentUser(int newUserId);
@@ -42,7 +43,7 @@
out int[] switches, out List<IBinder> binders);
void onPanelRevealed();
void onPanelHidden();
- void onNotificationClick(String pkg, String tag, int id, int userId);
+ void onNotificationClick(String key);
void onNotificationError(String pkg, String tag, int id,
int uid, int initialPid, String message, int userId);
void onClearAllNotifications(int userId);
diff --git a/core/java/com/android/internal/util/LegacyNotificationUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
similarity index 93%
rename from core/java/com/android/internal/util/LegacyNotificationUtil.java
rename to core/java/com/android/internal/util/NotificationColorUtil.java
index 0394bbc..f38cbde 100644
--- a/core/java/com/android/internal/util/LegacyNotificationUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -24,6 +24,7 @@
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.VectorDrawable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.TextAppearanceSpan;
@@ -38,21 +39,21 @@
*
* @hide
*/
-public class LegacyNotificationUtil {
+public class NotificationColorUtil {
- private static final String TAG = "LegacyNotificationUtil";
+ private static final String TAG = "NotificationColorUtil";
private static final Object sLock = new Object();
- private static LegacyNotificationUtil sInstance;
+ private static NotificationColorUtil sInstance;
private final ImageUtils mImageUtils = new ImageUtils();
private final WeakHashMap<Bitmap, Pair<Boolean, Integer>> mGrayscaleBitmapCache =
new WeakHashMap<Bitmap, Pair<Boolean, Integer>>();
- public static LegacyNotificationUtil getInstance() {
+ public static NotificationColorUtil getInstance() {
synchronized (sLock) {
if (sInstance == null) {
- sInstance = new LegacyNotificationUtil();
+ sInstance = new NotificationColorUtil();
}
return sInstance;
}
@@ -107,6 +108,9 @@
AnimationDrawable ad = (AnimationDrawable) d;
int count = ad.getNumberOfFrames();
return count > 0 && isGrayscale(ad.getFrame(0));
+ } else if (d instanceof VectorDrawable) {
+ // We just assume you're doing the right thing if using vectors
+ return true;
} else {
return false;
}
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index a54b364..f6722a6 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -30,7 +30,7 @@
* @return the non-null reference that was validated
* @throws NullPointerException if {@code reference} is null
*/
- public static <T> T checkNotNull(T reference) {
+ public static <T> T checkNotNull(final T reference) {
if (reference == null) {
throw new NullPointerException();
}
@@ -47,7 +47,7 @@
* @return the non-null reference that was validated
* @throws NullPointerException if {@code reference} is null
*/
- public static <T> T checkNotNull(T reference, Object errorMessage) {
+ public static <T> T checkNotNull(final T reference, final Object errorMessage) {
if (reference == null) {
throw new NullPointerException(String.valueOf(errorMessage));
}
@@ -61,7 +61,7 @@
* @param expression a boolean expression
* @throws IllegalStateException if {@code expression} is false
*/
- public static void checkState(boolean expression) {
+ public static void checkState(final boolean expression) {
if (!expression) {
throw new IllegalStateException();
}
@@ -71,11 +71,178 @@
* Check the requested flags, throwing if any requested flags are outside
* the allowed set.
*/
- public static void checkFlagsArgument(int requestedFlags, int allowedFlags) {
+ public static void checkFlagsArgument(final int requestedFlags, final int allowedFlags) {
if ((requestedFlags & allowedFlags) != requestedFlags) {
throw new IllegalArgumentException("Requested flags 0x"
+ Integer.toHexString(requestedFlags) + ", but only 0x"
+ Integer.toHexString(allowedFlags) + " are allowed");
}
}
+
+ /**
+ * Ensures that that the argument numeric value is non-negative.
+ *
+ * @param value a numeric int value
+ * @param errorMessage the exception message to use if the check fails
+ * @return the validated numeric value
+ * @throws IllegalArgumentException if {@code value} was negative
+ */
+ public static int checkArgumentNonnegative(final int value, final String errorMessage) {
+ if (value < 0) {
+ throw new IllegalArgumentException(errorMessage);
+ }
+
+ return value;
+ }
+
+ /**
+ * Ensures that that the argument numeric value is non-negative.
+ *
+ * @param value a numeric long value
+ * @param errorMessage the exception message to use if the check fails
+ * @return the validated numeric value
+ * @throws IllegalArgumentException if {@code value} was negative
+ */
+ public static long checkArgumentNonnegative(final long value, final String errorMessage) {
+ if (value < 0) {
+ throw new IllegalArgumentException(errorMessage);
+ }
+
+ return value;
+ }
+
+ /**
+ * Ensures that that the argument numeric value is positive.
+ *
+ * @param value a numeric int value
+ * @param errorMessage the exception message to use if the check fails
+ * @return the validated numeric value
+ * @throws IllegalArgumentException if {@code value} was not positive
+ */
+ public static int checkArgumentPositive(final int value, final String errorMessage) {
+ if (value <= 0) {
+ throw new IllegalArgumentException(errorMessage);
+ }
+
+ return value;
+ }
+
+ /**
+ * Ensures that the argument floating point value is a finite number.
+ *
+ * <p>A finite number is defined to be both representable (that is, not NaN) and
+ * not infinite (that is neither positive or negative infinity).</p>
+ *
+ * @param value a floating point value
+ * @param valueName the name of the argument to use if the check fails
+ *
+ * @return the validated floating point value
+ *
+ * @throws IllegalArgumentException if {@code value} was not finite
+ */
+ public static float checkArgumentFinite(final float value, final String valueName) {
+ if (Float.isNaN(value)) {
+ throw new IllegalArgumentException(valueName + " must not be NaN");
+ } else if (Float.isInfinite(value)) {
+ throw new IllegalArgumentException(valueName + " must not be infinite");
+ }
+
+ return value;
+ }
+
+ /**
+ * Ensures that the argument floating point value is within the inclusive range.
+ *
+ * <p>While this can be used to range check against +/- infinity, note that all NaN numbers
+ * will always be out of range.</p>
+ *
+ * @param value a floating point value
+ * @param lower the lower endpoint of the inclusive range
+ * @param upper the upper endpoint of the inclusive range
+ * @param valueName the name of the argument to use if the check fails
+ *
+ * @return the validated floating point value
+ *
+ * @throws IllegalArgumentException if {@code value} was not within the range
+ */
+ public static float checkArgumentInRange(float value, float lower, float upper,
+ String valueName) {
+ if (Float.isNaN(value)) {
+ throw new IllegalArgumentException(valueName + " must not be NaN");
+ } else if (value < lower) {
+ throw new IllegalArgumentException(
+ String.format(
+ "%s is out of range of [%f, %f] (too low)", valueName, lower, upper));
+ } else if (value > upper) {
+ throw new IllegalArgumentException(
+ String.format(
+ "%s is out of range of [%f, %f] (too high)", valueName, lower, upper));
+ }
+
+ return value;
+ }
+
+ /**
+ * Ensures that the array is not {@code null}, and none if its elements are {@code null}.
+ *
+ * @param value an array of boxed objects
+ * @param valueName the name of the argument to use if the check fails
+ *
+ * @return the validated array
+ *
+ * @throws NullPointerException if the {@code value} or any of its elements were {@code null}
+ */
+ public static <T> T[] checkArrayElementsNotNull(final T[] value, final String valueName) {
+ if (value == null) {
+ throw new NullPointerException(valueName + " must not be null");
+ }
+
+ for (int i = 0; i < value.length; ++i) {
+ if (value[i] == null) {
+ throw new NullPointerException(
+ String.format("%s[%d] must not be null", valueName, i));
+ }
+ }
+
+ return value;
+ }
+
+ /**
+ * Ensures that all elements in the argument floating point array are within the inclusive range
+ *
+ * <p>While this can be used to range check against +/- infinity, note that all NaN numbers
+ * will always be out of range.</p>
+ *
+ * @param value a floating point array of values
+ * @param lower the lower endpoint of the inclusive range
+ * @param upper the upper endpoint of the inclusive range
+ * @param valueName the name of the argument to use if the check fails
+ *
+ * @return the validated floating point value
+ *
+ * @throws IllegalArgumentException if any of the elements in {@code value} were out of range
+ * @throws NullPointerException if the {@code value} was {@code null}
+ */
+ public static float[] checkArrayElementsInRange(float[] value, float lower, float upper,
+ String valueName) {
+ checkNotNull(value, valueName + " must not be null");
+
+ for (int i = 0; i < value.length; ++i) {
+ float v = value[i];
+
+ if (Float.isNaN(v)) {
+ throw new IllegalArgumentException(valueName + "[" + i + "] must not be NaN");
+ } else if (v < lower) {
+ throw new IllegalArgumentException(
+ String.format("%s[%d] is out of range of [%f, %f] (too low)",
+ valueName, i, lower, upper));
+ } else if (v > upper) {
+ throw new IllegalArgumentException(
+ String.format("%s[%d] is out of range of [%f, %f] (too high)",
+ valueName, i, lower, upper));
+ }
+ }
+
+ return value;
+ }
}
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index b380403..bc92c4a 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -46,6 +46,8 @@
public static final int BASE_WIFI_MONITOR = 0x00024000;
public static final int BASE_WIFI_MANAGER = 0x00025000;
public static final int BASE_WIFI_CONTROLLER = 0x00026000;
+ public static final int BASE_WIFI_SCANNER = 0x00027000;
+ public static final int BASE_WIFI_SCANNER_SERVICE = 0x00027100;
public static final int BASE_DHCP = 0x00030000;
public static final int BASE_DATA_CONNECTION = 0x00040000;
public static final int BASE_DATA_CONNECTION_AC = 0x00041000;
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index d664058..5a12893 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -53,6 +53,7 @@
private final MenuAdapter mAdapter;
private final boolean mOverflowOnly;
private final int mPopupMaxWidth;
+ private final int mPopupStyleAttr;
private View mAnchorView;
private ListPopupWindow mPopup;
@@ -72,20 +73,21 @@
private int mDropDownGravity = Gravity.NO_GRAVITY;
public MenuPopupHelper(Context context, MenuBuilder menu) {
- this(context, menu, null, false);
+ this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle);
}
public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) {
- this(context, menu, anchorView, false);
+ this(context, menu, anchorView, false, com.android.internal.R.attr.popupMenuStyle);
}
- public MenuPopupHelper(Context context, MenuBuilder menu,
- View anchorView, boolean overflowOnly) {
+ public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView,
+ boolean overflowOnly, int popupStyleAttr) {
mContext = context;
mInflater = LayoutInflater.from(context);
mMenu = menu;
mAdapter = new MenuAdapter(mMenu);
mOverflowOnly = overflowOnly;
+ mPopupStyleAttr = popupStyleAttr;
final Resources res = context.getResources();
mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
@@ -119,7 +121,7 @@
}
public boolean tryShow() {
- mPopup = new ListPopupWindow(mContext, null, com.android.internal.R.attr.popupMenuStyle);
+ mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr);
mPopup.setOnDismissListener(this);
mPopup.setOnItemClickListener(this);
mPopup.setAdapter(mAdapter);
@@ -272,7 +274,7 @@
@Override
public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
if (subMenu.hasVisibleItems()) {
- MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView, false);
+ MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView);
subPopup.setCallback(mPresenterCallback);
boolean preserveIconSpacing = false;
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index c9dff1a..19d58bf 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -16,18 +16,22 @@
package com.android.internal.widget;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.view.ViewGroup;
-import android.view.WindowInsets;
-import com.android.internal.app.WindowDecorActionBar;
-
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Canvas;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.util.AttributeSet;
+import android.util.IntProperty;
+import android.util.Property;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewPropertyAnimator;
+import android.view.WindowInsets;
+import android.widget.OverScroller;
/**
* Special layout for the containing of an overlay action bar (and its
@@ -38,7 +42,7 @@
private static final String TAG = "ActionBarOverlayLayout";
private int mActionBarHeight;
- private WindowDecorActionBar mActionBar;
+ //private WindowDecorActionBar mActionBar;
private int mWindowVisibility = View.VISIBLE;
// The main UI elements that we handle the layout of.
@@ -54,6 +58,10 @@
private boolean mIgnoreWindowContentOverlay;
private boolean mOverlayMode;
+ private boolean mHasNonEmbeddedTabs;
+ private boolean mHideOnContentScroll;
+ private boolean mAnimatingForFling;
+ private int mHideOnContentScrollReference;
private int mLastSystemUiVisibility;
private final Rect mBaseContentInsets = new Rect();
private final Rect mLastBaseContentInsets = new Rect();
@@ -62,6 +70,84 @@
private final Rect mInnerInsets = new Rect();
private final Rect mLastInnerInsets = new Rect();
+ private ActionBarVisibilityCallback mActionBarVisibilityCallback;
+
+ private final int ACTION_BAR_ANIMATE_DELAY = 600; // ms
+
+ private OverScroller mFlingEstimator;
+
+ private ViewPropertyAnimator mCurrentActionBarTopAnimator;
+ private ViewPropertyAnimator mCurrentActionBarBottomAnimator;
+
+ private final Animator.AnimatorListener mTopAnimatorListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mCurrentActionBarTopAnimator = null;
+ mAnimatingForFling = false;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCurrentActionBarTopAnimator = null;
+ mAnimatingForFling = false;
+ }
+ };
+
+ private final Animator.AnimatorListener mBottomAnimatorListener =
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mCurrentActionBarBottomAnimator = null;
+ mAnimatingForFling = false;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCurrentActionBarBottomAnimator = null;
+ mAnimatingForFling = false;
+ }
+ };
+
+ private final Runnable mRemoveActionBarHideOffset = new Runnable() {
+ public void run() {
+ haltActionBarHideOffsetAnimations();
+ mCurrentActionBarTopAnimator = mActionBarTop.animate().translationY(0)
+ .setListener(mTopAnimatorListener);
+ if (mActionBarBottom != null && mActionBarBottom.getVisibility() != GONE) {
+ mCurrentActionBarBottomAnimator = mActionBarBottom.animate().translationY(0)
+ .setListener(mBottomAnimatorListener);
+ }
+ }
+ };
+
+ private final Runnable mAddActionBarHideOffset = new Runnable() {
+ public void run() {
+ haltActionBarHideOffsetAnimations();
+ mCurrentActionBarTopAnimator = mActionBarTop.animate()
+ .translationY(-mActionBarTop.getHeight())
+ .setListener(mTopAnimatorListener);
+ if (mActionBarBottom != null && mActionBarBottom.getVisibility() != GONE) {
+ mCurrentActionBarBottomAnimator = mActionBarBottom.animate()
+ .translationY(mActionBarBottom.getHeight())
+ .setListener(mBottomAnimatorListener);
+ }
+ }
+ };
+
+ public static final Property<ActionBarOverlayLayout, Integer> ACTION_BAR_HIDE_OFFSET =
+ new IntProperty<ActionBarOverlayLayout>("actionBarHideOffset") {
+
+ @Override
+ public void setValue(ActionBarOverlayLayout object, int value) {
+ object.setActionBarHideOffset(value);
+ }
+
+ @Override
+ public Integer get(ActionBarOverlayLayout object) {
+ return object.getActionBarHideOffset();
+ }
+ };
+
static final int[] ATTRS = new int [] {
com.android.internal.R.attr.actionBarSize,
com.android.internal.R.attr.windowContentOverlay
@@ -86,14 +172,22 @@
mIgnoreWindowContentOverlay = context.getApplicationInfo().targetSdkVersion <
Build.VERSION_CODES.KITKAT;
+
+ mFlingEstimator = new OverScroller(context);
}
- public void setActionBar(WindowDecorActionBar impl) {
- mActionBar = impl;
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ haltActionBarHideOffsetAnimations();
+ }
+
+ public void setActionBarVisibilityCallback(ActionBarVisibilityCallback cb) {
+ mActionBarVisibilityCallback = cb;
if (getWindowToken() != null) {
// This is being initialized after being added to a window;
// make sure to update all state now.
- mActionBar.setWindowVisibility(mWindowVisibility);
+ mActionBarVisibilityCallback.onWindowVisibilityChanged(mWindowVisibility);
if (mLastSystemUiVisibility != 0) {
int newVis = mLastSystemUiVisibility;
onWindowSystemUiVisibilityChanged(newVis);
@@ -114,6 +208,14 @@
Build.VERSION_CODES.KITKAT;
}
+ public boolean isInOverlayMode() {
+ return mOverlayMode;
+ }
+
+ public void setHasNonEmbeddedTabs(boolean hasNonEmbeddedTabs) {
+ mHasNonEmbeddedTabs = hasNonEmbeddedTabs;
+ }
+
public void setShowingForActionMode(boolean showing) {
if (showing) {
// Here's a fun hack: if the status bar is currently being hidden,
@@ -140,19 +242,18 @@
pullChildren();
final int diff = mLastSystemUiVisibility ^ visible;
mLastSystemUiVisibility = visible;
- final boolean barVisible = (visible&SYSTEM_UI_FLAG_FULLSCREEN) == 0;
- final boolean wasVisible = mActionBar != null ? mActionBar.isSystemShowing() : true;
- final boolean stable = (visible&SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
- if (mActionBar != null) {
+ final boolean barVisible = (visible & SYSTEM_UI_FLAG_FULLSCREEN) == 0;
+ final boolean stable = (visible & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
+ if (mActionBarVisibilityCallback != null) {
// We want the bar to be visible if it is not being hidden,
// or the app has not turned on a stable UI mode (meaning they
// are performing explicit layout around the action bar).
- mActionBar.enableContentAnimations(!stable);
- if (barVisible || !stable) mActionBar.showForSystem();
- else mActionBar.hideForSystem();
+ mActionBarVisibilityCallback.enableContentAnimations(!stable);
+ if (barVisible || !stable) mActionBarVisibilityCallback.showForSystem();
+ else mActionBarVisibilityCallback.hideForSystem();
}
- if ((diff&SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
- if (mActionBar != null) {
+ if ((diff & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
+ if (mActionBarVisibilityCallback != null) {
requestApplyInsets();
}
}
@@ -162,8 +263,8 @@
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
mWindowVisibility = visibility;
- if (mActionBar != null) {
- mActionBar.setWindowVisibility(visibility);
+ if (mActionBarVisibilityCallback != null) {
+ mActionBarVisibilityCallback.onWindowVisibilityChanged(visibility);
}
}
@@ -279,8 +380,8 @@
// This is the standard space needed for the action bar. For stable measurement,
// we can't depend on the size currently reported by it -- this must remain constant.
topInset = mActionBarHeight;
- if (mActionBar != null && mActionBar.hasNonEmbeddedTabs()) {
- View tabs = mActionBarTop.getTabContainer();
+ if (mHasNonEmbeddedTabs) {
+ final View tabs = mActionBarTop.getTabContainer();
if (tabs != null) {
// If tabs are not embedded, increase space on top to account for them.
topInset += mActionBarHeight;
@@ -395,16 +496,138 @@
return false;
}
+ @Override
+ public boolean onStartNestedScroll(View child, View target, int axes) {
+ if ((axes & SCROLL_AXIS_VERTICAL) == 0 || mActionBarTop.getVisibility() != VISIBLE) {
+ return false;
+ }
+ return mHideOnContentScroll;
+ }
+
+ @Override
+ public void onNestedScrollAccepted(View child, View target, int axes) {
+ super.onNestedScrollAccepted(child, target, axes);
+ mHideOnContentScrollReference = getActionBarHideOffset();
+ haltActionBarHideOffsetAnimations();
+ if (mActionBarVisibilityCallback != null) {
+ mActionBarVisibilityCallback.onContentScrollStarted();
+ }
+ }
+
+ @Override
+ public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
+ int dxUnconsumed, int dyUnconsumed) {
+ mHideOnContentScrollReference += dyConsumed;
+ setActionBarHideOffset(mHideOnContentScrollReference);
+ }
+
+ @Override
+ public void onStopNestedScroll(View target) {
+ super.onStopNestedScroll(target);
+ if (mHideOnContentScroll && !mAnimatingForFling) {
+ if (mHideOnContentScrollReference <= mActionBarTop.getHeight()) {
+ postRemoveActionBarHideOffset();
+ } else {
+ postAddActionBarHideOffset();
+ }
+ }
+ if (mActionBarVisibilityCallback != null) {
+ mActionBarVisibilityCallback.onContentScrollStopped();
+ }
+ }
+
+ @Override
+ public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
+ if (!mHideOnContentScroll || !consumed) {
+ return false;
+ }
+ if (shouldHideActionBarOnFling(velocityX, velocityY)) {
+ addActionBarHideOffset();
+ } else {
+ removeActionBarHideOffset();
+ }
+ mAnimatingForFling = true;
+ return true;
+ }
+
void pullChildren() {
if (mContent == null) {
mContent = findViewById(com.android.internal.R.id.content);
- mActionBarTop = (ActionBarContainer)findViewById(
+ mActionBarTop = (ActionBarContainer) findViewById(
com.android.internal.R.id.action_bar_container);
mActionBarView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
mActionBarBottom = findViewById(com.android.internal.R.id.split_action_bar);
}
}
+ public void setHideOnContentScrollEnabled(boolean hideOnContentScroll) {
+ if (hideOnContentScroll != mHideOnContentScroll) {
+ mHideOnContentScroll = hideOnContentScroll;
+ if (!hideOnContentScroll) {
+ stopNestedScroll();
+ haltActionBarHideOffsetAnimations();
+ setActionBarHideOffset(0);
+ }
+ }
+ }
+
+ public boolean isHideOnContentScrollEnabled() {
+ return mHideOnContentScroll;
+ }
+
+ public int getActionBarHideOffset() {
+ return mActionBarTop != null ? -((int) mActionBarTop.getTranslationY()) : 0;
+ }
+
+ public void setActionBarHideOffset(int offset) {
+ haltActionBarHideOffsetAnimations();
+ final int topHeight = mActionBarTop.getHeight();
+ offset = Math.max(0, Math.min(offset, topHeight));
+ mActionBarTop.setTranslationY(-offset);
+ if (mActionBarBottom != null && mActionBarBottom.getVisibility() != GONE) {
+ // Match the hide offset proportionally for a split bar
+ final float fOffset = (float) offset / topHeight;
+ final int bOffset = (int) (mActionBarBottom.getHeight() * fOffset);
+ mActionBarBottom.setTranslationY(bOffset);
+ }
+ }
+
+ private void haltActionBarHideOffsetAnimations() {
+ removeCallbacks(mRemoveActionBarHideOffset);
+ removeCallbacks(mAddActionBarHideOffset);
+ if (mCurrentActionBarTopAnimator != null) {
+ mCurrentActionBarTopAnimator.cancel();
+ }
+ if (mCurrentActionBarBottomAnimator != null) {
+ mCurrentActionBarBottomAnimator.cancel();
+ }
+ }
+
+ private void postRemoveActionBarHideOffset() {
+ haltActionBarHideOffsetAnimations();
+ postDelayed(mRemoveActionBarHideOffset, ACTION_BAR_ANIMATE_DELAY);
+ }
+
+ private void postAddActionBarHideOffset() {
+ haltActionBarHideOffsetAnimations();
+ postDelayed(mAddActionBarHideOffset, ACTION_BAR_ANIMATE_DELAY);
+ }
+
+ private void removeActionBarHideOffset() {
+ haltActionBarHideOffsetAnimations();
+ mRemoveActionBarHideOffset.run();
+ }
+
+ private void addActionBarHideOffset() {
+ haltActionBarHideOffsetAnimations();
+ mAddActionBarHideOffset.run();
+ }
+
+ private boolean shouldHideActionBarOnFling(float velocityX, float velocityY) {
+ mFlingEstimator.fling(0, 0, 0, (int) velocityY, 0, 0, Integer.MIN_VALUE, Integer.MAX_VALUE);
+ final int finalY = mFlingEstimator.getFinalY();
+ return finalY > mActionBarTop.getHeight();
+ }
public static class LayoutParams extends MarginLayoutParams {
public LayoutParams(Context c, AttributeSet attrs) {
@@ -423,4 +646,13 @@
super(source);
}
}
+
+ public interface ActionBarVisibilityCallback {
+ void onWindowVisibilityChanged(int visibility);
+ void showForSystem();
+ void hideForSystem();
+ void enableContentAnimations(boolean enable);
+ void onContentScrollStarted();
+ void onContentScrollStopped();
+ }
}
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index 467d42e..674d084 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -35,7 +35,7 @@
public class SwipeDismissLayout extends FrameLayout {
private static final String TAG = "SwipeDismissLayout";
- private static final float TRANSLATION_MIN_ALPHA = 0.5f;
+ private static final float DISMISS_MIN_PROGRESS = 0.6f;
public interface OnDismissedListener {
void onDismissed(SwipeDismissLayout layout);
@@ -77,6 +77,8 @@
private OnDismissedListener mDismissedListener;
private OnSwipeProgressChangedListener mProgressListener;
+ private float mLastX;
+
public SwipeDismissLayout(Context context) {
super(context);
init(context);
@@ -95,7 +97,7 @@
private void init(Context context) {
ViewConfiguration vc = ViewConfiguration.get(getContext());
mSlop = vc.getScaledTouchSlop();
- mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 16;
+ mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
mAnimationTime = getContext().getResources().getInteger(
android.R.integer.config_shortAnimTime);
@@ -193,8 +195,8 @@
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(ev);
+ mLastX = ev.getRawX();
updateSwiping(ev);
- updateDismiss(ev);
if (mSwiping) {
setProgress(ev.getRawX() - mDownX);
break;
@@ -256,20 +258,16 @@
float absVelocityX = Math.abs(velocityX);
float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
- if (deltaX > getWidth() / 2) {
- mDismissed = true;
- } else if (absVelocityX >= mMinFlingVelocity
- && absVelocityX <= mMaxFlingVelocity
- && absVelocityY < absVelocityX / 2
- && velocityX > 0
- && deltaX > 0) {
+ if (deltaX > (getWidth() * DISMISS_MIN_PROGRESS) &&
+ absVelocityX < mMinFlingVelocity &&
+ ev.getRawX() >= mLastX) {
mDismissed = true;
}
}
// Check if the user tried to undo this.
if (mDismissed && mSwiping) {
// Check if the user's finger is actually back
- if (deltaX < getWidth() / 2) {
+ if (deltaX < (getWidth() * DISMISS_MIN_PROGRESS)) {
mDismissed = false;
}
}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index ee59c8a..8bd2e4f 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -92,6 +92,7 @@
android/graphics/BitmapFactory.cpp \
android/graphics/Camera.cpp \
android/graphics/Canvas.cpp \
+ android/graphics/CanvasProperty.cpp \
android/graphics/ColorFilter.cpp \
android/graphics/DrawFilter.cpp \
android/graphics/CreateJavaOutputStreamAdaptor.cpp \
@@ -140,6 +141,7 @@
android_util_FileObserver.cpp \
android/opengl/poly_clip.cpp.arm \
android/opengl/util.cpp.arm \
+ android_server_FingerprintManager.cpp \
android_server_NetworkManagementSocketTagger.cpp \
android_server_Watchdog.cpp \
android_ddm_DdmHandleNativeHeap.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f964cd2..66fbb8e 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -105,6 +105,7 @@
extern int register_android_content_XmlBlock(JNIEnv* env);
extern int register_android_emoji_EmojiFactory(JNIEnv* env);
extern int register_android_graphics_Canvas(JNIEnv* env);
+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_Matrix(JNIEnv* env);
@@ -1221,6 +1222,7 @@
REG_JNI(register_android_graphics_Camera),
REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
REG_JNI(register_android_graphics_Canvas),
+ REG_JNI(register_android_graphics_CanvasProperty),
REG_JNI(register_android_graphics_ColorFilter),
REG_JNI(register_android_graphics_DrawFilter),
REG_JNI(register_android_graphics_Interpolator),
diff --git a/core/jni/android/graphics/CanvasProperty.cpp b/core/jni/android/graphics/CanvasProperty.cpp
new file mode 100644
index 0000000..70e2db5
--- /dev/null
+++ b/core/jni/android/graphics/CanvasProperty.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 20014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "GraphicsJNI.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include <utils/VirtualLightRefBase.h>
+#include <CanvasProperty.h>
+
+namespace android {
+
+using namespace uirenderer;
+
+#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));
+}
+
+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);
+}
+
+#endif
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "android/graphics/CanvasProperty";
+
+static JNINativeMethod gMethods[] = {
+#ifdef USE_OPENGL_RENDERER
+ { "nCreateFloat", "(F)J", (void*) createFloat },
+ { "nCreatePaint", "(J)J", (void*) createPaint },
+ { "nUnref", "(J)V", (void*) unref },
+#endif
+};
+
+int register_android_graphics_CanvasProperty(JNIEnv* env) {
+ return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index b78b131..621534e 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -221,7 +221,7 @@
}
fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
- "(Ljava/lang/Object;)V");
+ "(Ljava/lang/ref/WeakReference;)V");
if (fields.postEvent == NULL) {
ALOGE("can't find android/graphics/SurfaceTexture.postEventFromNative");
}
@@ -338,7 +338,7 @@
static JNINativeMethod gSurfaceTextureMethods[] = {
{"nativeClassInit", "()V", (void*)SurfaceTexture_classInit },
- {"nativeInit", "(IZLjava/lang/Object;)V", (void*)SurfaceTexture_init },
+ {"nativeInit", "(IZLjava/lang/ref/WeakReference;)V", (void*)SurfaceTexture_init },
{"nativeFinalize", "()V", (void*)SurfaceTexture_finalize },
{"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize },
{"nativeUpdateTexImage", "()V", (void*)SurfaceTexture_updateTexImage },
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 957f95c..05a99a3 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -18,8 +18,12 @@
// #define LOG_NDEBUG 0
// #define LOG_NNDEBUG 0
#define LOG_TAG "CameraMetadata-JNI"
+#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
#include <string.h>
#include "jni.h"
@@ -483,12 +487,20 @@
ALOGV("%s (key = '%s')", __FUNCTION__, key);
+ sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
+
+ SortedVector<String8> vendorSections = vTags->getAllSectionNames();
+ size_t vendorSectionCount = vendorSections.size();
+
// First, find the section by the longest string match
const char *section = NULL;
size_t sectionIndex = 0;
size_t sectionLength = 0;
- for (size_t i = 0; i < ANDROID_SECTION_COUNT; ++i) {
- const char *str = camera_metadata_section_names[i];
+ size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
+ for (size_t i = 0; i < totalSectionCount; ++i) {
+
+ const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
+ vendorSections[i - ANDROID_SECTION_COUNT].string();
ALOGVV("%s: Trying to match against section '%s'",
__FUNCTION__, str);
if (strstr(key, str) == key) { // key begins with the section name
@@ -502,12 +514,11 @@
sectionIndex = i;
sectionLength = strLength;
- ALOGVV("%s: Found new best section (idx %d)", __FUNCTION__, sectionIndex);
+ ALOGVV("%s: Found new best section (%s)", __FUNCTION__, section);
}
}
}
- // TODO: vendor ext
// TODO: Make above get_camera_metadata_section_from_name ?
if (section == NULL) {
@@ -524,33 +535,47 @@
if (sectionLength + 1 >= keyLength) {
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
"Key length too short for key '%s')", key);
+ return 0;
}
// Match rest of name against the tag names in that section only
- uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
- tagBegin = camera_metadata_section_bounds[sectionIndex][0];
- tagEnd = camera_metadata_section_bounds[sectionIndex][1];
+ uint32_t tag = 0;
+ if (sectionIndex < ANDROID_SECTION_COUNT) {
+ // Match built-in tags (typically android.*)
+ uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
+ tagBegin = camera_metadata_section_bounds[sectionIndex][0];
+ tagEnd = camera_metadata_section_bounds[sectionIndex][1];
- uint32_t tag;
- for (tag = tagBegin; tag < tagEnd; ++tag) {
- const char *tagName = get_camera_metadata_tag_name(tag);
+ for (tag = tagBegin; tag < tagEnd; ++tag) {
+ const char *tagName = get_camera_metadata_tag_name(tag);
- if (strcmp(keyTagName, tagName) == 0) {
- ALOGV("%s: Found matched tag '%s' (%d)",
- __FUNCTION__, tagName, tag);
- break;
+ if (strcmp(keyTagName, tagName) == 0) {
+ ALOGV("%s: Found matched tag '%s' (%d)",
+ __FUNCTION__, tagName, tag);
+ break;
+ }
+ }
+
+ if (tag == tagEnd) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "Could not find tag name for key '%s')", key);
+ return 0;
+ }
+ } else {
+ // Match vendor tags (typically com.*)
+ const String8 sectionName(section);
+ const String8 tagName(keyTagName);
+
+ status_t res = OK;
+ if ((res = vTags->lookupTag(tagName, sectionName, &tag)) != OK) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "%s: No vendor tag matches key '%s'", __FUNCTION__, key);
+ return 0;
}
}
- // TODO: vendor ext
// TODO: Make above get_camera_metadata_tag_from_name ?
- if (tag == tagEnd) {
- jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
- "Could not find tag name for key '%s')", key);
- return 0;
- }
-
return tag;
}
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index f4bab26..fedb1b2 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -22,6 +22,7 @@
// keep these values in sync with AudioFormat.java
#define ENCODING_PCM_16BIT 2
#define ENCODING_PCM_8BIT 3
+#define ENCODING_PCM_FLOAT 4
static inline audio_format_t audioFormatToNative(int audioFormat)
{
@@ -30,6 +31,8 @@
return AUDIO_FORMAT_PCM_16_BIT;
case ENCODING_PCM_8BIT:
return AUDIO_FORMAT_PCM_8_BIT;
+ case ENCODING_PCM_FLOAT:
+ return AUDIO_FORMAT_PCM_FLOAT;
default:
return AUDIO_FORMAT_INVALID;
}
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index d8faaf3..09bdc61 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -393,13 +393,46 @@
jshortArray javaAudioData,
jint offsetInShorts, jint sizeInShorts) {
- jint read = android_media_AudioRecord_readInByteArray(env, thiz,
- (jbyteArray) javaAudioData,
- offsetInShorts*2, sizeInShorts*2);
- if (read > 0) {
- read /= 2;
+ jshort* recordBuff = NULL;
+ // get the audio recorder from which we'll read new audio samples
+ sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+ if (lpRecorder == NULL) {
+ ALOGE("Unable to retrieve AudioRecord object, can't record");
+ return 0;
}
- return read;
+
+ if (!javaAudioData) {
+ ALOGE("Invalid Java array to store recorded audio, can't record");
+ return 0;
+ }
+
+ // get the pointer to where we'll record the audio
+ // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
+ // a way that it becomes much more efficient. When doing so, we will have to prevent the
+ // AudioSystem callback to be called while in critical section (in case of media server
+ // process crash for instance)
+ recordBuff = (jshort *)env->GetShortArrayElements(javaAudioData, NULL);
+
+ if (recordBuff == NULL) {
+ ALOGE("Error retrieving destination for recorded audio data, can't record");
+ return 0;
+ }
+
+ // read the new audio data from the native AudioRecord object
+ const size_t recorderBuffSize = lpRecorder->frameCount()*lpRecorder->frameSize();
+ const size_t sizeInBytes = sizeInShorts * sizeof(short);
+ ssize_t readSize = lpRecorder->read(recordBuff + offsetInShorts * sizeof(short),
+ sizeInBytes > recorderBuffSize ?
+ recorderBuffSize : sizeInBytes);
+
+ env->ReleaseShortArrayElements(javaAudioData, recordBuff, 0);
+
+ if (readSize < 0) {
+ readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+ } else {
+ readSize /= sizeof(short);
+ }
+ return (jint) readSize;
}
// ----------------------------------------------------------------------------
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 162d0c4..da752752 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -637,14 +637,43 @@
jshortArray javaAudioData,
jint offsetInShorts, jint sizeInShorts,
jint javaAudioFormat) {
- jint written = android_media_AudioTrack_write_byte(env, thiz,
- (jbyteArray) javaAudioData,
- offsetInShorts*2, sizeInShorts*2,
- javaAudioFormat,
- JNI_TRUE /*blocking write, legacy behavior*/);
- if (written > 0) {
- written /= 2;
+
+ //ALOGV("android_media_AudioTrack_write_short(offset=%d, sizeInShorts=%d) called",
+ // offsetInShorts, sizeInShorts);
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for write()");
+ return 0;
}
+
+ // get the pointer for the audio data from the java array
+ // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
+ // a way that it becomes much more efficient. When doing so, we will have to prevent the
+ // AudioSystem callback to be called while in critical section (in case of media server
+ // process crash for instance)
+ jshort* cAudioData = NULL;
+ if (javaAudioData) {
+ cAudioData = (jshort *)env->GetShortArrayElements(javaAudioData, NULL);
+ if (cAudioData == NULL) {
+ ALOGE("Error retrieving source of audio data to play, can't play");
+ return 0; // out of memory or no data to load
+ }
+ } else {
+ ALOGE("NULL java array of audio data to play, can't play");
+ return 0;
+ }
+ jint written = writeToTrack(lpTrack, javaAudioFormat, (jbyte *)cAudioData,
+ offsetInShorts * sizeof(short), sizeInShorts * sizeof(short),
+ true /*blocking write, legacy behavior*/);
+ env->ReleaseShortArrayElements(javaAudioData, cAudioData, 0);
+
+ if (written > 0) {
+ written /= sizeof(short);
+ }
+ //ALOGV("write wrote %d (tried %d) shorts in the native AudioTrack with offset %d",
+ // (int)written, (int)(sizeInShorts), (int)offsetInShorts);
+
return written;
}
diff --git a/core/jni/android_server_FingerprintManager.cpp b/core/jni/android_server_FingerprintManager.cpp
new file mode 100644
index 0000000..f8a1fd9
--- /dev/null
+++ b/core/jni/android_server_FingerprintManager.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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 "Fingerprint-JNI"
+
+#include "JNIHelp.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <utils/Log.h>
+
+namespace android {
+
+static struct {
+ jclass clazz;
+ jmethodID notify;
+} gFingerprintManagerClassInfo;
+
+static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
+ return -1; // TODO
+}
+
+static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
+ return -1; // TODO
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod g_methods[] = {
+ { "nativeEnroll", "(I)I", (void*)nativeEnroll },
+ { "nativeRemove", "(I)I", (void*)nativeRemove },
+};
+
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(! var, "Unable to find class " className); \
+ var = jclass(env->NewGlobalRef(var));
+
+#define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
+ var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find static method" methodName);
+
+#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
+ var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find method" methodName);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+int register_android_server_FingerprintManager(JNIEnv* env) {
+ FIND_CLASS(gFingerprintManagerClassInfo.clazz,
+ "android/service/fingerprint/FingerprintManager");
+ GET_METHOD_ID(gFingerprintManagerClassInfo.notify, gFingerprintManagerClassInfo.clazz,
+ "notify", "(III)V");
+ return AndroidRuntime::registerNativeMethods(
+ env, "com/android/service/fingerprint/FingerprintManager", g_methods, NELEM(g_methods));
+}
+
+} // namespace android
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index ca840d91..fae6698 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -49,6 +49,7 @@
#include <Stencil.h>
#include <Rect.h>
#include <RenderNode.h>
+#include <CanvasProperty.h>
#include <TextLayout.h>
#include <TextLayoutCache.h>
@@ -204,32 +205,6 @@
return renderer->callDrawGLFunction(functor, dirty);
}
-static void android_view_GLES20Canvas_detachFunctor(JNIEnv* env,
- jobject clazz, jlong rendererPtr, jlong functorPtr) {
- OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
- Functor* functor = reinterpret_cast<Functor*>(functorPtr);
- renderer->detachFunctor(functor);
-}
-
-static void android_view_GLES20Canvas_attachFunctor(JNIEnv* env,
- jobject clazz, jlong rendererPtr, jlong functorPtr) {
- OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
- Functor* functor = reinterpret_cast<Functor*>(functorPtr);
- renderer->attachFunctor(functor);
-}
-
-static jint android_view_GLES20Canvas_invokeFunctors(JNIEnv* env,
- jobject clazz, jlong rendererPtr, jobject dirty) {
- OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
- android::uirenderer::Rect bounds;
- status_t status = renderer->invokeFunctors(bounds);
- if (status != DrawGlInfo::kStatusDone && dirty != NULL) {
- env->CallVoidMethod(dirty, gRectClassInfo.set,
- int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
- }
- return status;
-}
-
// ----------------------------------------------------------------------------
// Misc
// ----------------------------------------------------------------------------
@@ -543,6 +518,16 @@
renderer->drawCircle(x, y, radius, paint);
}
+static void android_view_GLES20Canvas_drawCircleProps(JNIEnv* env, jobject clazz,
+ jlong rendererPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
+ OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+ CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
+ CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
+ CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
+ CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
+ renderer->drawCircle(xProp, yProp, radiusProp, paintProp);
+}
+
static void android_view_GLES20Canvas_drawOval(JNIEnv* env, jobject clazz,
jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom,
jlong paintPtr) {
@@ -988,10 +973,6 @@
{ "nGetStencilSize", "()I", (void*) android_view_GLES20Canvas_getStencilSize },
{ "nCallDrawGLFunction", "(JJ)I", (void*) android_view_GLES20Canvas_callDrawGLFunction },
- { "nDetachFunctor", "(JJ)V", (void*) android_view_GLES20Canvas_detachFunctor },
- { "nAttachFunctor", "(JJ)V", (void*) android_view_GLES20Canvas_attachFunctor },
- { "nInvokeFunctors", "(JLandroid/graphics/Rect;)I",
- (void*) android_view_GLES20Canvas_invokeFunctors },
{ "nSave", "(JI)I", (void*) android_view_GLES20Canvas_save },
{ "nRestore", "(J)V", (void*) android_view_GLES20Canvas_restore },
@@ -1033,6 +1014,7 @@
{ "nDrawRects", "(J[FIJ)V", (void*) android_view_GLES20Canvas_drawRects },
{ "nDrawRoundRect", "(JFFFFFFJ)V", (void*) android_view_GLES20Canvas_drawRoundRect },
{ "nDrawCircle", "(JFFFJ)V", (void*) android_view_GLES20Canvas_drawCircle },
+ { "nDrawCircle", "(JJJJJ)V", (void*) android_view_GLES20Canvas_drawCircleProps },
{ "nDrawOval", "(JFFFFJ)V", (void*) android_view_GLES20Canvas_drawOval },
{ "nDrawArc", "(JFFFFFFZJ)V", (void*) android_view_GLES20Canvas_drawArc },
{ "nDrawPoints", "(J[FIIJ)V", (void*) android_view_GLES20Canvas_drawPoints },
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
index 2e8dccf..8a426ac 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -74,15 +74,10 @@
} gRectClassInfo;
static struct {
- jfieldID mFinalizer;
- jfieldID mNativeCanvas;
jfieldID mSurfaceFormat;
+ jmethodID safeCanvasSwap;
} gCanvasClassInfo;
-static struct {
- jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
#define GET_INT(object, field) \
env->GetIntField(object, field)
@@ -146,15 +141,6 @@
// Canvas management
// ----------------------------------------------------------------------------
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
- jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
- SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
- GET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas));
- SET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas, (long) newCanvas);
- SET_LONG(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (long) newCanvas);
- SkSafeUnref(previousCanvas);
-}
-
static inline SkBitmap::Config convertPixelFormat(int32_t format) {
switch (format) {
case PIXEL_FORMAT_RGBA_8888:
@@ -213,7 +199,7 @@
SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer->getPixelFormat());
SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
- swapCanvasPtr(env, canvas, nativeCanvas);
+ INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
SkRect clipRect;
clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
@@ -233,7 +219,7 @@
GraphicBufferWrapper* wrapper =
reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
SkCanvas* nativeCanvas = SkNEW(SkCanvas);
- swapCanvasPtr(env, canvas, nativeCanvas);
+ INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
if (wrapper) {
status_t status = wrapper->buffer->unlock();
@@ -332,13 +318,8 @@
GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
FIND_CLASS(clazz, "android/graphics/Canvas");
- GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
- "Landroid/graphics/Canvas$CanvasFinalizer;");
- GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I");
-
- FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
- GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
+ GET_METHOD_ID(gCanvasClassInfo.safeCanvasSwap, clazz, "safeCanvasSwap", "(JZ)V");
return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index b92c992..3be013b 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -16,8 +16,6 @@
#define LOG_TAG "OpenGLRenderer"
-#include "android_view_RenderNodeAnimator.h"
-
#include "jni.h"
#include "GraphicsJNI.h"
#include <nativehelper/JNIHelp.h>
@@ -47,46 +45,93 @@
return env;
}
-RenderNodeAnimator::RenderNodeAnimator(JNIEnv* env, jobject weakThis,
- RenderProperty property, DeltaValueType deltaType, float delta)
- : RenderPropertyAnimator(property, deltaType, delta) {
- mWeakThis = env->NewGlobalRef(weakThis);
- env->GetJavaVM(&mJvm);
-}
+class AnimationListenerBridge : public AnimationListener {
+public:
+ // This holds a strong reference to a Java WeakReference<T> object. This avoids
+ // cyclic-references-of-doom. If you think "I know, just use NewWeakGlobalRef!"
+ // then you end up with basically a PhantomReference, which is totally not
+ // what we want.
+ AnimationListenerBridge(JNIEnv* env, jobject weakThis) {
+ mWeakThis = env->NewGlobalRef(weakThis);
+ env->GetJavaVM(&mJvm);
+ }
-RenderNodeAnimator::~RenderNodeAnimator() {
- JNIEnv* env = getEnv(mJvm);
- env->DeleteGlobalRef(mWeakThis);
- mWeakThis = NULL;
-}
+ virtual ~AnimationListenerBridge() {
+ JNIEnv* env = getEnv(mJvm);
+ env->DeleteGlobalRef(mWeakThis);
+ mWeakThis = NULL;
+ }
-void RenderNodeAnimator::callOnFinished() {
- JNIEnv* env = getEnv(mJvm);
- env->CallStaticVoidMethod(
- gRenderNodeAnimatorClassInfo.clazz,
- gRenderNodeAnimatorClassInfo.callOnFinished,
- mWeakThis);
-}
+ virtual void onAnimationFinished(BaseAnimator*) {
+ JNIEnv* env = getEnv(mJvm);
+ env->CallStaticVoidMethod(
+ gRenderNodeAnimatorClassInfo.clazz,
+ gRenderNodeAnimatorClassInfo.callOnFinished,
+ mWeakThis);
+ }
-static jlong createAnimator(JNIEnv* env, jobject clazz, jobject weakThis,
- jint property, jint deltaType, jfloat deltaValue) {
- LOG_ALWAYS_FATAL_IF(property < 0 || property > RenderNodeAnimator::ALPHA,
+private:
+ JavaVM* mJvm;
+ jobject mWeakThis;
+};
+
+static inline RenderPropertyAnimator::RenderProperty toRenderProperty(jint property) {
+ LOG_ALWAYS_FATAL_IF(property < 0 || property > RenderPropertyAnimator::ALPHA,
"Invalid property %d", property);
+ 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);
+}
- RenderNodeAnimator* animator = new RenderNodeAnimator(env, weakThis,
- static_cast<RenderPropertyAnimator::RenderProperty>(property),
- static_cast<RenderPropertyAnimator::DeltaValueType>(deltaType),
- deltaValue);
+static inline CanvasPropertyPaintAnimator::PaintField toPaintField(jint field) {
+ LOG_ALWAYS_FATAL_IF(field < 0
+ || field > CanvasPropertyPaintAnimator::ALPHA,
+ "Invalid paint field %d", field);
+ return static_cast<CanvasPropertyPaintAnimator::PaintField>(field);
+}
+
+static jlong createAnimator(JNIEnv* env, jobject clazz, jobject weakThis,
+ jint propertyRaw, jint deltaTypeRaw, jfloat deltaValue) {
+ RenderPropertyAnimator::RenderProperty property = toRenderProperty(propertyRaw);
+ RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
+
+ BaseAnimator* animator = new RenderPropertyAnimator(property, deltaType, deltaValue);
animator->incStrong(0);
+ 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);
+ CanvasPropertyPrimitive* canvasProperty = reinterpret_cast<CanvasPropertyPrimitive*>(canvasPropertyPtr);
+ BaseAnimator* animator = new CanvasPropertyPrimitiveAnimator(canvasProperty, deltaType, deltaValue);
+ animator->incStrong(0);
+ 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);
+ CanvasPropertyPaint* canvasProperty = reinterpret_cast<CanvasPropertyPaint*>(canvasPropertyPtr);
+ CanvasPropertyPaintAnimator::PaintField paintField = toPaintField(paintFieldRaw);
+ BaseAnimator* animator = new CanvasPropertyPaintAnimator(
+ canvasProperty, paintField, deltaType, deltaValue);
+ animator->incStrong(0);
+ 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");
- RenderNodeAnimator* animator = reinterpret_cast<RenderNodeAnimator*>(animatorPtr);
+ BaseAnimator* animator = reinterpret_cast<BaseAnimator*>(animatorPtr);
animator->setDuration(duration);
}
@@ -106,6 +151,8 @@
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 },
{ "nSetDuration", "(JI)V", (void*) setDuration },
{ "nUnref", "(J)V", (void*) unref },
#endif
diff --git a/core/jni/android_view_RenderNodeAnimator.h b/core/jni/android_view_RenderNodeAnimator.h
deleted file mode 100644
index 760ca91..0000000
--- a/core/jni/android_view_RenderNodeAnimator.h
+++ /dev/null
@@ -1,40 +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.
- */
-
-#include "jni.h"
-
-#ifdef USE_OPENGL_RENDERER
-
-#include <Animator.h>
-
-namespace android {
-
-class RenderNodeAnimator : public uirenderer::RenderPropertyAnimator {
-public:
- RenderNodeAnimator(JNIEnv* env, jobject callbackObject,
- RenderProperty property, DeltaValueType deltaType, float delta);
- virtual ~RenderNodeAnimator();
-
- void callOnFinished();
-
-private:
- JavaVM* mJvm;
- jobject mWeakThis;
-};
-
-}
-
-#endif
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index ab6c1e0..6c9d060 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -69,15 +69,10 @@
} gRectClassInfo;
static struct {
- jfieldID mFinalizer;
- jfieldID mNativeCanvas;
jfieldID mSurfaceFormat;
+ jmethodID safeCanvasSwap;
} gCanvasClassInfo;
-static struct {
- jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
// ----------------------------------------------------------------------------
// this is just a pointer we use to pass to inc/decStrong
@@ -191,15 +186,6 @@
}
}
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
- jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
- SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
- env->GetLongField(canvasObj, gCanvasClassInfo.mNativeCanvas));
- env->SetLongField(canvasObj, gCanvasClassInfo.mNativeCanvas, (jlong)newCanvas);
- env->SetLongField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (jlong)newCanvas);
- SkSafeUnref(previousCanvas);
-}
-
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
@@ -247,7 +233,7 @@
}
SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
- swapCanvasPtr(env, canvasObj, nativeCanvas);
+ env->CallVoidMethod(canvasObj, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
if (dirtyRectPtr) {
nativeCanvas->clipRect( SkRect::Make(reinterpret_cast<const SkIRect&>(dirtyRect)) );
@@ -277,7 +263,7 @@
// detach the canvas from the surface
SkCanvas* nativeCanvas = SkNEW(SkCanvas);
- swapCanvasPtr(env, canvasObj, nativeCanvas);
+ env->CallVoidMethod(canvasObj, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
// unlock surface
status_t err = surface->unlockAndPost();
@@ -388,12 +374,8 @@
gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "(J)V");
clazz = env->FindClass("android/graphics/Canvas");
- gCanvasClassInfo.mFinalizer = env->GetFieldID(clazz, "mFinalizer", "Landroid/graphics/Canvas$CanvasFinalizer;");
- gCanvasClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "J");
gCanvasClassInfo.mSurfaceFormat = env->GetFieldID(clazz, "mSurfaceFormat", "I");
-
- clazz = env->FindClass("android/graphics/Canvas$CanvasFinalizer");
- gCanvasFinalizerClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "J");
+ gCanvasClassInfo.safeCanvasSwap = env->GetMethodID(clazz, "safeCanvasSwap", "(JZ)V");
clazz = env->FindClass("android/graphics/Rect");
gRectClassInfo.left = env->GetFieldID(clazz, "left", "I");
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index c293c7a..5a935a9 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -50,6 +50,8 @@
"android/view/Surface$OutOfResourcesException";
static struct {
+ jclass clazz;
+ jmethodID ctor;
jfieldID width;
jfieldID height;
jfieldID refreshRate;
@@ -346,24 +348,49 @@
SurfaceComposerClient::setDisplayProjection(token, orientation, layerStackRect, displayRect);
}
-static jboolean nativeGetDisplayInfo(JNIEnv* env, jclass clazz,
- jobject tokenObj, jobject infoObj) {
+static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz,
+ jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
- if (token == NULL) return JNI_FALSE;
+ if (token == NULL) return NULL;
- DisplayInfo info;
- if (SurfaceComposerClient::getDisplayInfo(token, &info)) {
- return JNI_FALSE;
+ Vector<DisplayInfo> configs;
+ if (SurfaceComposerClient::getDisplayConfigs(token, &configs) != NO_ERROR ||
+ configs.size() == 0) {
+ return NULL;
}
- env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
- env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
- env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
- env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
- env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
- env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
- env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
- return JNI_TRUE;
+ jobjectArray configArray = env->NewObjectArray(configs.size(),
+ gPhysicalDisplayInfoClassInfo.clazz, NULL);
+
+ for (size_t c = 0; c < configs.size(); ++c) {
+ const DisplayInfo& info = configs[c];
+ jobject infoObj = env->NewObject(gPhysicalDisplayInfoClassInfo.clazz,
+ gPhysicalDisplayInfoClassInfo.ctor);
+ env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
+ env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
+ env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
+ env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
+ env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
+ env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
+ env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
+ env->SetObjectArrayElement(configArray, static_cast<jsize>(c), infoObj);
+ env->DeleteLocalRef(infoObj);
+ }
+
+ return configArray;
+}
+
+static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+ if (token == NULL) return -1;
+ return static_cast<jint>(SurfaceComposerClient::getActiveConfig(token));
+}
+
+static jboolean nativeSetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj, jint id) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+ if (token == NULL) return JNI_FALSE;
+ status_t err = SurfaceComposerClient::setActiveConfig(token, static_cast<int>(id));
+ return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}
static void nativeBlankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
@@ -576,8 +603,12 @@
(void*)nativeSetDisplayLayerStack },
{"nativeSetDisplayProjection", "(Landroid/os/IBinder;IIIIIIIII)V",
(void*)nativeSetDisplayProjection },
- {"nativeGetDisplayInfo", "(Landroid/os/IBinder;Landroid/view/SurfaceControl$PhysicalDisplayInfo;)Z",
- (void*)nativeGetDisplayInfo },
+ {"nativeGetDisplayConfigs", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo;",
+ (void*)nativeGetDisplayConfigs },
+ {"nativeGetActiveConfig", "(Landroid/os/IBinder;)I",
+ (void*)nativeGetActiveConfig },
+ {"nativeSetActiveConfig", "(Landroid/os/IBinder;I)Z",
+ (void*)nativeSetActiveConfig },
{"nativeBlankDisplay", "(Landroid/os/IBinder;)V",
(void*)nativeBlankDisplay },
{"nativeUnblankDisplay", "(Landroid/os/IBinder;)V",
@@ -598,6 +629,9 @@
sSurfaceControlMethods, NELEM(sSurfaceControlMethods));
jclass clazz = env->FindClass("android/view/SurfaceControl$PhysicalDisplayInfo");
+ gPhysicalDisplayInfoClassInfo.clazz = static_cast<jclass>(env->NewGlobalRef(clazz));
+ gPhysicalDisplayInfoClassInfo.ctor = env->GetMethodID(gPhysicalDisplayInfoClassInfo.clazz,
+ "<init>", "()V");
gPhysicalDisplayInfoClassInfo.width = env->GetFieldID(clazz, "width", "I");
gPhysicalDisplayInfoClassInfo.height = env->GetFieldID(clazz, "height", "I");
gPhysicalDisplayInfoClassInfo.refreshRate = env->GetFieldID(clazz, "refreshRate", "F");
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index 77ede33..9258543 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -44,16 +44,11 @@
} gRectClassInfo;
static struct {
- jfieldID mFinalizer;
- jfieldID mNativeCanvas;
jfieldID mSurfaceFormat;
+ jmethodID safeCanvasSwap;
} gCanvasClassInfo;
static struct {
- jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
-static struct {
jfieldID nativeWindow;
} gTextureViewClassInfo;
@@ -125,15 +120,6 @@
}
}
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
- jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
- SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
- env->GetLongField(canvasObj, gCanvasClassInfo.mNativeCanvas));
- env->SetLongField(canvasObj, gCanvasClassInfo.mNativeCanvas, (jlong)newCanvas);
- env->SetLongField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (jlong)newCanvas);
- SkSafeUnref(previousCanvas);
-}
-
static jboolean android_view_TextureView_lockCanvas(JNIEnv* env, jobject,
jlong nativeWindow, jobject canvas, jobject dirtyRect) {
@@ -175,7 +161,7 @@
SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer.format);
SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
- swapCanvasPtr(env, canvas, nativeCanvas);
+ INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
SkRect clipRect;
clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
@@ -193,7 +179,7 @@
jlong nativeWindow, jobject canvas) {
SkCanvas* nativeCanvas = SkNEW(SkCanvas);
- swapCanvasPtr(env, canvas, nativeCanvas);
+ INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
if (nativeWindow) {
sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
@@ -241,13 +227,8 @@
GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
FIND_CLASS(clazz, "android/graphics/Canvas");
- GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
- "Landroid/graphics/Canvas$CanvasFinalizer;");
- GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I");
-
- FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
- GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
+ GET_METHOD_ID(gCanvasClassInfo.safeCanvasSwap, clazz, "safeCanvasSwap", "(JZ)V");
FIND_CLASS(clazz, "android/view/TextureView");
GET_FIELD_ID(gTextureViewClassInfo.nativeWindow, clazz, "mNativeWindow", "J");
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 58fc1e1..cdd036e 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -26,7 +26,7 @@
#include <android_runtime/android_view_Surface.h>
#include <system/window.h>
-#include "android_view_RenderNodeAnimator.h"
+#include <Animator.h>
#include <RenderNode.h>
#include <renderthread/RenderProxy.h>
#include <renderthread/RenderTask.h>
@@ -67,26 +67,34 @@
jobject mRunnable;
};
+class OnFinishedEvent {
+public:
+ OnFinishedEvent(BaseAnimator* animator, AnimationListener* listener)
+ : animator(animator), listener(listener) {}
+ sp<BaseAnimator> animator;
+ sp<AnimationListener> listener;
+};
+
class InvokeAnimationListeners : public MessageHandler {
public:
- InvokeAnimationListeners(std::vector< sp<RenderNodeAnimator> >& animators) {
- mAnimators.swap(animators);
+ InvokeAnimationListeners(std::vector<OnFinishedEvent>& events) {
+ mOnFinishedEvents.swap(events);
}
- static void callOnFinished(const sp<RenderNodeAnimator>& animator) {
- animator->callOnFinished();
+ static void callOnFinished(OnFinishedEvent& event) {
+ event.listener->onAnimationFinished(event.animator.get());
}
virtual void handleMessage(const Message& message) {
- std::for_each(mAnimators.begin(), mAnimators.end(), callOnFinished);
- mAnimators.clear();
+ std::for_each(mOnFinishedEvents.begin(), mOnFinishedEvents.end(), callOnFinished);
+ mOnFinishedEvents.clear();
}
private:
- std::vector< sp<RenderNodeAnimator> > mAnimators;
+ std::vector<OnFinishedEvent> mOnFinishedEvents;
};
-class RootRenderNode : public RenderNode, public AnimationListener {
+class RootRenderNode : public RenderNode, public AnimationHook {
public:
RootRenderNode() : RenderNode() {
mLooper = Looper::getForThread();
@@ -96,27 +104,27 @@
virtual ~RootRenderNode() {}
- void onAnimationFinished(const sp<RenderPropertyAnimator>& animator) {
- mFinishedAnimators.push_back(
- reinterpret_cast<RenderNodeAnimator*>(animator.get()));
+ virtual void callOnFinished(BaseAnimator* animator, AnimationListener* listener) {
+ OnFinishedEvent event(animator, listener);
+ mOnFinishedEvents.push_back(event);
}
virtual void prepareTree(TreeInfo& info) {
- info.animationListener = this;
+ info.animationHook = this;
RenderNode::prepareTree(info);
- info.animationListener = NULL;
+ info.animationHook = NULL;
// post all the finished stuff
- if (mFinishedAnimators.size()) {
+ if (mOnFinishedEvents.size()) {
sp<InvokeAnimationListeners> message
- = new InvokeAnimationListeners(mFinishedAnimators);
+ = new InvokeAnimationListeners(mOnFinishedEvents);
mLooper->sendMessage(message, 0);
}
}
private:
sp<Looper> mLooper;
- std::vector< sp<RenderNodeAnimator> > mFinishedAnimators;
+ std::vector<OnFinishedEvent> mOnFinishedEvents;
};
static void android_view_ThreadedRenderer_postToRenderThread(JNIEnv* env, jobject clazz,
@@ -144,6 +152,18 @@
delete proxy;
}
+static void android_view_ThreadedRenderer_setFrameInterval(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong frameIntervalNanos) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->setFrameInterval(frameIntervalNanos);
+}
+
+static jboolean android_view_ThreadedRenderer_loadSystemProperties(JNIEnv* env, jobject clazz,
+ jlong proxyPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ return proxy->loadSystemProperties();
+}
+
static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
jlong proxyPtr, jobject jsurface) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -177,11 +197,17 @@
proxy->setup(width, height);
}
-static void android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
- jlong proxyPtr, jint dirtyLeft, jint dirtyTop,
+static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jboolean opaque) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->setOpaque(opaque);
+}
+
+static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong frameTimeNanos, jint dirtyLeft, jint dirtyTop,
jint dirtyRight, jint dirtyBottom) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- proxy->syncAndDrawFrame(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
+ return proxy->syncAndDrawFrame(frameTimeNanos, dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
}
static void android_view_ThreadedRenderer_destroyCanvasAndSurface(JNIEnv* env, jobject clazz,
@@ -253,11 +279,14 @@
{ "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
{ "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
{ "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
+ { "nSetFrameInterval", "(JJ)V", (void*) android_view_ThreadedRenderer_setFrameInterval },
+ { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
{ "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
{ "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
{ "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface },
{ "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup },
- { "nSyncAndDrawFrame", "(JIIII)V", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
+ { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
+ { "nSyncAndDrawFrame", "(JJIIII)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
{ "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface },
{ "nInvokeFunctor", "(JJZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
{ "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3d3e86f..cdb77f1 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1279,7 +1279,7 @@
or recently running tasks. -->
<permission android:name="android.permission.GET_TASKS"
android:permissionGroup="android.permission-group.APP_INFO"
- android:protectionLevel="dangerous"
+ android:protectionLevel="signature|system"
android:label="@string/permlab_getTasks"
android:description="@string/permdesc_getTasks" />
<!-- @hide Allows an application to call APIs that allow it to do interactions
@@ -1295,10 +1295,9 @@
<!-- @hide Fuller form of {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
that removes restrictions on where broadcasts can be sent and allows other
types of interactions. -->
- <!-- TODO: Remove the system protection level.-->
<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
- android:protectionLevel="signature|system"
+ android:protectionLevel="signature"
android:label="@string/permlab_interactAcrossUsersFull"
android:description="@string/permdesc_interactAcrossUsersFull" />
@@ -2793,7 +2792,7 @@
<receiver android:name="com.android.server.BootReceiver"
android:primaryUserOnly="true">
- <intent-filter>
+ <intent-filter android:priority="1000">
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
diff --git a/core/res/res/anim/button_state_list_anim_quantum.xml b/core/res/res/anim/button_state_list_anim_quantum.xml
new file mode 100644
index 0000000..01989a4
--- /dev/null
+++ b/core/res/res/anim/button_state_list_anim_quantum.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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:state_enabled="true">
+ <set>
+ <objectAnimator android:propertyName="translationZ"
+ android:duration="@integer/button_pressed_animation_duration"
+ android:valueTo="@dimen/button_pressed_z"
+ android:valueType="floatType"/>
+ </set>
+ </item>
+ <!-- base state -->
+ <item>
+ <set>
+ <objectAnimator android:propertyName="translationZ"
+ android:duration="@integer/button_pressed_animation_duration"
+ android:valueTo="0"
+ android:valueType="floatType"/>
+ </set>
+ </item>
+</selector>
\ No newline at end of file
diff --git a/core/res/res/anim/popup_enter_quantum.xml b/core/res/res/anim/popup_enter_quantum.xml
new file mode 100644
index 0000000..79de26b
--- /dev/null
+++ b/core/res/res/anim/popup_enter_quantum.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false" >
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:interpolator="@interpolator/decelerate_cubic"
+ android:duration="@android:integer/config_activityShortDur" />
+</set>
diff --git a/core/res/res/anim/popup_exit_quantum.xml b/core/res/res/anim/popup_exit_quantum.xml
new file mode 100644
index 0000000..7d7d5c5
--- /dev/null
+++ b/core/res/res/anim/popup_exit_quantum.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false" >
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:interpolator="@interpolator/decelerate_cubic"
+ android:duration="@android:integer/config_activityShortDur"/>
+</set>
diff --git a/core/res/res/drawable-hdpi/stat_sys_adb_am.png b/core/res/res/drawable-hdpi/stat_sys_adb_am.png
deleted file mode 100644
index dad614c..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_adb_am.png b/core/res/res/drawable-ldpi/stat_sys_adb_am.png
deleted file mode 100644
index 0171adb..0000000
--- a/core/res/res/drawable-ldpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_adb_am.png b/core/res/res/drawable-mdpi/stat_sys_adb_am.png
deleted file mode 100644
index 5482f34..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
deleted file mode 100644
index 6351c2d..0000000
--- a/core/res/res/drawable-nodpi/platlogo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
new file mode 100644
index 0000000..8eb00fa
--- /dev/null
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size android:width="400dp" android:height="400dp"/>
+
+ <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>
+</vector>
+
+
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
new file mode 100644
index 0000000..37df348
--- /dev/null
+++ b/core/res/res/drawable-nodpi/stat_sys_adb.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="25dp" android:height="25dp"/>
+
+ <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>
+</vector>
+
+
diff --git a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
deleted file mode 100644
index e53f498..0000000
--- a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
deleted file mode 100644
index d6018dd..0000000
--- a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/notification_icon_legacy_bg.xml b/core/res/res/drawable/notification_icon_legacy_bg.xml
index 4ac67c3..cc5755d 100644
--- a/core/res/res/drawable/notification_icon_legacy_bg.xml
+++ b/core/res/res/drawable/notification_icon_legacy_bg.xml
@@ -18,5 +18,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid
- android:color="@color/notification_icon_legacy_bg_color"/>
+ android:color="@color/notification_icon_bg_color"/>
</shape>
diff --git a/core/res/res/drawable/popup_background_quantum.xml b/core/res/res/drawable/popup_background_quantum.xml
new file mode 100644
index 0000000..7e5b003
--- /dev/null
+++ b/core/res/res/drawable/popup_background_quantum.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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+
+ <corners
+ android:radius="2dp" />
+ <solid
+ android:color="?attr/colorBackground" />
+
+</shape>
diff --git a/core/res/res/layout/alert_dialog_micro.xml b/core/res/res/layout/alert_dialog_micro.xml
new file mode 100644
index 0000000..f8eb46c
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_micro.xml
@@ -0,0 +1,138 @@
+<?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
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/parentPanel"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout android:id="@+id/topPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <View android:id="@+id/titleDividerTop"
+ android:layout_width="match_parent"
+ android:layout_height="2dip"
+ android:visibility="gone"
+ android:background="@android:color/holo_blue_light" />
+ <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>
+ <View android:id="@+id/titleDivider"
+ android:layout_width="match_parent"
+ android:layout_height="2dip"
+ android:visibility="gone"
+ android:background="@android:color/holo_blue_light" />
+ <!-- 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"
+ android:divider="?android:attr/dividerHorizontal"
+ android:showDividers="beginning"
+ android:dividerPadding="0dip">
+ <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/java/android/net/ProxyProperties.aidl b/core/res/res/layout/voice_interaction_session.xml
similarity index 60%
copy from core/java/android/net/ProxyProperties.aidl
copy to core/res/res/layout/voice_interaction_session.xml
index 02ea15d..48b6579 100644
--- a/core/java/android/net/ProxyProperties.aidl
+++ b/core/res/res/layout/voice_interaction_session.xml
@@ -1,6 +1,8 @@
-/*
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/layout/alert_dialog.xml
**
-** Copyright (C) 2010 The Android Open Source Project
+** Copyright 2014, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -14,8 +16,10 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
+-->
-package android.net;
-
-parcelable ProxyProperties;
-
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+</FrameLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index eb68c39..790567e 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 05594b3..7fac03f 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"የVPN ግልጋሎትን ወደ ከፍተኛ-ደረጃ በየነ ገጽ ለማሳር ለመያዣው ይፈቅዳሉ፡፡ለተለመዱ መተግበሪያዎች አያስፈልግም፡፡"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"በልጣፍ ጠርዝ"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ልጣፍ ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"መተግበሪያው ማሳወቂያዎችን እንዲያስመጣ፣ እንዲመረምር እና እንዲያጸዳ ያስችለዋል፣ በሌሎች መተግበሪያዎች የተለጠፉትንም ጨምሮ።"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ከአንድ የማሳወቂያ አዳማጭ አገልግሎት ጋር ይሰሩ"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ያዢው የማሳወቂያ አዳማጭ አገልግሎቱን ከከፍተኛ-ደረጃ በይነገጹ ጋር እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1059,7 +1068,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>
@@ -1091,7 +1100,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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"ልጣፍ"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"ልጣፍ ለውጥ"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ማሳወቂያ አዳማጭ"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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-ar/strings.xml b/core/res/res/values-ar/strings.xml
index fa662fd..a32c74c 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الشبكة الظاهرية الخاصة (VPN). لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"الالتزام بخلفية ما"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"للسماح للمالك بالالتزام بواجهة المستوى العلوي للخلفية. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"يتيح للتطبيق استرجاع الإشعارات وفحصها ومسحها، بما في ذلك تلك التي نشرتها تطبيقات أخرى."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"الربط بخدمة تلقّي الإشعارات الصوتية"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"يتيح للمالك الربط بواجهة المستوى العلوي لخدمة تلقّي الإشعارات الصوتية. ولن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"الخلفية"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"تغيير الخلفية"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"برنامج تلقّي الإشعارات الصوتية"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 d347db6..3ebe798 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за VPN. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"обвързване с тапет"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на тапет. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Разрешава на приложението да извлича, преглежда и изчиства известия, включително публикуваните от други приложения."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"обвързване с услуга за слушател на известия"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Разрешава на притежателя да се обвърже с интерфейса от първо ниво на услуга за слушател на известия. Нормалните приложения не би трябвало никога да се нуждаят от това."</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Тапет"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Промяна на тапета"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Слушател на известия"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 fce2c4e..a767e7f 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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_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>
@@ -717,14 +726,14 @@
<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 intents de desbloqueig de pantalla"</string>
+ <string name="policylab_watchLogin" msgid="914130646942199503">"Controlar els 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">"Esborra totes les dades"</string>
+ <string name="policylab_wipeData" msgid="3910545446758639713">"Esborrar 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>
@@ -734,7 +743,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 totes les càmeres del dispositiu."</string>
+ <string name="policydesc_disableCamera" msgid="2306349042834754597">"Impedeix l\'ús de 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">
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Proveïdor de condicions"</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 2f73544..1c4e8b8 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 d1ab769..1724de1 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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="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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Baggrund"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Skift baggrund"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Underretningslytter"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 31b9c9d..e527521 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -722,11 +731,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">"Display sperren"</string>
+ <string name="policylab_forceLock" msgid="2274085384704248431">"Bildschirm 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 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 die 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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 a1d6049..296fd71 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας Vpn. Δεν απαιτείται για κανονικές εφαρμογές."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"δέσμευση σε ταπετσαρία"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας ταπετσαρίας. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"δέσμευση σε υπηρεσία ακρόασης ειδοποίησης"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ακρόασης ειδοποιήσεων. Δεν απαιτείται σε κανονικές εφαρμογές."</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Ταπετσαρία"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Αλλαγή ταπετσαρίας"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Υπηρεσία ακρόασης ειδοποίησης"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 33f0010..c4b7aa0 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 33f0010..c4b7aa0 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 620d745..1225c81 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 cd96a08..1c6aa8d 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 1d905df..1c3d94a 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 a198fbb..66b4a90 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"به دارنده اجازه میدهد که به رابط سطح بالای سرویس Vpn متصل شود. هرگز برای برنامههای معمولی مورد نیاز نیست."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"پیوند شده به تصویر زمینه"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"به دارنده اجازه میدهد تا به رابط سطح بالای تصویر زمینه متصل شود. برنامههای معمولی هرگز به این ویژگی نیاز ندارند."</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه میدهد به بازیابی، بررسی و پاک کردن اعلانها از جمله موارد پست شده توسط سایر برنامهها بپردازد."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"اتصال به یک سرویس شنونده اعلان"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"به دارنده اجازه میدهد به یک رابط سطح بالای سرویس شنونده اعلان متصل شود. هرگز نباید برای برنامههای عادی لازم شود."</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -732,7 +741,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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"تصویر زمینه"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"تغییر تصویر زمینه"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"شنونده اعلان"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 5a01910..eb2540d 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 17cda8d..276be79 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 3c0266f..6a6ed88 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 1638b6bc..957e76a 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"धारक को किसी Vpn सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"वॉलपेपर से आबद्ध करें"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"धारक को किसी वॉलपेपर के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"ऐप्स को सूचनाओं को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य ऐप्स के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना श्रवणकर्ता सेवा से जुड़ें"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"धारक को सूचना श्रवणकर्ता सेवा के शीर्ष स्तरीय इंटरफ़ेस से जुड़ने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होनी चाहिए."</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"वॉलपेपर"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"वॉलपेपर बदलें"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"सूचना श्रवणकर्ता"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 6e44150..e4db3e6 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 9697bae..6130c5e 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 682e191..a4a5f48 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Թույլ է տալիս սեփականատիրոջը միանալ Vpn ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"միանալ պաստառին"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Թույլ է տալիս սեփականատիրոջը միանալ պաստառի վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Թույլ է տալիս հավելվածին առբերել, ուսումնասիրել և մաքրել ծանուցումներն, այդ թվում նաև այլ հավելվածների կողմից գրառվածները:"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"միանալ ծանուցումների ունկնդրիչ ծառայությանը"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Թույլ է տալիս սեփականատիրոջը միանալ ծանուցումները ունկնդրող ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Պաստառ"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Փոխել պաստառը"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Ծանուցման ունկնդիր"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 105da53..6003a23 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 17530b6..0e83a2f 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 a633d1f..8002d3a 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"מאפשר למשתמש לבצע איגוד לממשק ברמה עליונה של שירות VPN. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"קשור לטפט"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של טפט. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"מאפשר לאפליקציה לאחזר, לבדוק ולמחוק התראות, כולל כאלה שפורסמו על ידי אפליקציות אחרות."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"איגוד לשירות של מאזין להתראות"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של שירות מאזין להתראות. הרשאה זו אף פעם אינה נחוצה לאפליקציות רגילים."</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"טפט"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"שנה טפט"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"מאזין להתראות"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 8905af6..704b935 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"VPNサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"壁紙にバインド"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"壁紙のトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"通知(他のアプリから投稿されたものも含む)を取得、調査、クリアすることをアプリに許可します。"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"通知リスナーサービスにバインド"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"通知リスナーサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"壁紙"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"壁紙を変更"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知リスナー"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 a500b8e..0c179c0 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"აპს შეეძლება Vpn სერვისის ზედა დონის ინტერფეისთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"ფონზე მიჭედება"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"მფლობელს შეეძლება ფონის ზედა დონის ინტერფეისთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"აპს შეეძლება მოიძიოს, გამოიკვლიოს და წაშალოს შეტყობინებები, მათ შორის სხვა აპების მიერ გამოქვეყნებული."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"შეტყობინებების მოსმენის სერვისთან დაკავშირება"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"მფლობელს შეეძლება შეტყობინებების მსმენლის სერვისის ზედა დონის ინტერფეისთან დაკავშირება. არ უნდა მოხდეს მისი გამოყენება ჩვეუელებრივი აპებისთვის.ფ"</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"ფონი"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"ფონის შეცვლა"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"შეტყობინებების მსმენელი"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 43199fa..4d6f0a3 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃសេវាកម្ម Vpn ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"ចងទៅផ្ទាំងរូបភាព"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃផ្ទាំងរូបភាព។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"ឲ្យកម្មវិធីទៅយក ពិនិត្យ និងសម្អាតការជូនដំណឹង រួមមានប្រកាសដោយកម្មវិធីផ្សេងៗ។"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ចងទៅសេវាកម្មស្ដាប់ការជូនដំណឹង"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃសេវាកម្មកម្មវិធីស្ដាប់ការជូនដំណឹង។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"ផ្ទាំងរូបភាព"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"ប្ដូរផ្ទាំងរូបភាព"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"កម្មវិធីស្ដាប់ការជូនដំណឹង"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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-ko/strings.xml b/core/res/res/values-ko/strings.xml
index c01ddd8..310b1f0 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"권한을 가진 프로그램이 VPN 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"배경화면 연결"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"권한을 가진 프로그램이 배경화면에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"앱이 다른 앱에서 게시한 알림을 비롯하여 알림을 검색하고 살펴보며 삭제할 수 있도록 허용합니다."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"알림 수신기 서비스 사용"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"권한을 가진 프로그램이 알림 수신기 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"배경화면"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"배경화면 변경"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"알림 수신기"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 548d2c0..08ba7e1 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຊື່ອມໂຍງກັບສ່ວນຕິດຕໍ່ລະດັບເທິງສຸດ ຂອງບໍລິການ VPN. ແອັບຯທົ່ວໄປບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"ເຊື່ອມໂຍງກັບພາບພື້ນຫຼັງ"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ອະນຸຍາດໃຫ້ຜູ່ໃຊ້ເຊື່ອມໂຍງກັບສ່ວນຕິດຕໍ່ລະດັບສູງສຸດ ຂອງພາບພື້ນຫຼັງໃດນຶ່ງ. ແອັບຯທຳມະດາບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"ອະນຸຍາດໃຫ້ແອັບຯດຶງຂໍ້ມູນ, ກວດສອບ ແລະລຶບລ້າງການແຈ້ງເຕືອນ ຮວມທັງພວກທີ່ໂພສໂດຍແອັບຯອື່ນໆນຳ."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ເຊື່ອມໂຍງກັບບໍລິການໂຕຟັງການແຈ້ງເຕືອນ"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຊື່ອມໂຍງສ່ວນຕິດຕໍ່ລະດັບເທິງສຸດ ຂອງຜູ່ຟັງບໍລິການການແຈ້ງເຕືອນ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"ພາບພື້ນຫຼັງ"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"ປ່ຽນພາບພື້ນຫຼັງ"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ໂຕຟັງການແຈ້ງເຕືອນ"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 0b25703..7250f02 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 f2415d5..4c48278 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 8fd4fba..c609745 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Эзэмшигч нь VPN үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"ханын зурагтай холбох"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Эзэмшигч нь ханын зурагны дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-уудад шаардлагагүй."</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Апп нь бусад апп-уудын илгээсэн мэдэгдлүүдийг дуудах, шалгах, болон цэвэрлэх боломжтой."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"мэдэгдэл сонсогч үйлчилгээтэй холбох"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Эзэмшигч нь мэдэгдэл сонсох үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Ханын зураг"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ханын зураг солих"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Мэдэгдэл сонсогч"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 d0d4223..751327b 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 2c90ba3..16c5352 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 7821648..c19adf2e 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 3cbd980..949fea8 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -719,7 +728,7 @@
<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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 1ad8fad..f9b9fd2 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1131,7 +1140,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">"Seleccionar tudo"</string>
+ <string name="selectAll" msgid="6876518925844129331">"Selecionar tudo"</string>
<string name="cut" msgid="3092569408438626261">"Cortar"</string>
<string name="copy" msgid="2681946229533511987">"Copiar"</string>
<string name="paste" msgid="5629880836805036433">"Colar"</string>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 77e54a4..be2ed29 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 a4d58411..6bdaee5 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -28,6 +28,28 @@
<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>
@@ -224,6 +246,10 @@
<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 />
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 8a69824..33a5a81 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 70e7044..c7c5a08 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Приложение сможет подключаться к базовому интерфейсу службы VPN. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"Привязка к фоновому рисунку"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Приложение сможет подключаться к базовому интерфейсу службы обоев. Это разрешение не используется обычными приложениями."</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Приложение сможет получать, проверять и удалять уведомления, включая те, что опубликованы другими приложениями."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Подключение к службе просмотра уведомлений"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Приложение сможет подключаться к базовому интерфейсу службы просмотра уведомлений. Это разрешение не используется обычными приложениями."</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновый рисунок"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Сменить обои"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба просмотра уведомлений"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 055d23b..08e4c08 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 2a04337..dfa767b 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 5d03ffa..fb65c02 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дозвољава власнику да се повеже са интерфејсом VPN услуге највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"обавезивање на позадину"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дозвољава власнику да се повеже са интерфејсом позадине највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозвољава апликацији да преузима, испитује и брише обавештења, укључујући она која постављају друге апликације."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"повезивање са услугом монитора обавештења"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозвољава власнику да се повеже са интерфејсом услуге монитора обавештења највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Позадина"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Промена позадине"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Монитор обавештења"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 3599074..ea713a6 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 0c21017..8c77050 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -418,15 +429,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">"Futa kache za programu zingine"</string>
- <string name="permdesc_deleteCacheFiles" msgid="3812998599006730196">"Inaruhusu programu kufuta faili za kache."</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_getPackageSize" msgid="7472921768357981986">"Pima nafasi ya hifadhi ya programu"</string>
- <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Inaruhusu Programu kupata tena msimbo, data na ukubwa wa kache yake."</string>
+ <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Huruhusu Programu kupata tena msimbo, data na ukubwa wa akiba 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">"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="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_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>
@@ -577,7 +588,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">"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="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="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zuia kompyuta ndogo dhidi ya kulala"</string>
@@ -685,12 +696,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 kache"</string>
- <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Inaruhusu programu kusoma na kuandika mfumo wa faili wa kache."</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_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">"Inaruhusu programu kudhibiti wakati na jinsi mtumiaji anaona 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="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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -717,9 +726,9 @@
<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 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_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_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>
@@ -1296,14 +1305,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 kwa chaguo nyingine za USB."</string>
+ <string name="usb_notification_message" msgid="2290859399983720271">"Gusa ili uone chaguo zingine 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 USB umeunganishwa"</string>
- <string name="adb_active_notification_message" msgid="1016654627626476142">"Gusa ili kulemaza utatuaji wa USB."</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="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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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-th/strings.xml b/core/res/res/values-th/strings.xml
index ded9706..7f0cf61 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"อนุญาตให้เจ้าของเชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการ VPN ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"เชื่อมโยงกับวอลเปเปอร์"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของวอลเปเปอร์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"ทำให้แอปสามารถเรียกดู ตรวจสอบ และล้างการแจ้งเตือนได้ ซึ่งรวมถึงการแจ้งเตือนที่โพสต์โดยแอปอื่นๆ ด้วย"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"เชื่อมโยงกับบริการตัวฟังการแจ้งเตือน"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"อนุญาตให้เจ้าของเชื่อมโยงกับอินเตอร์เฟซระดับสูงสุดของบริการตัวฟังการแจ้งเตือน ซึ่งไม่มีความจำเป็นสำหรับแอปธรรมดา"</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"วอลเปเปอร์"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"เปลี่ยนวอลเปเปอร์"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ตัวฟังการแจ้งเตือน"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 4d2d0db..969b651 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 8c97507..6e6151f 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 104a45c..63fdd15 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби VPN. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"прив’язати до фонового малюнка"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня фонового малюнка. Ніколи не застосовується для звичайних програм."</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозволяє програмі отримувати, перевіряти й очищати сповіщення, зокрема опубліковані іншими програмами."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прив’язуватися до служби читання сповіщень"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня служби читання сповіщень. Ніколи не застосовується для звичайних програм."</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновий мал."</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Змінити фоновий малюнок"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба читання сповіщень"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 24d468c..545b92e 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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>
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 1dd4608..44e258d 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -30,4 +30,11 @@
<!-- Base "touch slop" value used by ViewConfiguration as a
movement threshold where scrolling should begin. -->
<dimen name="config_viewConfigurationTouchSlop">4dp</dimen>
+
+ <!-- Minimum velocity to initiate a fling, as measured in dips per second. -->
+ <dimen name="config_viewMinFlingVelocity">500dp</dimen>
+
+ <!-- Maximum velocity to initiate a fling, as measured in dips per second. -->
+ <dimen name="config_viewMaxFlingVelocity">8000dp</dimen>
+
</resources>
diff --git a/core/res/res/values-watch/themes.xml b/core/res/res/values-watch/themes.xml
new file mode 100644
index 0000000..9447d9cb
--- /dev/null
+++ b/core/res/res/values-watch/themes.xml
@@ -0,0 +1,21 @@
+<?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.Micro.Dialog.Alert" />
+ <style name="Theme.Dialog.AppError" parent="Theme.Micro.Dialog.AppError" />
+ <style name="Theme.Holo.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+ <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+</resources>
diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml
new file mode 100644
index 0000000..705143c
--- /dev/null
+++ b/core/res/res/values-watch/themes_device_defaults.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.
+-->
+<resources>
+ <style name="Theme.DeviceDefault" parent="Theme.Micro" />
+ <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Micro" />
+ <style name="Theme.DeviceDefault.Dialog" parent="Theme.Micro.Dialog" />
+ <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+ <style name="Theme.DeviceDefault.Light" parent="Theme.Micro.Light" />
+ <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Micro.Light" />
+ <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Micro.Light" />
+ <style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Micro.Dialog" />
+ <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+
+</resources>
+
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 95ec3846..3476692 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"允许用户绑定到 VPN 服务的顶级接口。普通应用绝不需要此权限。"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"绑定到壁纸"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允许用户绑定到壁纸的顶级接口。普通应用绝不需要此权限。"</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"允许该应用检索、检查并清除通知,包括其他应用发布的通知。"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"绑定到通知侦听器服务"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允许应用绑定到通知侦听器服务的顶级接口(普通应用绝不需要此权限)。"</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"壁纸"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"更改壁纸"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知侦听器"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 d78f298..fdd02a7 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"允許應用程式繫結至 VPN 服務的頂層介面 (不建議一般應用程式使用)。"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"繫結至桌布"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允許應用程式繫結至桌布的頂層介面 (不建議一般應用程式使用)。"</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允許應用程式繫結至通知接聽器服務的頂層介面 (不建議一般應用程式使用)。"</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"桌布"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知接聽器"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 38a487b..4a67538 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<string name="permdesc_bindVpnService" msgid="2067845564581693905">"允許應用程式聯繫至 VPN 服務的頂層介面 (一般應用程式不需使用)。"</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"連結至桌布"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允許應用程式繫結至桌布的頂層介面 (一般應用程式不需使用)。"</string>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允許應用程式繫結至通知接聽器服務的頂層介面 (一般應用程式不需使用)。"</string>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1160,7 +1169,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">"選取要以 USB 裝置存取的應用程式"</string>
<string name="noApplications" msgid="2991814273936504689">"沒有應用程式可執行這項操作。"</string>
<string name="aerr_title" msgid="1905800560317137752"></string>
@@ -1377,8 +1386,7 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"桌布"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知接聽器"</string>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 ede3d3c..58fdb1c 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -27,6 +27,17 @@
<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>
@@ -177,6 +188,8 @@
<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>
@@ -387,10 +400,8 @@
<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>
- <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) -->
- <skip />
- <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
- <skip />
+ <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>
@@ -703,10 +714,8 @@
<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>
- <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) -->
- <skip />
- <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) -->
- <skip />
+ <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>
@@ -1377,8 +1386,7 @@
<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>
- <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) -->
- <skip />
+ <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 efc1b55..172877f 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -721,6 +721,7 @@
<attr name="actionBarTabBarStyle" format="reference" />
<attr name="actionBarTabTextStyle" format="reference" />
<attr name="actionOverflowButtonStyle" format="reference" />
+ <attr name="actionOverflowMenuStyle" format="reference" />
<!-- Reference to a style for the Action Bar -->
<attr name="actionBarStyle" format="reference" />
<!-- Reference to a style for the split Action Bar. This style
@@ -966,7 +967,6 @@
<attr name="colorButtonPressed" format="color" />
<attr name="colorButtonNormalColored" format="color" />
<attr name="colorButtonPressedColored" format="color" />
-
</declare-styleable>
<!-- **************************************************************** -->
@@ -2364,6 +2364,9 @@
<!-- Specifies that this view should permit nested scrolling within a compatible
ancestor view. -->
<attr name="nestedScrollingEnabled" format="boolean" />
+
+ <!-- Sets the state-based animator for the View. -->
+ <attr name="stateListAnimator" format="reference"/>
</declare-styleable>
<!-- Attributes that can be assigned to a tag for a particular View. -->
@@ -3804,6 +3807,7 @@
<declare-styleable name="PopupWindow">
<attr name="popupBackground" format="reference|color" />
<attr name="popupAnimationStyle" format="reference" />
+ <attr name="overlapAnchor" format="boolean" />
</declare-styleable>
<declare-styleable name="ViewAnimator">
<!-- Identifier for the animation to use when a view is shown. -->
@@ -4254,6 +4258,11 @@
<attr name="drawable" format="reference" />
</declare-styleable>
+ <!-- Attributes that can be assigned to a StateListAnimator item. -->
+ <declare-styleable name="StateListAnimatorItem">
+ <attr name="animation"/>
+ </declare-styleable>
+
<!-- Drawable used to render a geometric shape, with a gradient or a solid color. -->
<declare-styleable name="GradientDrawable">
<!-- Indicates whether the drawable should intially be visible. -->
@@ -5811,6 +5820,9 @@
<attr name="imeExtractExitAnimation" format="reference" />
</declare-styleable>
+ <declare-styleable name="VoiceInteractionSession">
+ </declare-styleable>
+
<declare-styleable name="KeyboardView">
<!-- Default KeyboardView style. -->
<attr name="keyboardViewStyle" format="reference" />
@@ -5952,11 +5964,12 @@
<flag name="vertical" value="0x2" />
</attr>
<!-- Optional parameter which indicates where this widget can be shown,
- ie. home screen, keyguard or both.
- resized. Supports combined values using | operator. -->
+ ie. home screen, keyguard, recents or any combination thereof.
+ Supports combined values using | operator. -->
<attr name="widgetCategory" format="integer">
<flag name="home_screen" value="0x1" />
<flag name="keyguard" value="0x2" />
+ <flag name="recents" value="0x4" />
</attr>
</declare-styleable>
@@ -6348,6 +6361,8 @@
<!-- Specifies padding that should be applied to the left and right sides of
system-provided items in the bar. -->
<attr name="itemPadding" format="dimension" />
+ <!-- Set true to hide the action bar on a vertical nested scroll of content. -->
+ <attr name="hideOnContentScroll" format="boolean" />
</declare-styleable>
<declare-styleable name="ActionMode">
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index cce4dbd..b1f256e 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -885,6 +885,47 @@
be passed a persistable Bundle in their Intent.extras. -->
<attr name="persistable" format="boolean" />
+ <!-- Specify whether this activity should always be launched in doc-centric mode. For
+ values other than <code>none</code> the activity must be defined with
+ {@link android.R.attr#launchMode} <code>standard</code> or <code>singleTop</code>.
+ This attribute can be overridden by {@link
+ android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}.
+
+ <p>If this attribute is not specified, <code>none</code> will be used.
+ Note that this launch behavior can be changed in some ways at runtime
+ through the {@link android.content.Intent} flags
+ {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}. -->
+ <attr name="documentLaunchMode">
+ <!-- The default mode, which will create a new task only when
+ {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK
+ Intent.FLAG_ACTIVITY_NEW_TASK} is set. -->
+ <enum name="none" value="0" />
+ <!-- All tasks will be searched for a matching Intent. If one is found
+ That task will cleared and restarted with the root activity receiving a call
+ to {@link android.app.Activity#onNewIntent Activity.onNewIntent}. If no
+ such task is found a new task will be created.
+ This is the equivalent of with {@link
+ android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT Intent.FLAG_ACTIVITY_NEW_DOCUMENT}
+ without {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK}. -->
+ <enum name="intoExisting" value="1" />
+ <!-- A new task rooted at this activity will be created.
+ This is the equivalent of with {@link
+ android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT Intent.FLAG_ACTIVITY_NEW_DOCUMENT}
+ paired with {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK}. -->
+ <enum name="always" value="2" />
+ </attr>
+
+ <!-- Tasks launched by activities with this attribute will remain in the recent task
+ list until the last activity in the task is completed. When that happens the task
+ will be automatically removed from the recent task list.
+
+ This attribute is the equivalent of {@link
+ android.content.Intent#FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS
+ Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS} -->
+ <attr name="autoRemoveFromRecents" format="boolean" />
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -1549,6 +1590,8 @@
<attr name="primaryUserOnly" format="boolean" />
<attr name="persistable" />
<attr name="allowEmbedded" />
+ <attr name="documentLaunchMode" />
+ <attr name="autoRemoveFromRecents" />
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index d0c455bc..7d3fb44 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -71,11 +71,7 @@
<drawable name="editbox_dropdown_dark_frame">@drawable/editbox_dropdown_background_dark</drawable>
<drawable name="editbox_dropdown_light_frame">@drawable/editbox_dropdown_background</drawable>
- <drawable name="dialog_holo_dark_frame">@drawable/dialog_full_holo_dark</drawable>
- <drawable name="dialog_holo_light_frame">@drawable/dialog_full_holo_light</drawable>
-
<drawable name="input_method_fullscreen_background">#fff9f9f9</drawable>
- <drawable name="input_method_fullscreen_background_holo">@drawable/screen_background_holo_dark</drawable>
<color name="input_method_navigation_guard">#ff000000</color>
<!-- For date picker widget -->
@@ -122,78 +118,12 @@
<!-- FaceLock -->
<color name="facelock_spotlight_mask">#CC000000</color>
- <!-- For holo theme -->
- <drawable name="screen_background_holo_light">#fff3f3f3</drawable>
- <drawable name="screen_background_holo_dark">#ff000000</drawable>
- <color name="background_holo_dark">#ff000000</color>
- <color name="background_holo_light">#fff3f3f3</color>
- <color name="bright_foreground_holo_dark">@android:color/background_holo_light</color>
- <color name="bright_foreground_holo_light">@android:color/background_holo_dark</color>
- <color name="bright_foreground_disabled_holo_dark">#ff4c4c4c</color>
- <color name="bright_foreground_disabled_holo_light">#ffb2b2b2</color>
- <color name="bright_foreground_inverse_holo_dark">@android:color/bright_foreground_holo_light</color>
- <color name="bright_foreground_inverse_holo_light">@android:color/bright_foreground_holo_dark</color>
- <color name="dim_foreground_holo_dark">#bebebe</color>
- <color name="dim_foreground_disabled_holo_dark">#80bebebe</color>
- <color name="dim_foreground_inverse_holo_dark">#323232</color>
- <color name="dim_foreground_inverse_disabled_holo_dark">#80323232</color>
- <color name="hint_foreground_holo_dark">#808080</color>
- <color name="dim_foreground_holo_light">#323232</color>
- <color name="dim_foreground_disabled_holo_light">#80323232</color>
- <color name="dim_foreground_inverse_holo_light">#bebebe</color>
- <color name="dim_foreground_inverse_disabled_holo_light">#80bebebe</color>
- <color name="hint_foreground_holo_light">#808080</color>
- <color name="highlighted_text_holo_dark">#6633b5e5</color>
- <color name="highlighted_text_holo_light">#6633b5e5</color>
- <color name="link_text_holo_dark">#5c5cff</color>
- <color name="link_text_holo_light">#0000ee</color>
-
- <!-- Group buttons -->
- <eat-comment />
- <color name="group_button_dialog_pressed_holo_dark">#46c5c1ff</color>
- <color name="group_button_dialog_focused_holo_dark">#2699cc00</color>
-
- <color name="group_button_dialog_pressed_holo_light">#ffffffff</color>
- <color name="group_button_dialog_focused_holo_light">#4699cc00</color>
-
- <!-- Highlight colors for the legacy themes -->
- <eat-comment />
- <color name="legacy_pressed_highlight">#fffeaa0c</color>
- <color name="legacy_selected_highlight">#fff17a0a</color>
- <color name="legacy_long_pressed_highlight">#ffffffff</color>
-
- <!-- General purpose colors for Holo-themed elements -->
- <eat-comment />
-
- <!-- A light Holo shade of blue -->
- <color name="holo_blue_light">#ff33b5e5</color>
- <!-- A light Holo shade of gray -->
- <color name="holo_gray_light">#33999999</color>
- <!-- A light Holo shade of green -->
- <color name="holo_green_light">#ff99cc00</color>
- <!-- A light Holo shade of red -->
- <color name="holo_red_light">#ffff4444</color>
- <!-- A dark Holo shade of blue -->
- <color name="holo_blue_dark">#ff0099cc</color>
- <!-- A dark Holo shade of green -->
- <color name="holo_green_dark">#ff669900</color>
- <!-- A dark Holo shade of red -->
- <color name="holo_red_dark">#ffcc0000</color>
- <!-- A Holo shade of purple -->
- <color name="holo_purple">#ffaa66cc</color>
- <!-- A light Holo shade of orange -->
- <color name="holo_orange_light">#ffffbb33</color>
- <!-- A dark Holo shade of orange -->
- <color name="holo_orange_dark">#ffff8800</color>
- <!-- A really bright Holo shade of blue -->
- <color name="holo_blue_bright">#ff00ddff</color>
- <!-- A really bright Holo shade of gray -->
- <color name="holo_gray_bright">#33CCCCCC</color>
+ <color name="micro_text_light">#434343</color>
<drawable name="notification_template_icon_bg">#3333B5E5</drawable>
<drawable name="notification_template_icon_low_bg">#0cffffff</drawable>
- <color name="notification_icon_legacy_bg_color">#ff4285F4</color>
+ <color name="notification_icon_bg_color">#ffa3a3a3</color>
<color name="notification_action_legacy_color_filter">#ff555555</color>
<!-- Keyguard colors -->
@@ -204,21 +134,5 @@
<color name="accessibility_focus_highlight">#80ffff00</color>
- <!-- New TimePicker colors -->
- <color name="timepicker_default_background_holo_light">@android:color/white</color>
- <color name="timepicker_default_background_holo_dark">#ff303030</color>
-
- <color name="timepicker_default_text_color_holo_light">#8c8c8c</color>
- <color name="timepicker_default_text_color_holo_dark">@android:color/white</color>
-
- <color name="timepicker_default_disabled_color_holo_light">#7f000000</color>
- <color name="timepicker_default_disabled_color_holo_dark">#7f08c8c8</color>
-
- <color name="timepicker_default_ampm_selected_background_color_holo_light">@android:color/holo_blue_light</color>
- <color name="timepicker_default_ampm_selected_background_color_holo_dark">@android:color/holo_blue_light</color>
-
- <color name="timepicker_default_ampm_unselected_background_color_holo_light">@android:color/white</color>
- <color name="timepicker_default_ampm_unselected_background_color_holo_dark">@android:color/transparent</color>
-
</resources>
diff --git a/core/res/res/values/colors_holo.xml b/core/res/res/values/colors_holo.xml
new file mode 100644
index 0000000..d1f4e38
--- /dev/null
+++ b/core/res/res/values/colors_holo.xml
@@ -0,0 +1,123 @@
+<?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.
+-->
+
+<!-- Colors specific to Holo themes. -->
+<resources>
+
+ <drawable name="dialog_holo_dark_frame">@drawable/dialog_full_holo_dark</drawable>
+ <drawable name="dialog_holo_light_frame">@drawable/dialog_full_holo_light</drawable>
+ <drawable name="input_method_fullscreen_background_holo">@drawable/screen_background_holo_dark</drawable>
+
+ <drawable name="screen_background_holo_light">#fff3f3f3</drawable>
+ <drawable name="screen_background_holo_dark">#ff000000</drawable>
+
+ <color name="background_holo_dark">#ff000000</color>
+ <color name="background_holo_light">#fff3f3f3</color>
+ <color name="bright_foreground_holo_dark">@color/background_holo_light</color>
+ <color name="bright_foreground_holo_light">@color/background_holo_dark</color>
+ <color name="bright_foreground_disabled_holo_dark">#ff4c4c4c</color>
+ <color name="bright_foreground_disabled_holo_light">#ffb2b2b2</color>
+ <color name="bright_foreground_inverse_holo_dark">@color/bright_foreground_holo_light</color>
+ <color name="bright_foreground_inverse_holo_light">@color/bright_foreground_holo_dark</color>
+ <color name="dim_foreground_holo_dark">#bebebe</color>
+ <color name="dim_foreground_disabled_holo_dark">#80bebebe</color>
+ <color name="dim_foreground_inverse_holo_dark">#323232</color>
+ <color name="dim_foreground_inverse_disabled_holo_dark">#80323232</color>
+ <color name="hint_foreground_holo_dark">#808080</color>
+ <color name="dim_foreground_holo_light">#323232</color>
+ <color name="dim_foreground_disabled_holo_light">#80323232</color>
+ <color name="dim_foreground_inverse_holo_light">#bebebe</color>
+ <color name="dim_foreground_inverse_disabled_holo_light">#80bebebe</color>
+ <color name="hint_foreground_holo_light">#808080</color>
+ <color name="highlighted_text_holo_dark">#6633b5e5</color>
+ <color name="highlighted_text_holo_light">#6633b5e5</color>
+ <color name="link_text_holo_dark">#5c5cff</color>
+ <color name="link_text_holo_light">#0000ee</color>
+
+ <!-- General purpose colors for Holo-themed elements -->
+ <eat-comment />
+
+ <!-- A light Holo shade of blue -->
+ <color name="holo_blue_light">#ff33b5e5</color>
+ <!-- A light Holo shade of gray -->
+ <color name="holo_gray_light">#33999999</color>
+ <!-- A light Holo shade of green -->
+ <color name="holo_green_light">#ff99cc00</color>
+ <!-- A light Holo shade of red -->
+ <color name="holo_red_light">#ffff4444</color>
+ <!-- A dark Holo shade of blue -->
+ <color name="holo_blue_dark">#ff0099cc</color>
+ <!-- A dark Holo shade of green -->
+ <color name="holo_green_dark">#ff669900</color>
+ <!-- A dark Holo shade of red -->
+ <color name="holo_red_dark">#ffcc0000</color>
+ <!-- A Holo shade of purple -->
+ <color name="holo_purple">#ffaa66cc</color>
+ <!-- A light Holo shade of orange -->
+ <color name="holo_orange_light">#ffffbb33</color>
+ <!-- A dark Holo shade of orange -->
+ <color name="holo_orange_dark">#ffff8800</color>
+ <!-- A really bright Holo shade of blue -->
+ <color name="holo_blue_bright">#ff00ddff</color>
+ <!-- A really bright Holo shade of gray -->
+ <color name="holo_gray_bright">#33CCCCCC</color>
+
+ <!-- Forward compatibility for Quantum-style theme colors -->
+ <eat-comment />
+
+ <color name="holo_primary_dark">#ff000000</color>
+ <color name="holo_primary">#ffe6e6e6</color>
+ <color name="holo_primary_light">#ffffffff</color>
+ <color name="holo_control_activated">@color/holo_blue_light</color>
+ <color name="holo_control_normal">#39cccccc</color>
+ <color name="holo_button_pressed">#59f0f0f0</color>
+ <color name="holo_button_normal">#bd292f34</color>
+
+ <color name="holo_light_primary_dark">#ff000000</color>
+ <color name="holo_light_primary">#ffe6e6e6</color>
+ <color name="holo_light_primary_light">#ffffffff</color>
+ <color name="holo_light_control_activated">@color/holo_control_activated</color>
+ <color name="holo_light_control_normal">#dacccccc</color>
+ <color name="holo_light_button_pressed">#66666666</color>
+ <color name="holo_light_button_normal">#b3cccccc</color>
+
+ <!-- Group buttons -->
+ <eat-comment />
+
+ <color name="group_button_dialog_pressed_holo_dark">#46c5c1ff</color>
+ <color name="group_button_dialog_focused_holo_dark">#2699cc00</color>
+
+ <color name="group_button_dialog_pressed_holo_light">#ffffffff</color>
+ <color name="group_button_dialog_focused_holo_light">#4699cc00</color>
+
+ <!-- Time picker -->
+ <eat-comment />
+
+ <color name="timepicker_default_background_holo_light">@color/white</color>
+ <color name="timepicker_default_background_holo_dark">#ff303030</color>
+
+ <color name="timepicker_default_text_color_holo_light">#8c8c8c</color>
+ <color name="timepicker_default_text_color_holo_dark">@color/white</color>
+
+ <color name="timepicker_default_disabled_color_holo_light">#7f000000</color>
+ <color name="timepicker_default_disabled_color_holo_dark">#7f08c8c8</color>
+
+ <color name="timepicker_default_ampm_selected_background_color_holo_light">@color/holo_blue_light</color>
+ <color name="timepicker_default_ampm_selected_background_color_holo_dark">@color/holo_blue_light</color>
+
+ <color name="timepicker_default_ampm_unselected_background_color_holo_light">@color/white</color>
+ <color name="timepicker_default_ampm_unselected_background_color_holo_dark">@color/transparent</color>
+</resources>
diff --git a/core/res/res/values/colors_legacy.xml b/core/res/res/values/colors_legacy.xml
new file mode 100644
index 0000000..48d4b42
--- /dev/null
+++ b/core/res/res/values/colors_legacy.xml
@@ -0,0 +1,45 @@
+<?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.
+-->
+
+<!-- Colors specific to pre-Holo themes. -->
+<resources>
+
+ <!-- Highlight colors for the legacy themes -->
+ <eat-comment />
+
+ <color name="legacy_pressed_highlight">#fffeaa0c</color>
+ <color name="legacy_selected_highlight">#fff17a0a</color>
+ <color name="legacy_long_pressed_highlight">#ffffffff</color>
+
+ <!-- Forward compatibility for Quantum-style theme colors -->
+ <eat-comment />
+
+ <color name="legacy_primary_dark">#ff000000</color>
+ <color name="legacy_primary">#ffe6e6e6</color>
+ <color name="legacy_primary_light">#ffffffff</color>
+ <color name="legacy_control_activated">#ff90df25</color>
+ <color name="legacy_control_normal">#99ffffff</color>
+ <color name="legacy_button_pressed">#fffea50b</color>
+ <color name="legacy_button_normal">#f3dbdbdb</color>
+
+ <color name="legacy_light_primary_dark">@color/legacy_primary_dark</color>
+ <color name="legacy_light_primary">@color/legacy_primary</color>
+ <color name="legacy_light_primary_light">@color/legacy_primary_light</color>
+ <color name="legacy_light_control_activated">@color/legacy_control_activated</color>
+ <color name="legacy_light_control_normal">#99000000</color>
+ <color name="legacy_light_button_pressed">@color/legacy_button_pressed</color>
+ <color name="legacy_light_button_normal">@color/legacy_button_normal</color>
+</resources>
diff --git a/core/res/res/values/colors_quantum.xml b/core/res/res/values/colors_quantum.xml
index f8f192f..7171450 100644
--- a/core/res/res/values/colors_quantum.xml
+++ b/core/res/res/values/colors_quantum.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
+<!-- Colors specific to Quantum themes. -->
<resources>
<color name="background_quantum_dark">@color/black</color>
<color name="background_quantum_light">@color/white</color>
@@ -40,6 +41,7 @@
<color name="highlighted_text_quantum_light">#660097a7</color>
<!-- Primary & accent colors -->
+ <eat-comment />
<color name="quantum_red_100">#fff4c7c3</color>
<color name="quantum_red_300">#ffe67c73</color>
@@ -98,6 +100,7 @@
<color name="quantum_deep_orange_A400">#ffff1744</color>
<!-- Neutral colors -->
+ <eat-comment />
<color name="quantum_grey_50">#fffafafa</color>
<color name="quantum_grey_100">#fff5f5f5</color>
@@ -117,6 +120,7 @@
<color name="quantum_brown_700">#ff5d4037</color>
<!-- Text & foreground colors -->
+ <eat-comment />
<color name="primary_text_default_quantum_light">#de000000</color>
<color name="secondary_text_quantum_light">#8a000000</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f919c9f..f39155b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1206,6 +1206,15 @@
movement threshold where scrolling should begin. -->
<dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
+ <!-- Minimum velocity to initiate a fling, as measured in dips per second. -->
+ <dimen name="config_viewMinFlingVelocity">50dp</dimen>
+
+ <!-- Maximum velocity to initiate a fling, as measured in dips per second. -->
+ <dimen name="config_viewMaxFlingVelocity">8000dp</dimen>
+
+ <!-- Amount of time in ms the user needs to press the relevant key to bring up the global actions dialog -->
+ <integer name="config_globalActionsKeyTimeout">500</integer>
+
<!-- Maximum number of grid columns permitted in the ResolverActivity
used for picking activities to handle an intent. -->
<integer name="config_maxResolverActivityColumns">2</integer>
diff --git a/core/res/res/values/dimens_quantum.xml b/core/res/res/values/dimens_quantum.xml
index cebee12..53e97fd 100644
--- a/core/res/res/values/dimens_quantum.xml
+++ b/core/res/res/values/dimens_quantum.xml
@@ -49,4 +49,7 @@
<dimen name="floating_window_z">16dp</dimen>
<dimen name="floating_window_margin">32dp</dimen>
+
+ <!-- the amount of elevation for pressed button state-->
+ <dimen name="button_pressed_z">2dp</dimen>
</resources>
diff --git a/core/res/res/values/integers.xml b/core/res/res/values/integers.xml
index dc90bbf..e6748c4 100644
--- a/core/res/res/values/integers.xml
+++ b/core/res/res/values/integers.xml
@@ -19,4 +19,5 @@
<resources>
<integer name="kg_carousel_angle">75</integer>
<integer name="kg_glowpad_rotation_offset">0</integer>
+ <integer name="button_pressed_animation_duration">100</integer>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5ccb05b..d0cdefe 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2162,10 +2162,16 @@
<public type="attr" name="windowAllowExitTransitionOverlap" />
<public type="attr" name="windowAllowEnterTransitionOverlap" />
<public type="attr" name="sessionService" />
+ <public type="attr" name="stackViewStyle" />
<public type="attr" name="switchStyle" />
<public type="attr" name="elevation" />
<public type="attr" name="excludeId" />
<public type="attr" name="excludeClass" />
+ <public type="attr" name="hideOnContentScroll" />
+ <public type="attr" name="actionOverflowMenuStyle" />
+ <public type="attr" name="documentLaunchMode" />
+ <public type="attr" name="autoRemoveFromRecents" />
+ <public type="attr" name="stateListAnimator" />
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
@@ -2180,15 +2186,25 @@
<public-padding type="style" name="l_resource_pad" end="0x01030200" />
- <public type="style" name="Widget.Holo.FragmentBreadCrumbs" />
- <public type="style" name="Widget.Holo.Light.FragmentBreadCrumbs" />
- <public type="style" name="Widget.DeviceDefault.FragmentBreadCrumbs" />
- <public type="style" name="Widget.DeviceDefault.Light.FragmentBreadCrumbs" />
<public type="style" name="Widget.FastScroll" />
+ <public type="style" name="Widget.StackView" />
+
<public type="style" name="Widget.Holo.FastScroll" />
+ <public type="style" name="Widget.Holo.FragmentBreadCrumbs" />
+ <public type="style" name="Widget.Holo.StackView" />
+
+ <public type="style" name="Widget.Holo.Light.Button.Borderless" />
<public type="style" name="Widget.Holo.Light.FastScroll" />
+ <public type="style" name="Widget.Holo.Light.FragmentBreadCrumbs" />
+ <public type="style" name="Widget.Holo.Light.StackView" />
+
<public type="style" name="Widget.DeviceDefault.FastScroll" />
+ <public type="style" name="Widget.DeviceDefault.FragmentBreadCrumbs" />
+ <public type="style" name="Widget.DeviceDefault.StackView" />
+
<public type="style" name="Widget.DeviceDefault.Light.FastScroll" />
+ <public type="style" name="Widget.DeviceDefault.Light.FragmentBreadCrumbs" />
+ <public type="style" name="Widget.DeviceDefault.Light.StackView" />
<public type="style" name="TextAppearance.Quantum" />
<public type="style" name="TextAppearance.Quantum.DialogWindowTitle" />
@@ -2265,7 +2281,6 @@
<public type="style" name="Widget.Quantum.ActionButton" />
<public type="style" name="Widget.Quantum.ActionButton.CloseMode" />
<public type="style" name="Widget.Quantum.ActionButton.Overflow" />
- <public type="style" name="Widget.Quantum.ActionButton.TextButton" />
<public type="style" name="Widget.Quantum.ActionMode" />
<public type="style" name="Widget.Quantum.AutoCompleteTextView" />
<public type="style" name="Widget.Quantum.Button" />
@@ -2296,6 +2311,7 @@
<public type="style" name="Widget.Quantum.ListView.DropDown" />
<public type="style" name="Widget.Quantum.MediaRouteButton" />
<public type="style" name="Widget.Quantum.PopupMenu" />
+ <public type="style" name="Widget.Quantum.PopupMenu.Overflow" />
<public type="style" name="Widget.Quantum.PopupWindow" />
<public type="style" name="Widget.Quantum.ProgressBar" />
<public type="style" name="Widget.Quantum.ProgressBar.Horizontal" />
@@ -2308,6 +2324,7 @@
<public type="style" name="Widget.Quantum.ScrollView" />
<public type="style" name="Widget.Quantum.SeekBar" />
<public type="style" name="Widget.Quantum.SegmentedButton" />
+ <public type="style" name="Widget.Quantum.StackView" />
<public type="style" name="Widget.Quantum.Spinner" />
<public type="style" name="Widget.Quantum.Tab" />
<public type="style" name="Widget.Quantum.TabWidget" />
@@ -2328,6 +2345,7 @@
<public type="style" name="Widget.Quantum.Light.ActionMode" />
<public type="style" name="Widget.Quantum.Light.AutoCompleteTextView" />
<public type="style" name="Widget.Quantum.Light.Button" />
+ <public type="style" name="Widget.Quantum.Light.Button.Borderless" />
<public type="style" name="Widget.Quantum.Light.Button.Borderless.Small" />
<public type="style" name="Widget.Quantum.Light.Button.Inset" />
<public type="style" name="Widget.Quantum.Light.Button.Small" />
@@ -2353,6 +2371,7 @@
<public type="style" name="Widget.Quantum.Light.ListView.DropDown" />
<public type="style" name="Widget.Quantum.Light.MediaRouteButton" />
<public type="style" name="Widget.Quantum.Light.PopupMenu" />
+ <public type="style" name="Widget.Quantum.Light.PopupMenu.Overflow" />
<public type="style" name="Widget.Quantum.Light.PopupWindow" />
<public type="style" name="Widget.Quantum.Light.ProgressBar" />
<public type="style" name="Widget.Quantum.Light.ProgressBar.Horizontal" />
@@ -2368,6 +2387,7 @@
<public type="style" name="Widget.Quantum.Light.ScrollView" />
<public type="style" name="Widget.Quantum.Light.SeekBar" />
<public type="style" name="Widget.Quantum.Light.SegmentedButton" />
+ <public type="style" name="Widget.Quantum.Light.StackView" />
<public type="style" name="Widget.Quantum.Light.Spinner" />
<public type="style" name="Widget.Quantum.Light.Tab" />
<public type="style" name="Widget.Quantum.Light.TabWidget" />
@@ -2376,12 +2396,6 @@
<public type="style" name="Widget.Quantum.Light.WebTextView" />
<public type="style" name="Widget.Quantum.Light.WebView" />
- <public type="style" name="Widget.Quantum.Button.Paper" />
- <public type="style" name="Widget.Quantum.Button.Paper.Color" />
-
- <public type="style" name="Widget.Quantum.Light.Button.Paper" />
- <public type="style" name="Widget.Quantum.Light.Button.Paper.Color" />
-
<public type="style" name="TextAppearance.Quantum.Display4" />
<public type="style" name="TextAppearance.Quantum.Display3" />
<public type="style" name="TextAppearance.Quantum.Display2" />
@@ -2395,8 +2409,6 @@
<public type="style" name="TextAppearance.Quantum.Menu" />
<public type="style" name="TextAppearance.Quantum.Button" />
- <public type="style" name="Widget.Holo.Light.Button.Borderless" />
-
<public-padding type="interpolator" name="l_resource_pad" end="0x010c0010" />
<!-- An interpolator which accelerates fast but decelerates slowly. -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index fc0fccc..891265f 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -169,6 +169,12 @@
<item name="windowExitAnimation">@anim/input_method_exit</item>
</style>
+ <!-- Window animations that are applied to voice interaction overlay windows. -->
+ <style name="Animation.VoiceInteractionSession">
+ <item name="windowEnterAnimation">@anim/input_method_enter</item>
+ <item name="windowExitAnimation">@anim/input_method_exit</item>
+ </style>
+
<!-- Special optional fancy IM animations. @hide -->
<style name="Animation.InputMethodFancy">
<item name="windowEnterAnimation">@anim/input_method_fancy_enter</item>
@@ -397,6 +403,11 @@
<item name="android:disabledAlpha">?android:attr/disabledAlpha</item>
</style>
+ <style name="Widget.StackView">
+ <item name="android:resOutColor">@android:color/holo_blue_light</item>
+ <item name="android:clickColor">@android:color/holo_blue_light</item>
+ </style>
+
<style name="Widget.ProgressBar">
<item name="android:indeterminateOnly">true</item>
<item name="android:indeterminateDrawable">@android:drawable/progress_medium_white</item>
@@ -1609,11 +1620,6 @@
<item name="android:minWidth">64dip</item>
</style>
- <style name="Widget.Holo.StackView">
- <item name="android:resOutColor">@android:color/holo_blue_light</item>
- <item name="android:clickColor">@android:color/holo_blue_light</item>
- </style>
-
<style name="Widget.Holo.Button.Borderless">
<item name="android:background">?android:attr/selectableItemBackground</item>
<item name="android:paddingStart">4dip</item>
@@ -1645,6 +1651,11 @@
<item name="android:minHeight">48dip</item>
</style>
+ <style name="Widget.Holo.StackView">
+ <item name="android:resOutColor">@android:color/holo_blue_light</item>
+ <item name="android:clickColor">@android:color/holo_blue_light</item>
+ </style>
+
<style name="Holo.ButtonBar" parent="ButtonBar">
<item name="android:paddingTop">0dip</item>
<item name="android:paddingStart">0dip</item>
@@ -2099,6 +2110,11 @@
<item name="android:minHeight">48dip</item>
</style>
+ <style name="Widget.Holo.Light.StackView">
+ <item name="android:resOutColor">@android:color/holo_blue_light</item>
+ <item name="android:clickColor">@android:color/holo_blue_light</item>
+ </style>
+
<style name="Holo.Light.ButtonBar" parent="Holo.ButtonBar">
</style>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 629b2b7..60e06ce 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -72,7 +72,7 @@
<style name="Widget.DeviceDefault.PopupMenu" parent="Widget.Quantum.PopupMenu"/>
<style name="Widget.DeviceDefault.ActionButton" parent="Widget.Quantum.ActionButton"/>
<style name="Widget.DeviceDefault.ActionButton.Overflow" parent="Widget.Quantum.ActionButton.Overflow"/>
- <style name="Widget.DeviceDefault.ActionButton.TextButton" parent="Widget.Quantum.ActionButton.TextButton"/>
+ <style name="Widget.DeviceDefault.ActionButton.TextButton" parent="Widget.Quantum.ActionButton"/>
<style name="Widget.DeviceDefault.ActionMode" parent="Widget.Quantum.ActionMode"/>
<style name="Widget.DeviceDefault.ActionButton.CloseMode" parent="Widget.Quantum.ActionButton.CloseMode"/>
<style name="Widget.DeviceDefault.ActionBar" parent="Widget.Quantum.ActionBar"/>
@@ -97,6 +97,7 @@
<style name="Widget.DeviceDefault.ImageWell" parent="Widget.Quantum.ImageWell"/>
<style name="Widget.DeviceDefault.KeyboardView" parent="Widget.Quantum.KeyboardView"/>
<style name="Widget.DeviceDefault.ListView.White" parent="Widget.Quantum.ListView.White"/>
+ <style name="Widget.DeviceDefault.MediaRouteButton" parent="Widget.Quantum.MediaRouteButton" />
<style name="Widget.DeviceDefault.NumberPicker" parent="Widget.Quantum.NumberPicker"/>
<style name="Widget.DeviceDefault.PreferenceFrameLayout" parent="Widget.Quantum.PreferenceFrameLayout"/>
<style name="Widget.DeviceDefault.ProgressBar.Inverse" parent="Widget.Quantum.ProgressBar.Inverse"/>
@@ -114,11 +115,13 @@
<style name="Widget.DeviceDefault.TextSuggestionsPopupWindow" parent="Widget.Quantum.TextSuggestionsPopupWindow"/>
<style name="Widget.DeviceDefault.TextView.ListSeparator" parent="Widget.Quantum.TextView.ListSeparator"/>
<style name="Widget.DeviceDefault.TimePicker" parent="Widget.Quantum.TimePicker"/>
+
<style name="Widget.DeviceDefault.Light" parent="Widget.Quantum.Light"/>
<style name="Widget.DeviceDefault.Light.Button" parent="Widget.Quantum.Light.Button"/>
<style name="Widget.DeviceDefault.Light.Button.Small" parent="Widget.Quantum.Light.Button.Small"/>
<style name="Widget.DeviceDefault.Light.Button.Inset" parent="Widget.Quantum.Light.Button.Inset"/>
<style name="Widget.DeviceDefault.Light.Button.Toggle" parent="Widget.Quantum.Light.Button.Toggle"/>
+ <style name="Widget.DeviceDefault.Light.StackView" parent="Widget.Quantum.Light.StackView"/>
<style name="Widget.DeviceDefault.Light.TextView" parent="Widget.Quantum.Light.TextView"/>
<style name="Widget.DeviceDefault.Light.CheckedTextView" parent="Widget.Quantum.Light.CheckedTextView"/>
<style name="Widget.DeviceDefault.Light.AutoCompleteTextView" parent="Widget.Quantum.Light.AutoCompleteTextView"/>
@@ -131,6 +134,7 @@
<style name="Widget.DeviceDefault.Light.GridView" parent="Widget.Quantum.Light.GridView"/>
<style name="Widget.DeviceDefault.Light.ImageButton" parent="Widget.Quantum.Light.ImageButton"/>
<style name="Widget.DeviceDefault.Light.ListView" parent="Widget.Quantum.Light.ListView"/>
+ <style name="Widget.DeviceDefault.Light.MediaRouteButton" parent="Widget.Quantum.Light.MediaRouteButton" />
<style name="Widget.DeviceDefault.Light.PopupWindow" parent="Widget.Quantum.Light.PopupWindow"/>
<style name="Widget.DeviceDefault.Light.ProgressBar" parent="Widget.Quantum.Light.ProgressBar"/>
<style name="Widget.DeviceDefault.Light.ProgressBar.Horizontal" parent="Widget.Quantum.Light.ProgressBar.Horizontal"/>
@@ -195,7 +199,6 @@
<style name="Widget.DeviceDefault.Light.TimePicker" parent="Widget.Quantum.Light.TimePicker"/>
<style name="Widget.DeviceDefault.Light.TextSuggestionsPopupWindow" parent="Widget.Quantum.Light.TextSuggestionsPopupWindow"/>
-
<!-- Text Appearance Styles -->
<style name="TextAppearance.DeviceDefault" parent="TextAppearance.Quantum"/>
<style name="TextAppearance.DeviceDefault.Inverse" parent="TextAppearance.Quantum.Inverse"/>
@@ -207,6 +210,8 @@
<style name="TextAppearance.DeviceDefault.Small.Inverse" parent="TextAppearance.Quantum.Small.Inverse"/>
<style name="TextAppearance.DeviceDefault.SearchResult.Title" parent="TextAppearance.Quantum.SearchResult.Title"/>
<style name="TextAppearance.DeviceDefault.SearchResult.Subtitle" parent="TextAppearance.Quantum.SearchResult.Subtitle"/>
+ <style name="TextAppearance.DeviceDefault.TimePicker.TimeLabel" parent="TextAppearance.Quantum.TimePicker.TimeLabel"/>
+ <style name="TextAppearance.DeviceDefault.TimePicker.AmPmLabel" parent="TextAppearance.Quantum.TimePicker.AmPmLabel"/>
<style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Quantum.Widget"/>
<style name="TextAppearance.DeviceDefault.Widget.Button" parent="TextAppearance.Quantum.Widget.Button"/>
<style name="TextAppearance.DeviceDefault.Widget.IconMenu.Item" parent="TextAppearance.Quantum.Widget.IconMenu.Item"/>
@@ -235,20 +240,6 @@
<!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
<style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle.Inverse" parent="TextAppearance.Quantum.Widget.ActionMode.Subtitle.Inverse"/>
<style name="TextAppearance.DeviceDefault.Widget.ActionBar.Menu" parent="TextAppearance.Quantum.Widget.ActionBar.Menu"/>
- <style name="TextAppearance.DeviceDefault.Light" parent="TextAppearance.Quantum.Light"/>
- <style name="TextAppearance.DeviceDefault.Light.Inverse" parent="TextAppearance.Quantum.Light.Inverse"/>
- <style name="TextAppearance.DeviceDefault.Light.Large" parent="TextAppearance.Quantum.Light.Large"/>
- <style name="TextAppearance.DeviceDefault.Light.Large.Inverse" parent="TextAppearance.Quantum.Light.Large.Inverse"/>
- <style name="TextAppearance.DeviceDefault.Light.Medium" parent="TextAppearance.Quantum.Light.Medium"/>
- <style name="TextAppearance.DeviceDefault.Light.Medium.Inverse" parent="TextAppearance.Quantum.Light.Medium.Inverse"/>
- <style name="TextAppearance.DeviceDefault.Light.SearchResult.Subtitle" parent="TextAppearance.Quantum.Light.SearchResult.Subtitle"/>
- <style name="TextAppearance.DeviceDefault.Light.SearchResult.Title" parent="TextAppearance.Quantum.Light.SearchResult.Title"/>
- <style name="TextAppearance.DeviceDefault.Light.Small" parent="TextAppearance.Quantum.Light.Small"/>
- <style name="TextAppearance.DeviceDefault.Light.Small.Inverse" parent="TextAppearance.Quantum.Light.Small.Inverse"/>
- <style name="TextAppearance.DeviceDefault.Light.Widget.Button" parent="TextAppearance.Quantum.Light.Widget.Button"/>
- <style name="TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Large" parent="TextAppearance.Quantum.Light.Widget.PopupMenu.Large"/>
- <style name="TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Small" parent="TextAppearance.Quantum.Light.Widget.PopupMenu.Small"/>
-
<!-- Preference Styles -->
<style name="Preference.DeviceDefault" parent="Preference.Quantum"/>
@@ -262,7 +253,6 @@
<style name="Preference.DeviceDefault.RingtonePreference" parent="Preference.Quantum.RingtonePreference"/>
<style name="Preference.DeviceDefault.SwitchPreference" parent="Preference.Quantum.SwitchPreference"/>
-
<!-- AlertDialog Styles -->
<style name="AlertDialog.DeviceDefault" parent="AlertDialog.Quantum"/>
<style name="AlertDialog.DeviceDefault.Light" parent="AlertDialog.Quantum.Light"/>
@@ -271,32 +261,20 @@
<style name="Animation.DeviceDefault.Activity" parent="Animation.Quantum.Activity"/>
<style name="Animation.DeviceDefault.Dialog" parent="Animation.Quantum.Dialog"/>
-
<!-- DialogWindowTitle Styles -->
<style name="DialogWindowTitle.DeviceDefault" parent="DialogWindowTitle.Quantum"/>
<style name="DialogWindowTitle.DeviceDefault.Light" parent="DialogWindowTitle.Quantum.Light"/>
-
<!-- WindowTitle Styles -->
<style name="WindowTitle.DeviceDefault" parent="WindowTitle.Quantum"/>
<style name="WindowTitleBackground.DeviceDefault" parent="WindowTitleBackground.Quantum"/>
-
<!-- Other Styles -->
<style name="DeviceDefault.ButtonBar" parent="Widget.Quantum.ButtonBar"/>
<style name="DeviceDefault.ButtonBar.AlertDialog" parent="Widget.Quantum.ButtonBar.AlertDialog"/>
<style name="DeviceDefault.SegmentedButton" parent="Widget.Quantum.SegmentedButton"/>
+
<style name="DeviceDefault.Light.ButtonBar" parent="Widget.Quantum.Light.ButtonBar"/>
<style name="DeviceDefault.Light.ButtonBar.AlertDialog" parent="Widget.Quantum.Light.ButtonBar.AlertDialog"/>
<style name="DeviceDefault.Light.SegmentedButton" parent="Widget.Quantum.Light.SegmentedButton"/>
-
- <style name="Widget.DeviceDefault.MediaRouteButton" parent="Widget.Quantum.MediaRouteButton" />
- <style name="Widget.DeviceDefault.Light.MediaRouteButton" parent="Widget.Quantum.Light.MediaRouteButton" />
-
- <style name="TextAppearance.DeviceDefault.TimePicker.TimeLabel" parent="TextAppearance.Quantum.TimePicker.TimeLabel"/>
- <style name="TextAppearance.DeviceDefault.Light.TimePicker.TimeLabel" parent="TextAppearance.Quantum.Light.TimePicker.TimeLabel"/>
- <style name="TextAppearance.DeviceDefault.TimePicker.AmPmLabel" parent="TextAppearance.Quantum.TimePicker.AmPmLabel"/>
- <style name="TextAppearance.DeviceDefault.Light.TimePicker.AmPmLabel" parent="TextAppearance.Quantum.Light.TimePicker.AmPmLabel"/>
- <style name="Theme.DeviceDefault.Dialog.TimePicker" parent="Theme.Quantum.Dialog.TimePicker"/>
- <style name="Theme.DeviceDefault.Light.Dialog.TimePicker" parent="Theme.Quantum.Light.Dialog.TimePicker"/>
</resources>
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index 52d90bc..bdaa49d 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -14,21 +14,44 @@
limitations under the License.
-->
<resources>
+ <style name="AlertDialog.Micro" parent="AlertDialog.Holo.Light">
+ <item name="layout">@layout/alert_dialog_micro</item>
+ </style>
+
+ <style name="DialogWindowTitle.Micro">
+ <item name="maxLines">1</item>
+ <item name="scrollHorizontally">true</item>
+ <item name="textAppearance">@style/TextAppearance.Micro.DialogWindowTitle</item>
+ </style>
+
+ <style name="TextAppearance.Micro" parent="TextAppearance.Holo">
+ <item name="textSize">20sp</item>
+ <item name="fontFamily">sans-serif-condensed-light</item>
+ <item name="textColor">@color/micro_text_light</item>
+ </style>
+
+ <style name="TextAppearance.Micro.DialogWindowTitle" parent="TextAppearance.Holo.DialogWindowTitle">
+ <item name="textSize">20sp</item>
+ <item name="fontFamily">sans-serif-condensed-light</item>
+ <item name="textColor">@color/micro_text_light</item>
+ </style>
+
<style name="Widget.Micro" parent="Widget.Holo" />
<style name="Widget.Micro.TextView">
- <item name="android:fontFamily">sans-serif-condensed</item>
+ <item name="fontFamily">sans-serif-condensed</item>
</style>
<style name="Widget.Micro.NumberPicker">
- <item name="android:internalLayout">@android:layout/number_picker_with_selector_wheel_micro</item>
- <item name="android:solidColor">@android:color/transparent</item>
- <item name="android:selectionDivider">@android:drawable/numberpicker_selection_divider</item>
- <item name="android:selectionDividerHeight">0dip</item>
- <item name="android:selectionDividersDistance">104dip</item>
- <item name="android:internalMinWidth">64dip</item>
- <item name="android:internalMaxHeight">180dip</item>
- <item name="virtualButtonPressedDrawable">?android:attr/selectableItemBackground</item>
- <item name="android:descendantFocusability">blocksDescendants</item>
+ <item name="internalLayout">@layout/number_picker_with_selector_wheel_micro</item>
+ <item name="solidColor">@color/transparent</item>
+ <item name="selectionDivider">@drawable/numberpicker_selection_divider</item>
+ <item name="selectionDividerHeight">0dip</item>
+ <item name="selectionDividersDistance">104dip</item>
+ <item name="internalMinWidth">64dip</item>
+ <item name="internalMaxHeight">180dip</item>
+ <item name="virtualButtonPressedDrawable">?attr/selectableItemBackground</item>
+ <item name="descendantFocusability">blocksDescendants</item>
</style>
+
</resources>
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index 57f2443..88a2a9f 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -351,40 +351,6 @@
<item name="textStyle">bold</item>
</style>
- <!-- Light text styles -->
- <style name="TextAppearance.Quantum.Light" parent="TextAppearance.Quantum"/>
- <style name="TextAppearance.Quantum.Light.Inverse" parent="TextAppearance.Quantum.Inverse"/>
- <style name="TextAppearance.Quantum.Light.Large" parent="TextAppearance.Quantum.Large"/>
- <style name="TextAppearance.Quantum.Light.Large.Inverse" parent="TextAppearance.Quantum.Large.Inverse"/>
- <style name="TextAppearance.Quantum.Light.Medium" parent="TextAppearance.Quantum.Medium"/>
- <style name="TextAppearance.Quantum.Light.Medium.Inverse" parent="TextAppearance.Quantum.Medium.Inverse"/>
- <style name="TextAppearance.Quantum.Light.Small" parent="TextAppearance.Quantum.Small"/>
- <style name="TextAppearance.Quantum.Light.Small.Inverse" parent="TextAppearance.Quantum.Small.Inverse"/>
- <style name="TextAppearance.Quantum.Light.SearchResult" parent="TextAppearance.Quantum.SearchResult"/>
- <style name="TextAppearance.Quantum.Light.SearchResult.Title" parent="TextAppearance.Quantum.SearchResult.Title"/>
- <style name="TextAppearance.Quantum.Light.SearchResult.Subtitle" parent="TextAppearance.Quantum.SearchResult.Subtitle"/>
- <style name="TextAppearance.Quantum.Light.Widget" parent="TextAppearance.Quantum.Widget"/>
- <style name="TextAppearance.Quantum.Light.Widget.Button" parent="TextAppearance.Quantum.Widget.Button"/>
- <style name="TextAppearance.Quantum.Light.Widget.EditText" parent="TextAppearance.Quantum.Widget.EditText"/>
- <style name="TextAppearance.Quantum.Light.Widget.Switch" parent="TextAppearance.Quantum.Widget.Switch"/>
- <style name="TextAppearance.Quantum.Light.Widget.PopupMenu" parent="TextAppearance.Quantum.Widget.PopupMenu"/>
- <style name="TextAppearance.Quantum.Light.Widget.PopupMenu.Large" parent="TextAppearance.Quantum.Widget.PopupMenu.Large"/>
- <style name="TextAppearance.Quantum.Light.Widget.PopupMenu.Small" parent="TextAppearance.Quantum.Widget.PopupMenu.Small"/>
- <style name="TextAppearance.Quantum.Light.Widget.DropDownHint" parent="TextAppearance.Quantum.Widget.DropDownHint"/>
- <style name="TextAppearance.Quantum.Light.Widget.ActionMode.Title" parent="TextAppearance.Quantum.Widget.ActionMode.Title"/>
- <style name="TextAppearance.Quantum.Light.Widget.ActionMode.Subtitle" parent="TextAppearance.Quantum.Widget.ActionMode.Subtitle"/>
- <style name="TextAppearance.Quantum.Light.WindowTitle" parent="TextAppearance.Quantum.WindowTitle"/>
- <style name="TextAppearance.Quantum.Light.DialogWindowTitle" parent="TextAppearance.Quantum.DialogWindowTitle"/>
- <style name="TextAppearance.Quantum.Light.CalendarViewWeekDayView" parent="TextAppearance.Quantum.CalendarViewWeekDayView"/>
-
- <style name="TextAppearance.Quantum.Light.TimePicker.TimeLabel" parent="TextAppearance.Quantum.TimePicker.TimeLabel">
- <item name="textColor">?attr/textColorSecondary</item>
- </style>
-
- <style name="TextAppearance.Quantum.Light.TimePicker.AmPmLabel" parent="TextAppearance.Quantum.TimePicker.AmPmLabel">
- <item name="textColor">?attr/textColorSecondary</item>
- </style>
-
<!-- Widget Styles -->
<style name="Quantum"/>
@@ -398,6 +364,7 @@
<item name="textColor">?attr/textColorPrimary</item>
<item name="minHeight">48dip</item>
<item name="minWidth">96dip</item>
+ <item name="stateListAnimator">@anim/button_state_list_anim_quantum</item>
</style>
<!-- Small bordered ink button -->
@@ -406,19 +373,10 @@
<item name="minWidth">48dip</item>
</style>
- <!-- Bordered paper button -->
- <style name="Widget.Quantum.Button.Paper">
- <!-- TODO: Specify pressed state animation. -->
- </style>
-
- <!-- Bordered paper button with color -->
- <style name="Widget.Quantum.Button.Paper.Color">
- <item name="background">@drawable/btn_color_quantum</item>
- </style>
-
<!-- Borderless ink button -->
<style name="Widget.Quantum.Button.Borderless">
<item name="background">@drawable/btn_borderless_quantum</item>
+ <item name="stateListAnimator">@null</item>
</style>
<!-- Small borderless ink button -->
@@ -427,11 +385,6 @@
<item name="minWidth">48dip</item>
</style>
- <!-- Borderless paper button -->
- <style name="Widget.Quantum.Button.Borderless.Paper">
- <!-- TODO: Specify pressed state animation. -->
- </style>
-
<style name="Widget.Quantum.Button.Inset">
<item name="background">@drawable/button_inset</item>
</style>
@@ -714,7 +667,8 @@
<style name="Widget.Quantum.ListPopupWindow" parent="Widget.ListPopupWindow">
<item name="dropDownSelector">@drawable/list_selector_quantum</item>
- <item name="popupBackground">?attr/colorBackground</item>
+ <item name="popupBackground">@drawable/popup_background_quantum</item>
+ <item name="popupAnimationStyle">@style/Animation.Quantum.Popup</item>
<item name="dropDownVerticalOffset">0dip</item>
<item name="dropDownHorizontalOffset">0dip</item>
<item name="dropDownWidth">wrap_content</item>
@@ -722,6 +676,10 @@
<style name="Widget.Quantum.PopupMenu" parent="Widget.Quantum.ListPopupWindow"/>
+ <style name="Widget.Quantum.PopupMenu.Overflow">
+ <item name="overlapAnchor">true</item>
+ </style>
+
<style name="Widget.Quantum.ActionButton" parent="Widget.ActionButton">
<item name="minWidth">@dimen/action_button_min_width_quantum</item>
<item name="minHeight">@dimen/action_button_min_height_quantum</item>
@@ -743,8 +701,6 @@
<item name="scaleType">center</item>
</style>
- <style name="Widget.Quantum.ActionButton.TextButton" parent="Widget.Quantum.ButtonBar"/>
-
<style name="Widget.Quantum.ActionBar.TabView" parent="Widget.ActionBar.TabView">
<item name="background">@drawable/tab_indicator_quantum</item>
<item name="paddingStart">16dip</item>
@@ -820,11 +776,8 @@
<style name="Widget.Quantum.Light" parent="Widget.Quantum"/>
<style name="Widget.Quantum.Light.Button" parent="Widget.Quantum.Button"/>
<style name="Widget.Quantum.Light.Button.Small" parent="Widget.Quantum.Button.Small"/>
- <style name="Widget.Quantum.Light.Button.Paper" parent="Widget.Quantum.Button.Paper"/>
- <style name="Widget.Quantum.Light.Button.Paper.Color" parent="Widget.Quantum.Button.Paper.Color"/>
<style name="Widget.Quantum.Light.Button.Borderless" parent="Widget.Quantum.Button.Borderless"/>
<style name="Widget.Quantum.Light.Button.Borderless.Small" parent="Widget.Quantum.Button.Borderless.Small"/>
- <style name="Widget.Quantum.Light.Button.Borderless.Paper" parent="Widget.Quantum.Button.Borderless.Paper"/>
<style name="Widget.Quantum.Light.Button.Inset" parent="Widget.Quantum.Button.Inset"/>
<style name="Widget.Quantum.Light.Button.Toggle">
@@ -842,6 +795,7 @@
<item name="background">@drawable/btn_group_holo_light</item>
</style>
+ <style name="Widget.Quantum.Light.StackView" parent="Widget.Quantum.StackView"/>
<style name="Widget.Quantum.Light.TextView" parent="Widget.Quantum.TextView"/>
<style name="Widget.Quantum.Light.TextView.ListSeparator" parent="Widget.Quantum.TextView.ListSeparator"/>
<style name="Widget.Quantum.Light.TextView.SpinnerItem" parent="Widget.Quantum.TextView.SpinnerItem"/>
@@ -861,7 +815,7 @@
<style name="Widget.Quantum.Light.CompoundButton.Star" parent="Widget.Quantum.CompoundButton.Star"/>
<style name="Widget.Quantum.Light.CompoundButton.Switch" parent="Widget.Quantum.CompoundButton.Switch">
- <item name="switchTextAppearance">@style/TextAppearance.Quantum.Light.Widget.Switch</item>
+ <item name="switchTextAppearance">@style/TextAppearance.Quantum.Widget.Switch</item>
</style>
<style name="Widget.Quantum.Light.ListView.DropDown" parent="Widget.Quantum.ListView.DropDown"/>
@@ -880,7 +834,7 @@
<item name="unfocusedMonthDateColor">#7F08002B</item>
<item name="weekNumberColor">#7F080021</item>
<item name="weekSeparatorLineColor">#7F08002A</item>
- <item name="weekDayTextAppearance">@style/TextAppearance.Quantum.Light.CalendarViewWeekDayView</item>
+ <item name="weekDayTextAppearance">@style/TextAppearance.Quantum.CalendarViewWeekDayView</item>
</style>
<style name="Widget.Quantum.Light.NumberPicker" parent="Widget.Quantum.NumberPicker"/>
@@ -960,17 +914,9 @@
<style name="Widget.Quantum.Light.QuickContactBadgeSmall.WindowSmall" parent="Widget.Quantum.QuickContactBadgeSmall.WindowSmall"/>
<style name="Widget.Quantum.Light.QuickContactBadgeSmall.WindowMedium" parent="Widget.Quantum.QuickContactBadgeSmall.WindowMedium"/>
<style name="Widget.Quantum.Light.QuickContactBadgeSmall.WindowLarge" parent="Widget.Quantum.QuickContactBadgeSmall.WindowLarge"/>
-
- <style name="Widget.Quantum.Light.ListPopupWindow" parent="Widget.ListPopupWindow">
- <item name="dropDownSelector">@drawable/list_selector_quantum</item>
- <item name="popupBackground">?attr/colorBackground</item>
- <item name="dropDownVerticalOffset">0dip</item>
- <item name="dropDownHorizontalOffset">0dip</item>
- <item name="dropDownWidth">wrap_content</item>
- </style>
-
- <style name="Widget.Quantum.Light.PopupMenu" parent="Widget.Quantum.Light.ListPopupWindow"/>
-
+ <style name="Widget.Quantum.Light.ListPopupWindow" parent="Widget.Quantum.ListPopupWindow"/>
+ <style name="Widget.Quantum.Light.PopupMenu" parent="Widget.Quantum.ListPopupWindow"/>
+ <style name="Widget.Quantum.Light.PopupMenu.Overflow" parent="Widget.Quantum.PopupMenu.Overflow"/>
<style name="Widget.Quantum.Light.ActionButton" parent="Widget.Quantum.ActionButton"/>
<style name="Widget.Quantum.Light.ActionButton.Overflow" parent="Widget.Quantum.ActionButton.Overflow"/>
<style name="Widget.Quantum.Light.Tab" parent="Widget.Quantum.Tab"/>
@@ -1014,7 +960,16 @@
<style name="Animation.Quantum" parent="Animation"/>
<style name="Animation.Quantum.Activity" parent="Animation.Activity"/>
- <style name="Animation.Quantum.Dialog" parent="Animation.Dialog"/>
+
+ <style name="Animation.Quantum.Dialog">
+ <item name="windowEnterAnimation">@anim/popup_enter_quantum</item>
+ <item name="windowExitAnimation">@anim/popup_exit_quantum</item>
+ </style>
+
+ <style name="Animation.Quantum.Popup">
+ <item name="windowEnterAnimation">@anim/popup_enter_quantum</item>
+ <item name="windowExitAnimation">@anim/popup_exit_quantum</item>
+ </style>
<!-- Dialog styles -->
@@ -1058,7 +1013,7 @@
</style>
<style name="DialogWindowTitle.Quantum.Light">
- <item name="textAppearance">@style/TextAppearance.Quantum.Light.DialogWindowTitle</item>
+ <item name="textAppearance">@style/TextAppearance.Quantum.DialogWindowTitle</item>
</style>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d4ac74a..2bf72e8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -232,7 +232,6 @@
<java-symbol type="attr" name="preferenceFrameLayoutStyle" />
<java-symbol type="attr" name="searchDialogTheme" />
<java-symbol type="attr" name="searchViewSearchIcon" />
- <java-symbol type="attr" name="stackViewStyle" />
<java-symbol type="attr" name="textAppearanceAutoCorrectionSuggestion" />
<java-symbol type="attr" name="textAppearanceEasyCorrectSuggestion" />
<java-symbol type="attr" name="textAppearanceMisspelledSuggestion" />
@@ -328,6 +327,8 @@
<java-symbol type="dimen" name="accessibility_touch_slop" />
<java-symbol type="dimen" name="config_prefDialogWidth" />
<java-symbol type="dimen" name="config_viewConfigurationTouchSlop" />
+ <java-symbol type="dimen" name="config_viewMinFlingVelocity" />
+ <java-symbol type="dimen" name="config_viewMaxFlingVelocity" />
<java-symbol type="dimen" name="default_app_widget_padding_bottom" />
<java-symbol type="dimen" name="default_app_widget_padding_left" />
<java-symbol type="dimen" name="default_app_widget_padding_right" />
@@ -1197,6 +1198,7 @@
<java-symbol type="layout" name="transient_notification" />
<java-symbol type="layout" name="volume_adjust" />
<java-symbol type="layout" name="volume_adjust_item" />
+ <java-symbol type="layout" name="voice_interaction_session" />
<java-symbol type="layout" name="web_text_view_dropdown" />
<java-symbol type="layout" name="webview_find" />
<java-symbol type="layout" name="webview_select_singlechoice" />
@@ -1268,6 +1270,7 @@
<java-symbol type="style" name="TextAppearance.SlidingTabNormal" />
<java-symbol type="style" name="Theme.DeviceDefault.Dialog.NoFrame" />
<java-symbol type="style" name="Theme.IconMenu" />
+ <java-symbol type="style" name="Theme.DeviceDefault.VoiceInteractionSession" />
<java-symbol type="attr" name="mediaRouteButtonStyle" />
<java-symbol type="attr" name="externalRouteEnabledDrawable" />
@@ -1624,6 +1627,7 @@
<java-symbol type="string" name="wifi_display_notification_connected_message" />
<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.Toast" />
<java-symbol type="xml" name="storage_list" />
<java-symbol type="bool" name="config_dreamsSupported" />
@@ -1647,6 +1651,7 @@
<java-symbol type="id" name="resolver_list" />
<java-symbol type="id" name="button_once" />
<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" />
@@ -1659,6 +1664,7 @@
<java-symbol type="layout" name="notification_template_quantum_big_text" />
<java-symbol type="layout" name="notification_template_quantum_inbox" />
<java-symbol type="color" name="notification_action_legacy_color_filter" />
+ <java-symbol type="color" name="notification_icon_bg_color" />
<java-symbol type="drawable" name="notification_icon_legacy_bg_inset" />
<java-symbol type="drawable" name="notification_quantum_bg_dim" />
<java-symbol type="drawable" name="notification_quantum_bg" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 7b3d5e3..34ef508 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -53,6 +53,14 @@
<item name="colorMultiSelectHighlight">@color/legacy_selected_highlight</item>
<item name="colorActivatedHighlight">@color/legacy_selected_highlight</item>
+ <item name="colorPrimaryDark">@color/legacy_primary_dark</item>
+ <item name="colorPrimary">@color/legacy_primary</item>
+ <item name="colorPrimaryLight">@color/legacy_primary_light</item>
+ <item name="colorControlActivated">@color/legacy_control_activated</item>
+ <item name="colorControlNormal">@color/legacy_control_normal</item>
+ <item name="colorButtonPressed">@color/legacy_button_pressed</item>
+ <item name="colorButtonNormal">@color/legacy_button_normal</item>
+
<item name="disabledAlpha">0.5</item>
<item name="backgroundDimAmount">0.6</item>
@@ -328,6 +336,7 @@
<item name="actionDropDownStyle">@android:style/Widget.Spinner.DropDown</item>
<item name="actionButtonStyle">@android:style/Widget.ActionButton</item>
<item name="actionOverflowButtonStyle">@android:style/Widget.ActionButton.Overflow</item>
+ <item name="actionOverflowMenuStyle">?android:attr/popupMenuStyle</item>
<item name="actionModeBackground">@android:drawable/cab_background_top_holo_dark</item>
<item name="actionModeSplitBackground">@null</item>
<item name="actionModeCloseDrawable">@android:drawable/ic_menu_close_clear_cancel</item>
@@ -437,6 +446,14 @@
<item name="colorBackground">@android:color/background_light</item>
<item name="colorForeground">@color/bright_foreground_light</item>
<item name="colorForegroundInverse">@android:color/bright_foreground_light_inverse</item>
+
+ <item name="colorPrimaryDark">@color/legacy_light_primary_dark</item>
+ <item name="colorPrimary">@color/legacy_light_primary</item>
+ <item name="colorPrimaryLight">@color/legacy_light_primary_light</item>
+ <item name="colorControlActivated">@color/legacy_light_control_activated</item>
+ <item name="colorControlNormal">@color/legacy_light_control_normal</item>
+ <item name="colorButtonPressed">@color/legacy_light_button_pressed</item>
+ <item name="colorButtonNormal">@color/legacy_light_button_normal</item>
<item name="textColorPrimary">@android:color/primary_text_light</item>
<item name="textColorSecondary">@android:color/secondary_text_light</item>
@@ -789,6 +806,14 @@
<item name="android:imeExtractExitAnimation">@android:anim/input_method_extract_exit</item>
</style>
+ <!-- Default theme for voice interaction, which is used by the
+ {@link android.service.voice.VoiceInteractionSession} class.
+ this inherits from Theme.Panel, but sets up appropriate animations
+ and a few custom attributes. -->
+ <style name="Theme.VoiceInteractionSession" parent="Theme.Panel">
+ <item name="android:windowAnimationStyle">@android:style/Animation.VoiceInteractionSession</item>
+ </style>
+
<!-- Default theme for holo style input methods, which is used by the
{@link android.inputmethodservice.InputMethodService} class.
this inherits from Theme.Panel, but sets up IME appropriate animations
@@ -937,6 +962,14 @@
<item name="colorMultiSelectHighlight">@color/holo_green_light</item>
<item name="colorActivatedHighlight">@color/holo_blue_dark</item>
+ <item name="colorPrimaryDark">@color/holo_primary_dark</item>
+ <item name="colorPrimary">@color/holo_primary</item>
+ <item name="colorPrimaryLight">@color/holo_primary_light</item>
+ <item name="colorControlActivated">@color/holo_control_activated</item>
+ <item name="colorControlNormal">@color/holo_control_normal</item>
+ <item name="colorButtonPressed">@color/holo_button_pressed</item>
+ <item name="colorButtonNormal">@color/holo_button_normal</item>
+
<!-- Text styles -->
<item name="textAppearance">@android:style/TextAppearance.Holo</item>
<item name="textAppearanceInverse">@android:style/TextAppearance.Holo.Inverse</item>
@@ -1181,6 +1214,7 @@
<item name="actionDropDownStyle">@android:style/Widget.Holo.Spinner.DropDown.ActionBar</item>
<item name="actionButtonStyle">@android:style/Widget.Holo.ActionButton</item>
<item name="actionOverflowButtonStyle">@android:style/Widget.Holo.ActionButton.Overflow</item>
+ <item name="actionOverflowMenuStyle">?android:attr/popupMenuStyle</item>
<item name="actionModeBackground">@android:drawable/cab_background_top_holo_dark</item>
<item name="actionModeSplitBackground">@android:drawable/cab_background_bottom_holo_dark</item>
<item name="actionModeCloseDrawable">@android:drawable/ic_cab_done_holo_dark</item>
@@ -1268,6 +1302,14 @@
<item name="colorMultiSelectHighlight">@color/holo_green_light</item>
<item name="colorActivatedHighlight">@color/holo_blue_dark</item>
+ <item name="colorPrimaryDark">@color/holo_light_primary_dark</item>
+ <item name="colorPrimary">@color/holo_light_primary</item>
+ <item name="colorPrimaryLight">@color/holo_light_primary_light</item>
+ <item name="colorControlActivated">@color/holo_light_control_activated</item>
+ <item name="colorControlNormal">@color/holo_light_control_normal</item>
+ <item name="colorButtonPressed">@color/holo_light_button_pressed</item>
+ <item name="colorButtonNormal">@color/holo_light_button_normal</item>
+
<!-- Text styles -->
<item name="textAppearance">@android:style/TextAppearance.Holo.Light</item>
<item name="textAppearanceInverse">@android:style/TextAppearance.Holo.Light.Inverse</item>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 0ce5094..dbc3d9e 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -51,139 +51,139 @@
-->
<style name="Theme.DeviceDefault" parent="Theme.Quantum" >
<!-- Text styles -->
- <item name="textAppearance">@android:style/TextAppearance.DeviceDefault</item>
- <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Inverse</item>
+ <item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
+ <item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
- <item name="textAppearanceLarge">@android:style/TextAppearance.DeviceDefault.Large</item>
- <item name="textAppearanceMedium">@android:style/TextAppearance.DeviceDefault.Medium</item>
- <item name="textAppearanceSmall">@android:style/TextAppearance.DeviceDefault.Small</item>
- <item name="textAppearanceLargeInverse">@android:style/TextAppearance.DeviceDefault.Large.Inverse</item>
- <item name="textAppearanceMediumInverse">@android:style/TextAppearance.DeviceDefault.Medium.Inverse</item>
- <item name="textAppearanceSmallInverse">@android:style/TextAppearance.DeviceDefault.Small.Inverse</item>
- <item name="textAppearanceSearchResultTitle">@android:style/TextAppearance.DeviceDefault.SearchResult.Title</item>
- <item name="textAppearanceSearchResultSubtitle">@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle</item>
+ <item name="textAppearanceLarge">@style/TextAppearance.DeviceDefault.Large</item>
+ <item name="textAppearanceMedium">@style/TextAppearance.DeviceDefault.Medium</item>
+ <item name="textAppearanceSmall">@style/TextAppearance.DeviceDefault.Small</item>
+ <item name="textAppearanceLargeInverse">@style/TextAppearance.DeviceDefault.Large.Inverse</item>
+ <item name="textAppearanceMediumInverse">@style/TextAppearance.DeviceDefault.Medium.Inverse</item>
+ <item name="textAppearanceSmallInverse">@style/TextAppearance.DeviceDefault.Small.Inverse</item>
+ <item name="textAppearanceSearchResultTitle">@style/TextAppearance.DeviceDefault.SearchResult.Title</item>
+ <item name="textAppearanceSearchResultSubtitle">@style/TextAppearance.DeviceDefault.SearchResult.Subtitle</item>
- <item name="textAppearanceButton">@android:style/TextAppearance.DeviceDefault.Widget.Button</item>
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
- <item name="textAppearanceLargePopupMenu">@android:style/TextAppearance.DeviceDefault.Widget.PopupMenu.Large</item>
- <item name="textAppearanceSmallPopupMenu">@android:style/TextAppearance.DeviceDefault.Widget.PopupMenu.Small</item>
+ <item name="textAppearanceLargePopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Large</item>
+ <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Small</item>
<!-- Button styles -->
- <item name="buttonStyle">@android:style/Widget.DeviceDefault.Button</item>
+ <item name="buttonStyle">@style/Widget.DeviceDefault.Button</item>
- <item name="buttonStyleSmall">@android:style/Widget.DeviceDefault.Button.Small</item>
- <item name="buttonStyleInset">@android:style/Widget.DeviceDefault.Button.Inset</item>
+ <item name="buttonStyleSmall">@style/Widget.DeviceDefault.Button.Small</item>
+ <item name="buttonStyleInset">@style/Widget.DeviceDefault.Button.Inset</item>
- <item name="buttonStyleToggle">@android:style/Widget.DeviceDefault.Button.Toggle</item>
- <item name="switchStyle">@android:style/Widget.DeviceDefault.CompoundButton.Switch</item>
+ <item name="buttonStyleToggle">@style/Widget.DeviceDefault.Button.Toggle</item>
+ <item name="switchStyle">@style/Widget.DeviceDefault.CompoundButton.Switch</item>
- <item name="borderlessButtonStyle">@android:style/Widget.DeviceDefault.Button.Borderless</item>
+ <item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Button.Borderless</item>
- <item name="listSeparatorTextViewStyle">@android:style/Widget.DeviceDefault.TextView.ListSeparator</item>
+ <item name="listSeparatorTextViewStyle">@style/Widget.DeviceDefault.TextView.ListSeparator</item>
<!-- Window attributes -->
- <item name="windowTitleStyle">@android:style/WindowTitle.DeviceDefault</item>
- <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground.DeviceDefault</item>
- <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Activity</item>
+ <item name="windowTitleStyle">@style/WindowTitle.DeviceDefault</item>
+ <item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.DeviceDefault</item>
+ <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Activity</item>
<!-- Dialog attributes -->
- <item name="dialogTheme">@android:style/Theme.DeviceDefault.Dialog</item>
+ <item name="dialogTheme">@style/Theme.DeviceDefault.Dialog</item>
<!-- AlertDialog attributes -->
- <item name="alertDialogTheme">@android:style/Theme.DeviceDefault.Dialog.Alert</item>
- <item name="alertDialogStyle">@android:style/AlertDialog.DeviceDefault</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+ <item name="alertDialogStyle">@style/AlertDialog.DeviceDefault</item>
<!-- Presentation attributes -->
- <item name="presentationTheme">@android:style/Theme.DeviceDefault.Dialog.Presentation</item>
+ <item name="presentationTheme">@style/Theme.DeviceDefault.Dialog.Presentation</item>
<!-- Text selection handle attributes -->
- <item name="textSelectHandleWindowStyle">@android:style/Widget.DeviceDefault.TextSelectHandle</item>
- <item name="textSuggestionsWindowStyle">@android:style/Widget.DeviceDefault.TextSuggestionsPopupWindow</item>
+ <item name="textSelectHandleWindowStyle">@style/Widget.DeviceDefault.TextSelectHandle</item>
+ <item name="textSuggestionsWindowStyle">@style/Widget.DeviceDefault.TextSuggestionsPopupWindow</item>
<!-- Widget styles -->
- <item name="absListViewStyle">@android:style/Widget.DeviceDefault.AbsListView</item>
- <item name="autoCompleteTextViewStyle">@android:style/Widget.DeviceDefault.AutoCompleteTextView</item>
- <item name="checkboxStyle">@android:style/Widget.DeviceDefault.CompoundButton.CheckBox</item>
- <item name="checkedTextViewStyle">@android:style/Widget.DeviceDefault.CheckedTextView</item>
- <item name="dropDownListViewStyle">@android:style/Widget.DeviceDefault.ListView.DropDown</item>
- <item name="editTextStyle">@android:style/Widget.DeviceDefault.EditText</item>
- <item name="expandableListViewStyle">@android:style/Widget.DeviceDefault.ExpandableListView</item>
- <item name="expandableListViewWhiteStyle">@android:style/Widget.DeviceDefault.ExpandableListView.White</item>
- <item name="galleryStyle">@android:style/Widget.DeviceDefault.Gallery</item>
- <item name="gestureOverlayViewStyle">@android:style/Widget.DeviceDefault.GestureOverlayView</item>
- <item name="gridViewStyle">@android:style/Widget.DeviceDefault.GridView</item>
- <item name="imageButtonStyle">@android:style/Widget.DeviceDefault.ImageButton</item>
- <item name="imageWellStyle">@android:style/Widget.DeviceDefault.ImageWell</item>
- <item name="listViewStyle">@android:style/Widget.DeviceDefault.ListView</item>
- <item name="listViewWhiteStyle">@android:style/Widget.DeviceDefault.ListView.White</item>
- <item name="popupWindowStyle">@android:style/Widget.DeviceDefault.PopupWindow</item>
- <item name="progressBarStyle">@android:style/Widget.DeviceDefault.ProgressBar</item>
- <item name="progressBarStyleHorizontal">@android:style/Widget.DeviceDefault.ProgressBar.Horizontal</item>
- <item name="progressBarStyleSmall">@android:style/Widget.DeviceDefault.ProgressBar.Small</item>
- <item name="progressBarStyleSmallTitle">@android:style/Widget.DeviceDefault.ProgressBar.Small.Title</item>
- <item name="progressBarStyleLarge">@android:style/Widget.DeviceDefault.ProgressBar.Large</item>
- <item name="progressBarStyleInverse">@android:style/Widget.DeviceDefault.ProgressBar.Inverse</item>
- <item name="progressBarStyleSmallInverse">@android:style/Widget.DeviceDefault.ProgressBar.Small.Inverse</item>
- <item name="progressBarStyleLargeInverse">@android:style/Widget.DeviceDefault.ProgressBar.Large.Inverse</item>
- <item name="seekBarStyle">@android:style/Widget.DeviceDefault.SeekBar</item>
- <item name="ratingBarStyle">@android:style/Widget.DeviceDefault.RatingBar</item>
- <item name="ratingBarStyleIndicator">@android:style/Widget.DeviceDefault.RatingBar.Indicator</item>
- <item name="ratingBarStyleSmall">@android:style/Widget.DeviceDefault.RatingBar.Small</item>
- <item name="radioButtonStyle">@android:style/Widget.DeviceDefault.CompoundButton.RadioButton</item>
- <item name="scrollViewStyle">@android:style/Widget.DeviceDefault.ScrollView</item>
- <item name="horizontalScrollViewStyle">@android:style/Widget.DeviceDefault.HorizontalScrollView</item>
- <item name="dropDownSpinnerStyle">@android:style/Widget.DeviceDefault.Spinner.DropDown</item>
- <item name="starStyle">@android:style/Widget.DeviceDefault.CompoundButton.Star</item>
- <item name="tabWidgetStyle">@android:style/Widget.DeviceDefault.TabWidget</item>
- <item name="textViewStyle">@android:style/Widget.DeviceDefault.TextView</item>
- <item name="webTextViewStyle">@android:style/Widget.DeviceDefault.WebTextView</item>
- <item name="webViewStyle">@android:style/Widget.DeviceDefault.WebView</item>
- <item name="dropDownItemStyle">@android:style/Widget.DeviceDefault.DropDownItem</item>
- <item name="spinnerDropDownItemStyle">@android:style/Widget.DeviceDefault.DropDownItem.Spinner</item>
- <item name="spinnerItemStyle">@android:style/Widget.DeviceDefault.TextView.SpinnerItem</item>
- <item name="dropDownHintAppearance">@android:style/TextAppearance.DeviceDefault.Widget.DropDownHint</item>
- <item name="keyboardViewStyle">@android:style/Widget.DeviceDefault.KeyboardView</item>
- <item name="quickContactBadgeStyleWindowSmall">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowSmall</item>
- <item name="quickContactBadgeStyleWindowMedium">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowMedium</item>
- <item name="quickContactBadgeStyleWindowLarge">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowLarge</item>
- <item name="quickContactBadgeStyleSmallWindowSmall">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall</item>
- <item name="quickContactBadgeStyleSmallWindowMedium">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium</item>
- <item name="quickContactBadgeStyleSmallWindowLarge">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge</item>
- <item name="listPopupWindowStyle">@android:style/Widget.DeviceDefault.ListPopupWindow</item>
- <item name="popupMenuStyle">@android:style/Widget.DeviceDefault.PopupMenu</item>
- <item name="stackViewStyle">@android:style/Widget.DeviceDefault.StackView</item>
+ <item name="absListViewStyle">@style/Widget.DeviceDefault.AbsListView</item>
+ <item name="autoCompleteTextViewStyle">@style/Widget.DeviceDefault.AutoCompleteTextView</item>
+ <item name="checkboxStyle">@style/Widget.DeviceDefault.CompoundButton.CheckBox</item>
+ <item name="checkedTextViewStyle">@style/Widget.DeviceDefault.CheckedTextView</item>
+ <item name="dropDownListViewStyle">@style/Widget.DeviceDefault.ListView.DropDown</item>
+ <item name="editTextStyle">@style/Widget.DeviceDefault.EditText</item>
+ <item name="expandableListViewStyle">@style/Widget.DeviceDefault.ExpandableListView</item>
+ <item name="expandableListViewWhiteStyle">@style/Widget.DeviceDefault.ExpandableListView.White</item>
+ <item name="galleryStyle">@style/Widget.DeviceDefault.Gallery</item>
+ <item name="gestureOverlayViewStyle">@style/Widget.DeviceDefault.GestureOverlayView</item>
+ <item name="gridViewStyle">@style/Widget.DeviceDefault.GridView</item>
+ <item name="imageButtonStyle">@style/Widget.DeviceDefault.ImageButton</item>
+ <item name="imageWellStyle">@style/Widget.DeviceDefault.ImageWell</item>
+ <item name="listViewStyle">@style/Widget.DeviceDefault.ListView</item>
+ <item name="listViewWhiteStyle">@style/Widget.DeviceDefault.ListView.White</item>
+ <item name="popupWindowStyle">@style/Widget.DeviceDefault.PopupWindow</item>
+ <item name="progressBarStyle">@style/Widget.DeviceDefault.ProgressBar</item>
+ <item name="progressBarStyleHorizontal">@style/Widget.DeviceDefault.ProgressBar.Horizontal</item>
+ <item name="progressBarStyleSmall">@style/Widget.DeviceDefault.ProgressBar.Small</item>
+ <item name="progressBarStyleSmallTitle">@style/Widget.DeviceDefault.ProgressBar.Small.Title</item>
+ <item name="progressBarStyleLarge">@style/Widget.DeviceDefault.ProgressBar.Large</item>
+ <item name="progressBarStyleInverse">@style/Widget.DeviceDefault.ProgressBar.Inverse</item>
+ <item name="progressBarStyleSmallInverse">@style/Widget.DeviceDefault.ProgressBar.Small.Inverse</item>
+ <item name="progressBarStyleLargeInverse">@style/Widget.DeviceDefault.ProgressBar.Large.Inverse</item>
+ <item name="seekBarStyle">@style/Widget.DeviceDefault.SeekBar</item>
+ <item name="ratingBarStyle">@style/Widget.DeviceDefault.RatingBar</item>
+ <item name="ratingBarStyleIndicator">@style/Widget.DeviceDefault.RatingBar.Indicator</item>
+ <item name="ratingBarStyleSmall">@style/Widget.DeviceDefault.RatingBar.Small</item>
+ <item name="radioButtonStyle">@style/Widget.DeviceDefault.CompoundButton.RadioButton</item>
+ <item name="scrollViewStyle">@style/Widget.DeviceDefault.ScrollView</item>
+ <item name="horizontalScrollViewStyle">@style/Widget.DeviceDefault.HorizontalScrollView</item>
+ <item name="dropDownSpinnerStyle">@style/Widget.DeviceDefault.Spinner.DropDown</item>
+ <item name="starStyle">@style/Widget.DeviceDefault.CompoundButton.Star</item>
+ <item name="tabWidgetStyle">@style/Widget.DeviceDefault.TabWidget</item>
+ <item name="textViewStyle">@style/Widget.DeviceDefault.TextView</item>
+ <item name="webTextViewStyle">@style/Widget.DeviceDefault.WebTextView</item>
+ <item name="webViewStyle">@style/Widget.DeviceDefault.WebView</item>
+ <item name="dropDownItemStyle">@style/Widget.DeviceDefault.DropDownItem</item>
+ <item name="spinnerDropDownItemStyle">@style/Widget.DeviceDefault.DropDownItem.Spinner</item>
+ <item name="spinnerItemStyle">@style/Widget.DeviceDefault.TextView.SpinnerItem</item>
+ <item name="dropDownHintAppearance">@style/TextAppearance.DeviceDefault.Widget.DropDownHint</item>
+ <item name="keyboardViewStyle">@style/Widget.DeviceDefault.KeyboardView</item>
+ <item name="quickContactBadgeStyleWindowSmall">@style/Widget.DeviceDefault.QuickContactBadge.WindowSmall</item>
+ <item name="quickContactBadgeStyleWindowMedium">@style/Widget.DeviceDefault.QuickContactBadge.WindowMedium</item>
+ <item name="quickContactBadgeStyleWindowLarge">@style/Widget.DeviceDefault.QuickContactBadge.WindowLarge</item>
+ <item name="quickContactBadgeStyleSmallWindowSmall">@style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall</item>
+ <item name="quickContactBadgeStyleSmallWindowMedium">@style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium</item>
+ <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge</item>
+ <item name="listPopupWindowStyle">@style/Widget.DeviceDefault.ListPopupWindow</item>
+ <item name="popupMenuStyle">@style/Widget.DeviceDefault.PopupMenu</item>
+ <item name="stackViewStyle">@style/Widget.DeviceDefault.StackView</item>
<!-- Preference styles -->
- <item name="preferenceScreenStyle">@android:style/Preference.DeviceDefault.PreferenceScreen</item>
- <item name="preferenceCategoryStyle">@android:style/Preference.DeviceDefault.Category</item>
- <item name="preferenceStyle">@android:style/Preference.DeviceDefault</item>
- <item name="preferenceInformationStyle">@android:style/Preference.DeviceDefault.Information</item>
- <item name="checkBoxPreferenceStyle">@android:style/Preference.DeviceDefault.CheckBoxPreference</item>
- <item name="switchPreferenceStyle">@android:style/Preference.DeviceDefault.SwitchPreference</item>
- <item name="yesNoPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference.YesNoPreference</item>
- <item name="dialogPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference</item>
- <item name="editTextPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference.EditTextPreference</item>
- <item name="ringtonePreferenceStyle">@android:style/Preference.DeviceDefault.RingtonePreference</item>
+ <item name="preferenceScreenStyle">@style/Preference.DeviceDefault.PreferenceScreen</item>
+ <item name="preferenceCategoryStyle">@style/Preference.DeviceDefault.Category</item>
+ <item name="preferenceStyle">@style/Preference.DeviceDefault</item>
+ <item name="preferenceInformationStyle">@style/Preference.DeviceDefault.Information</item>
+ <item name="checkBoxPreferenceStyle">@style/Preference.DeviceDefault.CheckBoxPreference</item>
+ <item name="switchPreferenceStyle">@style/Preference.DeviceDefault.SwitchPreference</item>
+ <item name="yesNoPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference.YesNoPreference</item>
+ <item name="dialogPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference</item>
+ <item name="editTextPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference.EditTextPreference</item>
+ <item name="ringtonePreferenceStyle">@style/Preference.DeviceDefault.RingtonePreference</item>
<!-- Action bar styles -->
- <item name="actionDropDownStyle">@android:style/Widget.DeviceDefault.Spinner.DropDown.ActionBar</item>
- <item name="actionButtonStyle">@android:style/Widget.DeviceDefault.ActionButton</item>
- <item name="actionOverflowButtonStyle">@android:style/Widget.DeviceDefault.ActionButton.Overflow</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.ActionBar.TabView</item>
<item name="actionBarTabBarStyle">@style/Widget.DeviceDefault.ActionBar.TabBar</item>
<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">@android:style/Widget.DeviceDefault.ActionBar</item>
- <item name="actionModePopupWindowStyle">@android:style/Widget.DeviceDefault.PopupWindow.ActionMode</item>
+ <item name="actionBarStyle">@style/Widget.DeviceDefault.ActionBar</item>
+ <item name="actionModePopupWindowStyle">@style/Widget.DeviceDefault.PopupWindow.ActionMode</item>
- <item name="buttonBarStyle">@android:style/DeviceDefault.ButtonBar</item>
- <item name="segmentedButtonStyle">@android:style/DeviceDefault.SegmentedButton</item>
+ <item name="buttonBarStyle">@style/DeviceDefault.ButtonBar</item>
+ <item name="segmentedButtonStyle">@style/DeviceDefault.SegmentedButton</item>
<item name="searchDialogTheme">@style/Theme.DeviceDefault.SearchBar</item>
<!-- PreferenceFrameLayout attributes -->
- <item name="preferenceFrameLayoutStyle">@android:style/Widget.DeviceDefault.PreferenceFrameLayout</item>
+ <item name="preferenceFrameLayoutStyle">@style/Widget.DeviceDefault.PreferenceFrameLayout</item>
<!-- NumberPicker style-->
<item name="numberPickerStyle">@style/Widget.DeviceDefault.NumberPicker</item>
@@ -201,165 +201,245 @@
<item name="timePickerHeaderAmPmLabelTextAppearance">@style/TextAppearance.DeviceDefault.TimePicker.AmPmLabel</item>
<!-- TimePicker dialog theme -->
- <item name="timePickerDialogTheme">@android:style/Theme.DeviceDefault.Dialog.TimePicker</item>
+ <item name="timePickerDialogTheme">@style/Theme.DeviceDefault.Dialog.TimePicker</item>
<!-- DatePicker style -->
<item name="datePickerStyle">@style/Widget.DeviceDefault.DatePicker</item>
- <item name="mediaRouteButtonStyle">@android:style/Widget.DeviceDefault.MediaRouteButton</item>
+ <item name="mediaRouteButtonStyle">@style/Widget.DeviceDefault.MediaRouteButton</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
- <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Quantum.NoActionBar" >
- </style>
+ <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Quantum.NoActionBar" />
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar. This theme
sets {@link android.R.attr#windowFullscreen} to true. -->
- <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Quantum.NoActionBar.Fullscreen" >
- </style>
+ <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Quantum.NoActionBar.Fullscreen" />
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
extending in to overscan region. This theme
sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
to true. -->
- <style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Quantum.NoActionBar.Overscan" >
- </style>
+ <style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Quantum.NoActionBar.Overscan" />
<!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
{@link android.R.attr#windowTranslucentNavigation} to true. -->
- <style name="Theme.DeviceDefault.NoActionBar.TranslucentDecor" parent="Theme.Quantum.NoActionBar.TranslucentDecor" >
+ <style name="Theme.DeviceDefault.NoActionBar.TranslucentDecor" parent="Theme.Quantum.NoActionBar.TranslucentDecor" />
+
+ <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
+ floating (not fill the entire screen), and puts a frame around its contents. You can set this
+ theme on an activity if you would like to make an activity that looks like a Dialog. -->
+ <style name="Theme.DeviceDefault.Dialog" parent="Theme.Quantum.Dialog" >
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
+ <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+
+ <item name="buttonBarStyle">@style/DeviceDefault.ButtonBar.AlertDialog</item>
+ <item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Button.Borderless.Small</item>
+
+ <item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
+ <item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
</style>
+ <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
+ regular dialog. -->
+ <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Quantum.Dialog.MinWidth" />
+
+ <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
+ <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Quantum.Dialog.NoActionBar" />
+
+ <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
+ for a regular dialog. -->
+ <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Quantum.Dialog.NoActionBar.MinWidth" />
+
+ <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
+ <style name="Theme.DeviceDefault.Dialog.FixedSize">
+ <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+ </style>
+
+ <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
+ <style name="Theme.DeviceDefault.Dialog.NoActionBar.FixedSize">
+ <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+ </style>
+
+ <!-- DeviceDefault theme for a window that will be displayed either full-screen on smaller
+ screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
+ <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Quantum.DialogWhenLarge" />
+
+ <!-- DeviceDefault theme for a window without an action bar that will be displayed either
+ full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
+ xlarge). -->
+ <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Quantum.DialogWhenLarge.NoActionBar" />
+
+ <!-- DeviceDefault theme for a presentation window on a secondary display. -->
+ <style name="Theme.DeviceDefault.Dialog.Presentation" parent="Theme.Quantum.Dialog.Presentation" />
+
+ <style name="Theme.DeviceDefault.Dialog.TimePicker" parent="Theme.Quantum.Dialog.TimePicker"/>
+
+ <!-- DeviceDefault theme for panel windows. This removes all extraneous window
+ decorations, so you basically have an empty rectangle in which to place your content. It makes
+ the window floating, with a transparent background, and turns off dimming behind the window. -->
+ <style name="Theme.DeviceDefault.Panel" parent="Theme.Quantum.Panel" />
+
+ <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
+ behind them. -->
+ <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Quantum.Wallpaper" />
+
+ <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
+ behind them and without an action bar. -->
+ <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Quantum.Wallpaper.NoTitleBar" />
+
+ <!-- DeviceDefault style for input methods, which is used by the
+ {@link android.inputmethodservice.InputMethodService} class.-->
+ <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Quantum.InputMethod" />
+
+ <!-- DeviceDefault style for input methods, which is used by the
+ {@link android.service.voice.VoiceInteractionSession} class.-->
+ <style name="Theme.DeviceDefault.VoiceInteractionSession" parent="Theme.Quantum.VoiceInteractionSession" >
+
+ </style>
+ <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Quantum.Dialog.Alert">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
+ </style>
+
+ <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Quantum.SearchBar" />
+ <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Quantum.Dialog.NoFrame" />
+
<!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
<style name="Theme.DeviceDefault.Light" parent="Theme.Quantum.Light" >
<!-- Text styles -->
- <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Light</item>
- <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Light.Inverse</item>
+ <item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
+ <item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
- <item name="textAppearanceLarge">@android:style/TextAppearance.DeviceDefault.Light.Large</item>
- <item name="textAppearanceMedium">@android:style/TextAppearance.DeviceDefault.Light.Medium</item>
- <item name="textAppearanceSmall">@android:style/TextAppearance.DeviceDefault.Light.Small</item>
- <item name="textAppearanceLargeInverse">@android:style/TextAppearance.DeviceDefault.Light.Large.Inverse</item>
- <item name="textAppearanceMediumInverse">@android:style/TextAppearance.DeviceDefault.Light.Medium.Inverse</item>
- <item name="textAppearanceSmallInverse">@android:style/TextAppearance.DeviceDefault.Light.Small.Inverse</item>
- <item name="textAppearanceSearchResultTitle">@android:style/TextAppearance.DeviceDefault.Light.SearchResult.Title</item>
- <item name="textAppearanceSearchResultSubtitle">@android:style/TextAppearance.DeviceDefault.Light.SearchResult.Subtitle</item>
+ <item name="textAppearanceLarge">@style/TextAppearance.DeviceDefault.Large</item>
+ <item name="textAppearanceMedium">@style/TextAppearance.DeviceDefault.Medium</item>
+ <item name="textAppearanceSmall">@style/TextAppearance.DeviceDefault.Small</item>
+ <item name="textAppearanceLargeInverse">@style/TextAppearance.DeviceDefault.Large.Inverse</item>
+ <item name="textAppearanceMediumInverse">@style/TextAppearance.DeviceDefault.Medium.Inverse</item>
+ <item name="textAppearanceSmallInverse">@style/TextAppearance.DeviceDefault.Small.Inverse</item>
+ <item name="textAppearanceSearchResultTitle">@style/TextAppearance.DeviceDefault.SearchResult.Title</item>
+ <item name="textAppearanceSearchResultSubtitle">@style/TextAppearance.DeviceDefault.SearchResult.Subtitle</item>
- <item name="textAppearanceButton">@android:style/TextAppearance.DeviceDefault.Light.Widget.Button</item>
+ <item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
- <item name="textAppearanceLargePopupMenu">@android:style/TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Large</item>
- <item name="textAppearanceSmallPopupMenu">@android:style/TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Small</item>
+ <item name="textAppearanceLargePopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Large</item>
+ <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.DeviceDefault.Widget.PopupMenu.Small</item>
<!-- Button styles -->
- <item name="buttonStyle">@android:style/Widget.DeviceDefault.Light.Button</item>
+ <item name="buttonStyle">@style/Widget.DeviceDefault.Light.Button</item>
- <item name="buttonStyleSmall">@android:style/Widget.DeviceDefault.Light.Button.Small</item>
- <item name="buttonStyleInset">@android:style/Widget.DeviceDefault.Light.Button.Inset</item>
+ <item name="buttonStyleSmall">@style/Widget.DeviceDefault.Light.Button.Small</item>
+ <item name="buttonStyleInset">@style/Widget.DeviceDefault.Light.Button.Inset</item>
- <item name="buttonStyleToggle">@android:style/Widget.DeviceDefault.Light.Button.Toggle</item>
+ <item name="buttonStyleToggle">@style/Widget.DeviceDefault.Light.Button.Toggle</item>
- <item name="borderlessButtonStyle">@android:style/Widget.DeviceDefault.Light.Button.Borderless</item>
+ <item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Light.Button.Borderless</item>
- <item name="listSeparatorTextViewStyle">@android:style/Widget.DeviceDefault.Light.TextView.ListSeparator</item>
+ <item name="listSeparatorTextViewStyle">@style/Widget.DeviceDefault.Light.TextView.ListSeparator</item>
- <item name="windowTitleStyle">@android:style/WindowTitle.DeviceDefault</item>
- <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground.DeviceDefault</item>
- <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Activity</item>
+ <item name="windowTitleStyle">@style/WindowTitle.DeviceDefault</item>
+ <item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.DeviceDefault</item>
+ <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Activity</item>
<!-- Dialog attributes -->
- <item name="dialogTheme">@android:style/Theme.DeviceDefault.Light.Dialog</item>
+ <item name="dialogTheme">@style/Theme.DeviceDefault.Light.Dialog</item>
<!-- AlertDialog attributes -->
- <item name="alertDialogTheme">@android:style/Theme.DeviceDefault.Light.Dialog.Alert</item>
- <item name="alertDialogStyle">@android:style/AlertDialog.DeviceDefault.Light</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+ <item name="alertDialogStyle">@style/AlertDialog.DeviceDefault.Light</item>
<!-- Presentation attributes -->
- <item name="presentationTheme">@android:style/Theme.DeviceDefault.Light.Dialog.Presentation</item>
+ <item name="presentationTheme">@style/Theme.DeviceDefault.Light.Dialog.Presentation</item>
<!-- Text selection handle attributes -->
- <item name="textSelectHandleWindowStyle">@android:style/Widget.DeviceDefault.TextSelectHandle</item>
- <item name="textSuggestionsWindowStyle">@android:style/Widget.DeviceDefault.Light.TextSuggestionsPopupWindow</item>
+ <item name="textSelectHandleWindowStyle">@style/Widget.DeviceDefault.TextSelectHandle</item>
+ <item name="textSuggestionsWindowStyle">@style/Widget.DeviceDefault.Light.TextSuggestionsPopupWindow</item>
<!-- Widget styles -->
- <item name="absListViewStyle">@android:style/Widget.DeviceDefault.Light.AbsListView</item>
- <item name="autoCompleteTextViewStyle">@android:style/Widget.DeviceDefault.Light.AutoCompleteTextView</item>
- <item name="checkboxStyle">@android:style/Widget.DeviceDefault.Light.CompoundButton.CheckBox</item>
- <item name="checkedTextViewStyle">@android:style/Widget.DeviceDefault.Light.CheckedTextView</item>
- <item name="dropDownListViewStyle">@android:style/Widget.DeviceDefault.Light.ListView.DropDown</item>
- <item name="editTextStyle">@android:style/Widget.DeviceDefault.Light.EditText</item>
- <item name="expandableListViewStyle">@android:style/Widget.DeviceDefault.Light.ExpandableListView</item>
- <item name="expandableListViewWhiteStyle">@android:style/Widget.DeviceDefault.Light.ExpandableListView.White</item>
- <item name="galleryStyle">@android:style/Widget.DeviceDefault.Light.Gallery</item>
- <item name="gestureOverlayViewStyle">@android:style/Widget.DeviceDefault.Light.GestureOverlayView</item>
- <item name="gridViewStyle">@android:style/Widget.DeviceDefault.Light.GridView</item>
- <item name="imageButtonStyle">@android:style/Widget.DeviceDefault.Light.ImageButton</item>
- <item name="imageWellStyle">@android:style/Widget.DeviceDefault.Light.ImageWell</item>
- <item name="listViewStyle">@android:style/Widget.DeviceDefault.Light.ListView</item>
- <item name="listViewWhiteStyle">@android:style/Widget.DeviceDefault.Light.ListView.White</item>
- <item name="popupWindowStyle">@android:style/Widget.DeviceDefault.Light.PopupWindow</item>
- <item name="progressBarStyle">@android:style/Widget.DeviceDefault.Light.ProgressBar</item>
- <item name="progressBarStyleHorizontal">@android:style/Widget.DeviceDefault.Light.ProgressBar.Horizontal</item>
- <item name="progressBarStyleSmall">@android:style/Widget.DeviceDefault.Light.ProgressBar.Small</item>
- <item name="progressBarStyleSmallTitle">@android:style/Widget.DeviceDefault.Light.ProgressBar.Small.Title</item>
- <item name="progressBarStyleLarge">@android:style/Widget.DeviceDefault.Light.ProgressBar.Large</item>
- <item name="progressBarStyleInverse">@android:style/Widget.DeviceDefault.Light.ProgressBar.Inverse</item>
- <item name="progressBarStyleSmallInverse">@android:style/Widget.DeviceDefault.Light.ProgressBar.Small.Inverse</item>
- <item name="progressBarStyleLargeInverse">@android:style/Widget.DeviceDefault.Light.ProgressBar.Large.Inverse</item>
- <item name="seekBarStyle">@android:style/Widget.DeviceDefault.Light.SeekBar</item>
- <item name="ratingBarStyle">@android:style/Widget.DeviceDefault.Light.RatingBar</item>
- <item name="ratingBarStyleIndicator">@android:style/Widget.DeviceDefault.Light.RatingBar.Indicator</item>
- <item name="ratingBarStyleSmall">@android:style/Widget.DeviceDefault.Light.RatingBar.Small</item>
- <item name="radioButtonStyle">@android:style/Widget.DeviceDefault.Light.CompoundButton.RadioButton</item>
- <item name="scrollViewStyle">@android:style/Widget.DeviceDefault.Light.ScrollView</item>
- <item name="horizontalScrollViewStyle">@android:style/Widget.DeviceDefault.Light.HorizontalScrollView</item>
- <item name="dropDownSpinnerStyle">@android:style/Widget.DeviceDefault.Light.Spinner.DropDown</item>
- <item name="starStyle">@android:style/Widget.DeviceDefault.Light.CompoundButton.Star</item>
- <item name="tabWidgetStyle">@android:style/Widget.DeviceDefault.Light.TabWidget</item>
- <item name="textViewStyle">@android:style/Widget.DeviceDefault.Light.TextView</item>
- <item name="webTextViewStyle">@android:style/Widget.DeviceDefault.Light.WebTextView</item>
- <item name="webViewStyle">@android:style/Widget.DeviceDefault.Light.WebView</item>
- <item name="dropDownItemStyle">@android:style/Widget.DeviceDefault.Light.DropDownItem</item>
- <item name="spinnerDropDownItemStyle">@android:style/Widget.DeviceDefault.Light.DropDownItem.Spinner</item>
- <item name="spinnerItemStyle">@android:style/Widget.DeviceDefault.Light.TextView.SpinnerItem</item>
- <item name="dropDownHintAppearance">@android:style/TextAppearance.DeviceDefault.Widget.DropDownHint</item>
- <item name="keyboardViewStyle">@android:style/Widget.DeviceDefault.KeyboardView</item>
- <item name="quickContactBadgeStyleWindowSmall">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowSmall</item>
- <item name="quickContactBadgeStyleWindowMedium">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowMedium</item>
- <item name="quickContactBadgeStyleWindowLarge">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowLarge</item>
- <item name="quickContactBadgeStyleSmallWindowSmall">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall</item>
- <item name="quickContactBadgeStyleSmallWindowMedium">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium</item>
- <item name="quickContactBadgeStyleSmallWindowLarge">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge</item>
- <item name="listPopupWindowStyle">@android:style/Widget.DeviceDefault.Light.ListPopupWindow</item>
- <item name="popupMenuStyle">@android:style/Widget.DeviceDefault.Light.PopupMenu</item>
- <item name="stackViewStyle">@android:style/Widget.DeviceDefault.StackView</item>
+ <item name="absListViewStyle">@style/Widget.DeviceDefault.Light.AbsListView</item>
+ <item name="autoCompleteTextViewStyle">@style/Widget.DeviceDefault.Light.AutoCompleteTextView</item>
+ <item name="checkboxStyle">@style/Widget.DeviceDefault.Light.CompoundButton.CheckBox</item>
+ <item name="checkedTextViewStyle">@style/Widget.DeviceDefault.Light.CheckedTextView</item>
+ <item name="dropDownListViewStyle">@style/Widget.DeviceDefault.Light.ListView.DropDown</item>
+ <item name="editTextStyle">@style/Widget.DeviceDefault.Light.EditText</item>
+ <item name="expandableListViewStyle">@style/Widget.DeviceDefault.Light.ExpandableListView</item>
+ <item name="expandableListViewWhiteStyle">@style/Widget.DeviceDefault.Light.ExpandableListView.White</item>
+ <item name="galleryStyle">@style/Widget.DeviceDefault.Light.Gallery</item>
+ <item name="gestureOverlayViewStyle">@style/Widget.DeviceDefault.Light.GestureOverlayView</item>
+ <item name="gridViewStyle">@style/Widget.DeviceDefault.Light.GridView</item>
+ <item name="imageButtonStyle">@style/Widget.DeviceDefault.Light.ImageButton</item>
+ <item name="imageWellStyle">@style/Widget.DeviceDefault.Light.ImageWell</item>
+ <item name="listViewStyle">@style/Widget.DeviceDefault.Light.ListView</item>
+ <item name="listViewWhiteStyle">@style/Widget.DeviceDefault.Light.ListView.White</item>
+ <item name="popupWindowStyle">@style/Widget.DeviceDefault.Light.PopupWindow</item>
+ <item name="progressBarStyle">@style/Widget.DeviceDefault.Light.ProgressBar</item>
+ <item name="progressBarStyleHorizontal">@style/Widget.DeviceDefault.Light.ProgressBar.Horizontal</item>
+ <item name="progressBarStyleSmall">@style/Widget.DeviceDefault.Light.ProgressBar.Small</item>
+ <item name="progressBarStyleSmallTitle">@style/Widget.DeviceDefault.Light.ProgressBar.Small.Title</item>
+ <item name="progressBarStyleLarge">@style/Widget.DeviceDefault.Light.ProgressBar.Large</item>
+ <item name="progressBarStyleInverse">@style/Widget.DeviceDefault.Light.ProgressBar.Inverse</item>
+ <item name="progressBarStyleSmallInverse">@style/Widget.DeviceDefault.Light.ProgressBar.Small.Inverse</item>
+ <item name="progressBarStyleLargeInverse">@style/Widget.DeviceDefault.Light.ProgressBar.Large.Inverse</item>
+ <item name="seekBarStyle">@style/Widget.DeviceDefault.Light.SeekBar</item>
+ <item name="ratingBarStyle">@style/Widget.DeviceDefault.Light.RatingBar</item>
+ <item name="ratingBarStyleIndicator">@style/Widget.DeviceDefault.Light.RatingBar.Indicator</item>
+ <item name="ratingBarStyleSmall">@style/Widget.DeviceDefault.Light.RatingBar.Small</item>
+ <item name="radioButtonStyle">@style/Widget.DeviceDefault.Light.CompoundButton.RadioButton</item>
+ <item name="scrollViewStyle">@style/Widget.DeviceDefault.Light.ScrollView</item>
+ <item name="horizontalScrollViewStyle">@style/Widget.DeviceDefault.Light.HorizontalScrollView</item>
+ <item name="dropDownSpinnerStyle">@style/Widget.DeviceDefault.Light.Spinner.DropDown</item>
+ <item name="starStyle">@style/Widget.DeviceDefault.Light.CompoundButton.Star</item>
+ <item name="tabWidgetStyle">@style/Widget.DeviceDefault.Light.TabWidget</item>
+ <item name="textViewStyle">@style/Widget.DeviceDefault.Light.TextView</item>
+ <item name="webTextViewStyle">@style/Widget.DeviceDefault.Light.WebTextView</item>
+ <item name="webViewStyle">@style/Widget.DeviceDefault.Light.WebView</item>
+ <item name="dropDownItemStyle">@style/Widget.DeviceDefault.Light.DropDownItem</item>
+ <item name="spinnerDropDownItemStyle">@style/Widget.DeviceDefault.Light.DropDownItem.Spinner</item>
+ <item name="spinnerItemStyle">@style/Widget.DeviceDefault.Light.TextView.SpinnerItem</item>
+ <item name="dropDownHintAppearance">@style/TextAppearance.DeviceDefault.Widget.DropDownHint</item>
+ <item name="keyboardViewStyle">@style/Widget.DeviceDefault.KeyboardView</item>
+ <item name="quickContactBadgeStyleWindowSmall">@style/Widget.DeviceDefault.QuickContactBadge.WindowSmall</item>
+ <item name="quickContactBadgeStyleWindowMedium">@style/Widget.DeviceDefault.QuickContactBadge.WindowMedium</item>
+ <item name="quickContactBadgeStyleWindowLarge">@style/Widget.DeviceDefault.QuickContactBadge.WindowLarge</item>
+ <item name="quickContactBadgeStyleSmallWindowSmall">@style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall</item>
+ <item name="quickContactBadgeStyleSmallWindowMedium">@style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium</item>
+ <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge</item>
+ <item name="listPopupWindowStyle">@style/Widget.DeviceDefault.Light.ListPopupWindow</item>
+ <item name="popupMenuStyle">@style/Widget.DeviceDefault.Light.PopupMenu</item>
+ <item name="stackViewStyle">@style/Widget.DeviceDefault.Light.StackView</item>
<!-- Preference styles -->
- <item name="preferenceScreenStyle">@android:style/Preference.DeviceDefault.PreferenceScreen</item>
- <item name="preferenceCategoryStyle">@android:style/Preference.DeviceDefault.Category</item>
- <item name="preferenceStyle">@android:style/Preference.DeviceDefault</item>
- <item name="preferenceInformationStyle">@android:style/Preference.DeviceDefault.Information</item>
- <item name="checkBoxPreferenceStyle">@android:style/Preference.DeviceDefault.CheckBoxPreference</item>
- <item name="switchPreferenceStyle">@android:style/Preference.DeviceDefault.SwitchPreference</item>
- <item name="yesNoPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference.YesNoPreference</item>
- <item name="dialogPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference</item>
- <item name="editTextPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference.EditTextPreference</item>
- <item name="ringtonePreferenceStyle">@android:style/Preference.DeviceDefault.RingtonePreference</item>
+ <item name="preferenceScreenStyle">@style/Preference.DeviceDefault.PreferenceScreen</item>
+ <item name="preferenceCategoryStyle">@style/Preference.DeviceDefault.Category</item>
+ <item name="preferenceStyle">@style/Preference.DeviceDefault</item>
+ <item name="preferenceInformationStyle">@style/Preference.DeviceDefault.Information</item>
+ <item name="checkBoxPreferenceStyle">@style/Preference.DeviceDefault.CheckBoxPreference</item>
+ <item name="switchPreferenceStyle">@style/Preference.DeviceDefault.SwitchPreference</item>
+ <item name="yesNoPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference.YesNoPreference</item>
+ <item name="dialogPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference</item>
+ <item name="editTextPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference.EditTextPreference</item>
+ <item name="ringtonePreferenceStyle">@style/Preference.DeviceDefault.RingtonePreference</item>
<!-- Action bar styles -->
- <item name="actionDropDownStyle">@android:style/Widget.DeviceDefault.Light.Spinner.DropDown.ActionBar</item>
- <item name="actionButtonStyle">@android:style/Widget.DeviceDefault.Light.ActionButton</item>
- <item name="actionOverflowButtonStyle">@android:style/Widget.DeviceDefault.Light.ActionButton.Overflow</item>
+ <item name="actionDropDownStyle">@style/Widget.DeviceDefault.Light.Spinner.DropDown.ActionBar</item>
+ <item name="actionButtonStyle">@style/Widget.DeviceDefault.Light.ActionButton</item>
+ <item name="actionOverflowButtonStyle">@style/Widget.DeviceDefault.Light.ActionButton.Overflow</item>
<item name="actionBarTabStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabView</item>
<item name="actionBarTabBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabBar</item>
<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">@android:style/Widget.DeviceDefault.Light.ActionBar</item>
- <item name="actionModePopupWindowStyle">@android:style/Widget.DeviceDefault.Light.PopupWindow.ActionMode</item>
+ <item name="actionBarStyle">@style/Widget.DeviceDefault.Light.ActionBar</item>
+ <item name="actionModePopupWindowStyle">@style/Widget.DeviceDefault.Light.PopupWindow.ActionMode</item>
- <item name="buttonBarStyle">@android:style/DeviceDefault.Light.ButtonBar</item>
- <item name="segmentedButtonStyle">@android:style/DeviceDefault.Light.SegmentedButton</item>
+ <item name="buttonBarStyle">@style/DeviceDefault.Light.ButtonBar</item>
+ <item name="segmentedButtonStyle">@style/DeviceDefault.Light.SegmentedButton</item>
<item name="searchDialogTheme">@style/Theme.DeviceDefault.Light.SearchBar</item>
@@ -373,216 +453,117 @@
<item name="timePickerStyle">@style/Widget.DeviceDefault.Light.TimePicker</item>
<!-- TimePicker Header time label text appearance -->
- <item name="timePickerHeaderTimeLabelTextAppearance">@style/TextAppearance.DeviceDefault.Light.TimePicker.TimeLabel</item>
+ <item name="timePickerHeaderTimeLabelTextAppearance">@style/TextAppearance.DeviceDefault.TimePicker.TimeLabel</item>
<!-- TimePicker Header am pm label text appearance -->
- <item name="timePickerHeaderAmPmLabelTextAppearance">@style/TextAppearance.DeviceDefault.Light.TimePicker.AmPmLabel</item>
+ <item name="timePickerHeaderAmPmLabelTextAppearance">@style/TextAppearance.DeviceDefault.TimePicker.AmPmLabel</item>
<!-- TimePicker dialog theme -->
- <item name="timePickerDialogTheme">@android:style/Theme.DeviceDefault.Light.Dialog.TimePicker</item>
+ <item name="timePickerDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.TimePicker</item>
<!-- DatePicker style -->
<item name="datePickerStyle">@style/Widget.DeviceDefault.Light.DatePicker</item>
- <item name="mediaRouteButtonStyle">@android:style/Widget.DeviceDefault.Light.MediaRouteButton</item>
- </style>
- <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
- <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Quantum.Light.NoActionBar" >
- </style>
- <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
- This theme sets {@link android.R.attr#windowFullscreen} to true. -->
- <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Quantum.Light.NoActionBar.Fullscreen" >
- </style>
- <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
- and extending in to overscan region. This theme
- sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
- to true. -->
- <style name="Theme.DeviceDefault.Light.NoActionBar.Overscan"
- parent="Theme.Quantum.Light.NoActionBar.Overscan" >
- </style>
- <!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
- system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
- {@link android.R.attr#windowTranslucentNavigation} to true. -->
- <style name="Theme.DeviceDefault.Light.NoActionBar.TranslucentDecor"
- parent="Theme.Quantum.Light.NoActionBar.TranslucentDecor" >
- </style>
- <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
- floating (not fill the entire screen), and puts a frame around its contents. You can set this
- theme on an activity if you would like to make an activity that looks like a Dialog. -->
- <style name="Theme.DeviceDefault.Dialog" parent="Theme.Quantum.Dialog" >
- <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault</item>
- <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item>
-
- <item name="android:buttonBarStyle">@android:style/DeviceDefault.ButtonBar.AlertDialog</item>
- <item name="borderlessButtonStyle">@android:style/Widget.DeviceDefault.Button.Borderless.Small</item>
-
- <item name="textAppearance">@android:style/TextAppearance.DeviceDefault</item>
- <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Inverse</item>
- </style>
- <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
- regular dialog. -->
- <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Quantum.Dialog.MinWidth" >
-
- </style>
- <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
- <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Quantum.Dialog.NoActionBar" >
-
- </style>
- <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
- for a regular dialog. -->
- <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Quantum.Dialog.NoActionBar.MinWidth" >
-
+ <item name="mediaRouteButtonStyle">@style/Widget.DeviceDefault.Light.MediaRouteButton</item>
</style>
- <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
- <style name="Theme.DeviceDefault.Dialog.FixedSize">
- <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
- <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
- <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
- <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
- </style>
-
- <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
- <style name="Theme.DeviceDefault.Dialog.NoActionBar.FixedSize">
- <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
- <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
- <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
- <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
- </style>
-
- <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
- floating (not fill the entire screen), and puts a frame around its contents. You can set this
- theme on an activity if you would like to make an activity that looks like a Dialog.-->
- <style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Quantum.Light.Dialog" >
- <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault.Light</item>
- <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item>
-
- <item name="android:buttonBarStyle">@android:style/DeviceDefault.Light.ButtonBar.AlertDialog</item>
- <item name="borderlessButtonStyle">@android:style/Widget.DeviceDefault.Light.Button.Borderless.Small</item>
-
- <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Light</item>
- <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Light.Inverse</item>
- </style>
- <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
- regular dialog. -->
- <style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Quantum.Light.Dialog.MinWidth" >
-
- </style>
- <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
- <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Quantum.Light.Dialog.NoActionBar" >
-
- </style>
- <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
- width for a regular dialog. -->
- <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Quantum.Light.Dialog.NoActionBar.MinWidth" >
-
- </style>
-
- <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
- <style name="Theme.DeviceDefault.Light.Dialog.FixedSize">
- <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
- <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
- <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
- <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
- </style>
-
- <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
- <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.FixedSize">
- <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
- <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
- <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
- <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
- </style>
-
- <!-- DeviceDefault theme for a window that will be displayed either full-screen on smaller
- screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
- <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Quantum.DialogWhenLarge" >
-
- </style>
- <!-- DeviceDefault theme for a window without an action bar that will be displayed either
- full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
- xlarge). -->
- <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Quantum.DialogWhenLarge.NoActionBar" >
-
- </style>
- <!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller
- screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
- <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Quantum.Light.DialogWhenLarge" >
-
- </style>
- <!-- DeviceDefault light theme for a window without an action bar that will be displayed either
- full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
- xlarge). -->
- <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Quantum.Light.DialogWhenLarge.NoActionBar" >
-
- </style>
-
- <!-- DeviceDefault theme for a presentation window on a secondary display. -->
- <style name="Theme.DeviceDefault.Dialog.Presentation" parent="Theme.Quantum.Dialog.Presentation">
- </style>
-
- <!-- DeviceDefault light theme for a presentation window on a secondary display. -->
- <style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="Theme.Quantum.Light.Dialog.Presentation">
- </style>
-
- <!-- DeviceDefault theme for panel windows. This removes all extraneous window
- decorations, so you basically have an empty rectangle in which to place your content. It makes
- the window floating, with a transparent background, and turns off dimming behind the window. -->
- <style name="Theme.DeviceDefault.Panel" parent="Theme.Quantum.Panel" >
-
- </style>
- <!-- DeviceDefault light theme for panel windows. This removes all extraneous window
- decorations, so you basically have an empty rectangle in which to place your content. It makes
- the window floating, with a transparent background, and turns off dimming behind the window. -->
- <style name="Theme.DeviceDefault.Light.Panel" parent="Theme.Quantum.Light.Panel" >
-
- </style>
- <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
- behind them. -->
- <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Quantum.Wallpaper" >
-
- </style>
- <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
- behind them and without an action bar. -->
- <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Quantum.Wallpaper.NoTitleBar" >
-
- </style>
- <!-- DeviceDefault style for input methods, which is used by the
- {@link android.inputmethodservice.InputMethodService} class.-->
- <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Quantum.InputMethod" >
-
- </style>
<!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
inverse color profile. -->
<style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Quantum.Light.DarkActionBar" >
- <item name="android:actionBarStyle">@android:style/Widget.DeviceDefault.Light.ActionBar.Solid.Inverse</item>
-
- <item name="actionDropDownStyle">@android:style/Widget.DeviceDefault.Spinner.DropDown.ActionBar</item>
- <item name="actionButtonStyle">@android:style/Widget.DeviceDefault.ActionButton</item>
- <item name="actionOverflowButtonStyle">@android:style/Widget.DeviceDefault.ActionButton.Overflow</item>
+ <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">@android:style/Widget.DeviceDefault.PopupWindow.ActionMode</item>
-
+ <item name="actionModePopupWindowStyle">@style/Widget.DeviceDefault.PopupWindow.ActionMode</item>
</style>
- <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Quantum.Dialog.Alert">
- <item name="windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault</item>
+ <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
+ <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Quantum.Light.NoActionBar" />
+
+ <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
+ This theme sets {@link android.R.attr#windowFullscreen} to true. -->
+ <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Quantum.Light.NoActionBar.Fullscreen" />
+
+ <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
+ and extending in to overscan region. This theme
+ sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
+ to true. -->
+ <style name="Theme.DeviceDefault.Light.NoActionBar.Overscan" parent="Theme.Quantum.Light.NoActionBar.Overscan" />
+
+ <!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
+ system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
+ {@link android.R.attr#windowTranslucentNavigation} to true. -->
+ <style name="Theme.DeviceDefault.Light.NoActionBar.TranslucentDecor" parent="Theme.Quantum.Light.NoActionBar.TranslucentDecor" />
+
+ <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
+ floating (not fill the entire screen), and puts a frame around its contents. You can set this
+ theme on an activity if you would like to make an activity that looks like a Dialog.-->
+ <style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Quantum.Light.Dialog" >
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
+ <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+
+ <item name="buttonBarStyle">@style/DeviceDefault.Light.ButtonBar.AlertDialog</item>
+ <item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Light.Button.Borderless.Small</item>
+
+ <item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
+ <item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
</style>
+
+ <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
+ regular dialog. -->
+ <style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Quantum.Light.Dialog.MinWidth" />
+
+ <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
+ <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Quantum.Light.Dialog.NoActionBar" />
+
+ <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
+ width for a regular dialog. -->
+ <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Quantum.Light.Dialog.NoActionBar.MinWidth" />
+
+ <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
+ <style name="Theme.DeviceDefault.Light.Dialog.FixedSize">
+ <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+ </style>
+
+ <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
+ <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.FixedSize">
+ <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+ </style>
+
+ <!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller
+ screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
+ <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Quantum.Light.DialogWhenLarge" />
+
+ <!-- DeviceDefault light theme for a window without an action bar that will be displayed either
+ full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
+ xlarge). -->
+ <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Quantum.Light.DialogWhenLarge.NoActionBar" />
+
+ <!-- DeviceDefault light theme for a presentation window on a secondary display. -->
+ <style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="Theme.Quantum.Light.Dialog.Presentation" />
+
+ <style name="Theme.DeviceDefault.Light.Dialog.TimePicker" parent="Theme.Quantum.Light.Dialog.TimePicker"/>
+
+ <!-- DeviceDefault light theme for panel windows. This removes all extraneous window
+ decorations, so you basically have an empty rectangle in which to place your content. It makes
+ the window floating, with a transparent background, and turns off dimming behind the window. -->
+ <style name="Theme.DeviceDefault.Light.Panel" parent="Theme.Quantum.Light.Panel" />
+
<style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Quantum.Light.Dialog.Alert">
- <item name="windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault.Light</item>
- </style>
- <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Quantum.SearchBar">
-
- </style>
- <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Quantum.Light.SearchBar">
-
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
</style>
- <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Quantum.Dialog.NoFrame">
- </style>
+ <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Quantum.Light.SearchBar" />
</resources>
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index f51b8df..39df700 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -15,20 +15,51 @@
-->
<resources>
<style name="Theme.Micro" parent="Theme.Holo.NoActionBar">
- <item name="textViewStyle">@android:style/Widget.Micro.TextView</item>
- <item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
- <item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item>
+ <item name="alertDialogTheme">@style/Theme.Micro.Dialog.Alert</item>
+ <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
+ <item name="dialogTheme">@style/Theme.Micro.Dialog</item>
+ <item name="textViewStyle">@style/Widget.Micro.TextView</item>
+
+ <item name="numberPickerStyle">@style/Widget.Micro.NumberPicker</item>
+ <item name="windowAnimationStyle">@style/Animation.SwipeDismiss</item>
<item name="windowIsFloating">false</item>
<item name="windowIsTranslucent">true</item>
<item name="windowSwipeToDismiss">true</item>
</style>
<style name="Theme.Micro.Light" parent="Theme.Holo.Light.NoActionBar">
- <item name="textViewStyle">@android:style/Widget.Micro.TextView</item>
- <item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
- <item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item>
+ <item name="alertDialogTheme">@style/Theme.Micro.Dialog.Alert</item>
+ <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
+ <item name="dialogTheme">@style/Theme.Micro.Dialog</item>
+ <item name="textViewStyle">@style/Widget.Micro.TextView</item>
+ <item name="numberPickerStyle">@style/Widget.Micro.NumberPicker</item>
+ <item name="windowAnimationStyle">@style/Animation.SwipeDismiss</item>
<item name="windowIsFloating">false</item>
<item name="windowIsTranslucent">true</item>
<item name="windowSwipeToDismiss">true</item>
</style>
+
+ <style name="Theme.Micro.Dialog" parent="Theme.Holo.Light.Dialog">
+ <item name="windowTitleStyle">@android:style/DialogWindowTitle.Micro</item>
+ <item name="windowIsFloating">false</item>
+ <item name="windowFullscreen">true</item>
+ <item name="textAppearance">@style/TextAppearance.Micro</item>
+ <item name="textAppearanceInverse">@style/TextAppearance.Micro</item>
+ </style>
+
+ <style name="Theme.Micro.Dialog.Alert" parent="Theme.Holo.Light.Dialog.Alert">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Micro</item>
+ <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
+ <item name="windowIsFloating">false</item>
+ </style>
+
+ <style name="Theme.Micro.Dialog.AppError" parent="Theme.Micro.Dialog">
+ <item name="windowBackground">@null</item>
+ <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
+ <item name="windowOverscan">true</item>
+ <item name="windowCloseOnTouchOutside">false</item>
+ <item name="textSize">20sp</item>
+ <item name="fontFamily">sans-serif-condensed-light</item>
+ <item name="textColor">@color/micro_text_light</item>
+ </style>
</resources>
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index 9f76eae..768fd9a 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -123,7 +123,7 @@
<item name="listSeparatorTextViewStyle">@style/Widget.Quantum.TextView.ListSeparator</item>
<item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum</item>
- <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum_anim</item>
+ <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum</item>
<item name="listChoiceBackgroundIndicator">@drawable/list_selector_quantum</item>
@@ -291,6 +291,7 @@
<item name="actionDropDownStyle">@style/Widget.Quantum.Spinner.DropDown.ActionBar</item>
<item name="actionButtonStyle">@style/Widget.Quantum.ActionButton</item>
<item name="actionOverflowButtonStyle">@style/Widget.Quantum.ActionButton.Overflow</item>
+ <item name="actionOverflowMenuStyle">@android:style/Widget.Quantum.PopupMenu.Overflow</item>
<item name="actionModeBackground">?attr/colorPrimaryDark</item>
<item name="actionModeSplitBackground">?attr/colorPrimaryDark</item>
<item name="actionModeCloseDrawable">@drawable/ic_cab_done_quantum</item>
@@ -391,8 +392,8 @@
<item name="backgroundDimAmount">0.6</item>
<!-- Text styles -->
- <item name="textAppearance">@style/TextAppearance.Quantum.Light</item>
- <item name="textAppearanceInverse">@style/TextAppearance.Quantum.Light.Inverse</item>
+ <item name="textAppearance">@style/TextAppearance.Quantum</item>
+ <item name="textAppearanceInverse">@style/TextAppearance.Quantum.Inverse</item>
<item name="textColorPrimary">@color/primary_text_quantum_light</item>
<item name="textColorPrimaryInverse">@color/primary_text_quantum_dark</item>
@@ -411,16 +412,16 @@
<item name="textColorSearchUrl">@color/search_url_text_quantum_light</item>
<item name="textColorAlertDialogListItem">@color/primary_text_quantum_light</item>
- <item name="textAppearanceLarge">@style/TextAppearance.Quantum.Light.Large</item>
- <item name="textAppearanceLargeInverse">@style/TextAppearance.Quantum.Light.Large.Inverse</item>
- <item name="textAppearanceMedium">@style/TextAppearance.Quantum.Light.Medium</item>
- <item name="textAppearanceMediumInverse">@style/TextAppearance.Quantum.Light.Medium.Inverse</item>
- <item name="textAppearanceSmall">@style/TextAppearance.Quantum.Light.Small</item>
- <item name="textAppearanceSmallInverse">@style/TextAppearance.Quantum.Light.Small.Inverse</item>
- <item name="textAppearanceSearchResultTitle">@style/TextAppearance.Quantum.Light.SearchResult.Title</item>
- <item name="textAppearanceSearchResultSubtitle">@style/TextAppearance.Quantum.Light.SearchResult.Subtitle</item>
+ <item name="textAppearanceLarge">@style/TextAppearance.Quantum.Large</item>
+ <item name="textAppearanceLargeInverse">@style/TextAppearance.Quantum.Large.Inverse</item>
+ <item name="textAppearanceMedium">@style/TextAppearance.Quantum.Medium</item>
+ <item name="textAppearanceMediumInverse">@style/TextAppearance.Quantum.Medium.Inverse</item>
+ <item name="textAppearanceSmall">@style/TextAppearance.Quantum.Small</item>
+ <item name="textAppearanceSmallInverse">@style/TextAppearance.Quantum.Small.Inverse</item>
+ <item name="textAppearanceSearchResultTitle">@style/TextAppearance.Quantum.SearchResult.Title</item>
+ <item name="textAppearanceSearchResultSubtitle">@style/TextAppearance.Quantum.SearchResult.Subtitle</item>
- <item name="textAppearanceButton">@style/TextAppearance.Quantum.Light.Widget.Button</item>
+ <item name="textAppearanceButton">@style/TextAppearance.Quantum.Widget.Button</item>
<item name="editTextColor">?attr/textColorPrimary</item>
<item name="editTextBackground">@drawable/edit_text_quantum</item>
@@ -430,8 +431,8 @@
<item name="textCheckMark">@drawable/indicator_check_mark_light</item>
<item name="textCheckMarkInverse">@drawable/indicator_check_mark_dark</item>
- <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Quantum.Light.Widget.PopupMenu.Large</item>
- <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Quantum.Light.Widget.PopupMenu.Small</item>
+ <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Quantum.Widget.PopupMenu.Large</item>
+ <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Quantum.Widget.PopupMenu.Small</item>
<!-- Button styles -->
<item name="buttonStyle">@style/Widget.Quantum.Light.Button</item>
@@ -466,7 +467,7 @@
<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_anim</item>
+ <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum</item>
<item name="listChoiceBackgroundIndicator">@drawable/list_selector_quantum</item>
@@ -606,7 +607,7 @@
<item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Quantum.QuickContactBadgeSmall.WindowLarge</item>
<item name="listPopupWindowStyle">@style/Widget.Quantum.Light.ListPopupWindow</item>
<item name="popupMenuStyle">@style/Widget.Quantum.Light.PopupMenu</item>
- <item name="stackViewStyle">@style/Widget.Quantum.StackView</item>
+ <item name="stackViewStyle">@style/Widget.Quantum.Light.StackView</item>
<item name="activityChooserViewStyle">@style/Widget.Quantum.Light.ActivityChooserView</item>
<item name="fragmentBreadCrumbsStyle">@style/Widget.Quantum.Light.FragmentBreadCrumbs</item>
@@ -636,6 +637,7 @@
<item name="actionDropDownStyle">@style/Widget.Quantum.Light.Spinner.DropDown.ActionBar</item>
<item name="actionButtonStyle">@style/Widget.Quantum.Light.ActionButton</item>
<item name="actionOverflowButtonStyle">@style/Widget.Quantum.Light.ActionButton.Overflow</item>
+ <item name="actionOverflowMenuStyle">@android:style/Widget.Quantum.Light.PopupMenu.Overflow</item>
<item name="actionModeBackground">@drawable/cab_background_top_holo_light</item>
<item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item>
<item name="actionModeCloseDrawable">@drawable/ic_cab_done_quantum</item>
@@ -690,10 +692,10 @@
<item name="timePickerHeaderBackgroundColor">?attr/colorBackground</item>
<!-- TimePicker Header time label text appearance -->
- <item name="timePickerHeaderTimeLabelTextAppearance">@style/TextAppearance.Quantum.Light.TimePicker.TimeLabel</item>
+ <item name="timePickerHeaderTimeLabelTextAppearance">@style/TextAppearance.Quantum.TimePicker.TimeLabel</item>
<!-- TimePicker Header am pm label text appearance -->
- <item name="timePickerHeaderAmPmLabelTextAppearance">@style/TextAppearance.Quantum.Light.TimePicker.AmPmLabel</item>
+ <item name="timePickerHeaderAmPmLabelTextAppearance">@style/TextAppearance.Quantum.TimePicker.AmPmLabel</item>
<!-- TimePicker dialog theme -->
<item name="timePickerDialogTheme">@style/Theme.Quantum.Light.Dialog.TimePicker</item>
@@ -717,9 +719,6 @@
<item name="colorControlActivated">?attr/colorPrimary</item>
<item name="colorButtonNormal">@color/quantum_grey_100</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/colorPrimaryDark</item>
</style>
<style name="ThemeOverlay" />
@@ -856,6 +855,14 @@
<item name="imeExtractExitAnimation">@anim/input_method_extract_exit</item>
</style>
+ <!-- Default theme for quantum style voice interaction, which is used by the
+ {@link android.service.voice.VoiceInteractionSession} class.
+ this inherits from Theme.Panel, but sets up appropriate animations
+ and a few custom attributes. -->
+ <style name="Theme.Quantum.VoiceInteractionSession" parent="Theme.Quantum.Light.Panel">
+ <item name="android:windowAnimationStyle">@android:style/Animation.VoiceInteractionSession</item>
+ </style>
+
<!-- Theme for the search input bar. -->
<style name="Theme.Quantum.SearchBar" parent="Theme.Quantum.Panel">
@@ -1031,8 +1038,8 @@
<item name="buttonBarStyle">@style/Widget.Quantum.Light.ButtonBar.AlertDialog</item>
<item name="borderlessButtonStyle">@style/Widget.Quantum.Light.Button.Borderless.Small</item>
- <item name="textAppearance">@style/TextAppearance.Quantum.Light</item>
- <item name="textAppearanceInverse">@style/TextAppearance.Quantum.Light.Inverse</item>
+ <item name="textAppearance">@style/TextAppearance.Quantum</item>
+ <item name="textAppearanceInverse">@style/TextAppearance.Quantum.Inverse</item>
<item name="listPreferredItemPaddingLeft">16dip</item>
<item name="listPreferredItemPaddingRight">16dip</item>
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
index 0cd19f2..67203b2 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
@@ -64,6 +64,8 @@
unpairAll();
} else if ("getName".equals(command)) {
getName();
+ } else if ("getAddress".equals(command)) {
+ getAddress();
} else {
finish(null);
}
@@ -90,6 +92,12 @@
finish(mSuccessResult);
}
+ public void getAddress() {
+ String name = getBluetoothAdapter().getAddress();
+ mSuccessResult.putString("address", name);
+ finish(mSuccessResult);
+ }
+
public void finish(Bundle result) {
if (result == null) {
result = new Bundle();
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java
new file mode 100644
index 0000000..0f3ea0e
--- /dev/null
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java
@@ -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 android.bluetooth;
+
+import android.os.ParcelUuid;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test cases for {@link BluetoothUuid}.
+ * <p>
+ * To run this test, use adb shell am instrument -e class 'android.bluetooth.BluetoothUuidTest' -w
+ * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
+ */
+public class BluetoothUuidTest extends TestCase {
+
+ @SmallTest
+ public void testUuidParser() {
+ byte[] uuid16 = new byte[] {
+ 0x0B, 0x11 };
+ assertEquals(ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"),
+ BluetoothUuid.parseUuidFrom(uuid16));
+
+ byte[] uuid32 = new byte[] {
+ 0x0B, 0x11, 0x33, (byte) 0xFE };
+ assertEquals(ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB"),
+ BluetoothUuid.parseUuidFrom(uuid32));
+
+ byte[] uuid128 = new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, (byte) 0xFF };
+ assertEquals(ParcelUuid.fromString("FF0F0E0D-0C0B-0A09-0807-0060504030201"),
+ BluetoothUuid.parseUuidFrom(uuid128));
+ }
+}
diff --git a/core/tests/coretests/res/anim/reset_state_anim.xml b/core/tests/coretests/res/anim/reset_state_anim.xml
new file mode 100644
index 0000000..918d0a3
--- /dev/null
+++ b/core/tests/coretests/res/anim/reset_state_anim.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+ <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+ <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+</set>
\ No newline at end of file
diff --git a/core/tests/coretests/res/anim/test_state_anim.xml b/core/tests/coretests/res/anim/test_state_anim.xml
new file mode 100644
index 0000000..9e08f68
--- /dev/null
+++ b/core/tests/coretests/res/anim/test_state_anim.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true">
+ <set>
+ <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="10" android:valueType="floatType"/>
+ <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="20" android:valueType="floatType"/>
+ <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="20" android:valueType="floatType"/>
+ </set>
+ </item>
+ <item android:state_enabled="true" android:state_pressed="false">
+ <set>
+ <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+ <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+ <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+ </set>
+ </item>
+ <!-- base state-->
+ <item android:animation="@anim/reset_state_anim"/>
+</selector>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/animation/StateListAnimatorTest.java b/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
new file mode 100644
index 0000000..38df78d
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/StateListAnimatorTest.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 android.animation;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.util.StateSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.frameworks.coretests.R;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+public class StateListAnimatorTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
+
+ public StateListAnimatorTest() {
+ super(BasicAnimatorActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ public void testInflateFromAnimator() throws Exception {
+ StateListAnimator stateListAnimator = AnimatorInflater
+ .loadStateListAnimator(getActivity(), R.anim.test_state_anim);
+ assertNotNull("A state list animator should be returned", stateListAnimator);
+ assertEquals("State list animator should have three items", 3,
+ stateListAnimator.getTuples().size());
+ }
+
+ @UiThreadTest
+ public void testAttachDetach() throws Exception {
+ View view = new View(getActivity());
+ final AtomicInteger setStateCount = new AtomicInteger(0);
+ StateListAnimator stateListAnimator = new StateListAnimator() {
+ @Override
+ public void setState(int[] state) {
+ setStateCount.incrementAndGet();
+ super.setState(state);
+ }
+ };
+ view.setStateListAnimator(stateListAnimator);
+ assertNotNull("State list animator should have a reference to view even if it is detached",
+ stateListAnimator.getTarget());
+ ViewGroup viewGroup = (ViewGroup) getActivity().findViewById(android.R.id.content);
+ int preSetStateCount = setStateCount.get();
+ viewGroup.addView(view);
+ assertTrue("When view is attached, state list drawable's setState should be called",
+ preSetStateCount < setStateCount.get());
+
+ StateListAnimator stateListAnimator2 = new StateListAnimator();
+ view.setStateListAnimator(stateListAnimator2);
+ assertNull("When a new state list animator is assigned, previous one should be detached",
+ stateListAnimator.getTarget());
+ assertNull("Any running animator should be removed on detach",
+ stateListAnimator.getRunningAnimator());
+ assertEquals("The new state list animator should be attached to the view",
+ view, stateListAnimator2.getTarget());
+ viewGroup.removeView(view);
+ assertNotNull("When view is detached from window, state list animator should still keep the"
+ + " reference",
+ stateListAnimator2.getTarget());
+ }
+
+ public void testStateListLoading() throws InterruptedException {
+ StateListAnimator stateListAnimator = AnimatorInflater
+ .loadStateListAnimator(getActivity(), R.anim.test_state_anim);
+ assertNotNull("A state list animator should be returned", stateListAnimator);
+ assertEquals("Steate list animator should have two items", 3,
+ stateListAnimator.getTuples().size());
+ StateListAnimator.Tuple tuple1 = stateListAnimator.getTuples().get(0);
+ assertEquals("first tuple should have one state", 1, tuple1.getSpecs().length);
+ assertEquals("first spec in tuple 1 should be pressed",
+ com.android.internal.R.attr.state_pressed, tuple1.getSpecs()[0]);
+
+ StateListAnimator.Tuple tuple2 = stateListAnimator.getTuples().get(1);
+ assertEquals("Second tuple should have two specs", 2, tuple2.getSpecs().length);
+ assertTrue("Tuple two should match the expected state",
+ StateSet.stateSetMatches(tuple2.getSpecs(),
+ new int[]{-com.android.internal.R.attr.state_pressed,
+ com.android.internal.R.attr.state_enabled}));
+ }
+}
diff --git a/core/tests/coretests/src/android/net/RssiCurveTest.java b/core/tests/coretests/src/android/net/RssiCurveTest.java
new file mode 100644
index 0000000..d4438df
--- /dev/null
+++ b/core/tests/coretests/src/android/net/RssiCurveTest.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 android.net;
+
+import junit.framework.TestCase;
+
+public class RssiCurveTest extends TestCase {
+ public void testLookupScore_constantCurve() {
+ RssiCurve curve = new RssiCurve(-100, 200, new byte[] { 10 });
+ assertEquals(10, curve.lookupScore(-200));
+ assertEquals(10, curve.lookupScore(-100));
+ assertEquals(10, curve.lookupScore(0));
+ assertEquals(10, curve.lookupScore(100));
+ assertEquals(10, curve.lookupScore(200));
+ }
+
+ public void testLookupScore_changingCurve() {
+ RssiCurve curve = new RssiCurve(-100, 100, new byte[] { -10, 10 });
+ assertEquals(-10, curve.lookupScore(-200));
+ assertEquals(-10, curve.lookupScore(-100));
+ assertEquals(-10, curve.lookupScore(-50));
+ assertEquals(10, curve.lookupScore(0));
+ assertEquals(10, curve.lookupScore(50));
+ assertEquals(10, curve.lookupScore(100));
+ assertEquals(10, curve.lookupScore(200));
+ }
+}
diff --git a/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java
index 6d33529..23b6780 100644
--- a/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java
+++ b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java
@@ -73,7 +73,6 @@
DUMMY_FORCE_DEFAULT, supportsSwitchingToNextInputMethod);
for (int i = 0; i < subtypes.size(); ++i) {
final String subtypeLocale = subtypeLocales.get(i);
- final InputMethodSubtype subtype = subtypes.get(i);
items.add(new ImeSubtypeListItem(imeName, subtypeLocale, imi, i, subtypeLocale,
SYSTEM_LOCALE));
}
@@ -116,36 +115,37 @@
imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
currentIme.mSubtypeName.toString()));
assertEquals(imList.get(2), nextIme);
- // "switchAwareLatinIme/fr" -> "nonSwitchAwareLatinIme/en_UK
+ // "switchAwareLatinIme/fr" -> "switchAwareJapaneseIme/ja_JP"
currentIme = imList.get(2);
nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
currentIme.mSubtypeName.toString()));
- assertEquals(imList.get(3), nextIme);
+ assertEquals(imList.get(5), nextIme);
+ // "switchAwareJapaneseIme/ja_JP" -> "switchAwareLatinIme/en_US"
+ currentIme = imList.get(5);
+ nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+ imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
+ currentIme.mSubtypeName.toString()));
+ assertEquals(imList.get(0), nextIme);
+
// "nonSwitchAwareLatinIme/en_UK" -> "nonSwitchAwareLatinIme/hi"
currentIme = imList.get(3);
nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
currentIme.mSubtypeName.toString()));
assertEquals(imList.get(4), nextIme);
- // "nonSwitchAwareLatinIme/hi" -> "switchAwareJapaneseIme/ja_JP"
+ // "nonSwitchAwareLatinIme/hi" -> "nonSwitchAwareJapaneseIme/ja_JP"
currentIme = imList.get(4);
nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
currentIme.mSubtypeName.toString()));
- assertEquals(imList.get(5), nextIme);
- // "switchAwareJapaneseIme/ja_JP" -> "nonSwitchAwareJapaneseIme/ja_JP"
- currentIme = imList.get(5);
- nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
- imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
- currentIme.mSubtypeName.toString()));
assertEquals(imList.get(6), nextIme);
- // "nonSwitchAwareJapaneseIme/ja_JP" -> "switchAwareLatinIme/en_US"
+ // "nonSwitchAwareJapaneseIme/ja_JP" -> "nonSwitchAwareLatinIme/en_UK"
currentIme = imList.get(6);
nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
currentIme.mSubtypeName.toString()));
- assertEquals(imList.get(0), nextIme);
+ assertEquals(imList.get(3), nextIme);
}
@SmallTest
diff --git a/data/keyboards/Generic.kcm b/data/keyboards/Generic.kcm
index 01d22ee..1ef74ba 100644
--- a/data/keyboards/Generic.kcm
+++ b/data/keyboards/Generic.kcm
@@ -492,11 +492,11 @@
}
key BUTTON_X {
- base: fallback DPAD_CENTER
+ base: fallback DEL
}
key BUTTON_Y {
- base: fallback BACK
+ base: fallback SPACE
}
key BUTTON_Z {
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 56423c9..cfc1484 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -404,6 +404,8 @@
# key 503 KEY_BRL_DOT7
# key 504 KEY_BRL_DOT8
+key 580 APP_SWITCH
+
# Keys defined by HID usages
key usage 0x0c006F BRIGHTNESS_UP
key usage 0x0c0070 BRIGHTNESS_DOWN
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 92ecd24..bddb8ec 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -61,7 +61,7 @@
</div>
-<p style="clear:both"><em>Data collected during a 7-day period ending on April 1, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on May 1, 2014.
<br/>Any versions with less than 0.1% distribution are not shown.</em>
</p>
@@ -92,7 +92,7 @@
</div>
-<p style="clear:both"><em>Data collected during a 7-day period ending on April 1, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on May 1, 2014.
<br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
@@ -111,7 +111,7 @@
<img alt="" style="float:right"
-src="//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" />
+src="//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A0.1%2C87.0%2C12.9&chf=bg%2Cs%2C00000000&chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chco=c4df9b%2C6fad0c" />
<p>To declare which version of OpenGL ES your application requires, you should use the {@code
android:glEsVersion} attribute of the <a
@@ -133,17 +133,17 @@
</tr>
<tr>
<td>2.0</th>
-<td>89.4%</td>
+<td>87.0%</td>
</tr>
<tr>
<td>3.0</th>
-<td>10.5%</td>
+<td>12.9%</td>
</tr>
</table>
-<p style="clear:both"><em>Data collected during a 7-day period ending on April 1, 2014</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on May 1, 2014</em></p>
@@ -161,17 +161,17 @@
var VERSION_DATA =
[
{
- "chart": "//chart.googleapis.com/chart?cht=p&chs=500x250&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A1.1%2C17.8%2C0.1%2C14.3%2C61.4%2C5.3&chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat",
+ "chart": "//chart.googleapis.com/chart?chs=500x250&cht=p&chd=t%3A1.0%2C16.2%2C0.1%2C13.4%2C60.8%2C8.5&chf=bg%2Cs%2C00000000&chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chco=c4df9b%2C6fad0c",
"data": [
{
"api": 8,
"name": "Froyo",
- "perc": "1.1"
+ "perc": "1.0"
},
{
"api": 10,
"name": "Gingerbread",
- "perc": "17.8"
+ "perc": "16.2"
},
{
"api": 13,
@@ -181,27 +181,27 @@
{
"api": 15,
"name": "Ice Cream Sandwich",
- "perc": "14.3"
+ "perc": "13.4"
},
{
"api": 16,
"name": "Jelly Bean",
- "perc": "34.4"
+ "perc": "33.5"
},
{
"api": 17,
"name": "Jelly Bean",
- "perc": "18.1"
+ "perc": "18.8"
},
{
"api": 18,
"name": "Jelly Bean",
- "perc": "8.9"
+ "perc": "8.5"
},
{
"api": 19,
"name": "KitKat",
- "perc": "5.3"
+ "perc": "8.5"
}
]
}
@@ -217,19 +217,19 @@
"data": {
"Large": {
"hdpi": "0.6",
- "ldpi": "0.7",
+ "ldpi": "0.6",
"mdpi": "4.4",
- "tvdpi": "1.5",
+ "tvdpi": "1.6",
"xhdpi": "0.6"
},
"Normal": {
- "hdpi": "33.7",
- "mdpi": "13.2",
- "xhdpi": "19.8",
- "xxhdpi": "12.5"
+ "hdpi": "33.9",
+ "mdpi": "12.5",
+ "xhdpi": "19.9",
+ "xxhdpi": "13.5"
},
"Small": {
- "ldpi": "8.1"
+ "ldpi": "7.5"
},
"Xlarge": {
"hdpi": "0.3",
@@ -238,8 +238,8 @@
"xhdpi": "0.3"
}
},
- "densitychart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A8.9%2C21.8%2C1.5%2C34.6%2C20.7%2C12.6&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi",
- "layoutchart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A4.9%2C7.8%2C79.3%2C8.1&chl=Xlarge%7CLarge%7CNormal%7CSmall"
+ "densitychart": "//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A8.2%2C21.1%2C1.6%2C34.8%2C20.8%2C13.5&chf=bg%2Cs%2C00000000&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chco=c4df9b%2C6fad0c",
+ "layoutchart": "//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A4.9%2C7.8%2C80.0%2C7.5&chf=bg%2Cs%2C00000000&chl=Xlarge%7CLarge%7CNormal%7CSmall&chco=c4df9b%2C6fad0c"
}
];
diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
index a0f7ce1..b4813a5 100644
--- a/docs/html/guide/components/intents-common.jd
+++ b/docs/html/guide/components/intents-common.jd
@@ -737,7 +737,7 @@
<pre>
public void editContact(Uri contactUri, String email) {
Intent intent = new Intent(Intent.ACTION_EDIT);
- intent.setDataAndType(contactUri, Contacts.CONTENT_TYPE);
+ intent.setData(contactUri);
intent.putExtra(Intents.Insert.EMAIL, email);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
diff --git a/docs/html/tools/device.jd b/docs/html/tools/device.jd
index ccd5903..e9caa44 100644
--- a/docs/html/tools/device.jd
+++ b/docs/html/tools/device.jd
@@ -192,6 +192,10 @@
<td><code>12d1</code></td>
</tr>
<tr>
+ <td>Intel</td>
+ <td><code>8087</code></td>
+ </tr>
+ <tr>
<td>K-Touch</td>
<td><code>24e3</code></td>
</tr>
diff --git a/docs/html/wear/images/11_bundles_A.png b/docs/html/wear/images/11_bundles_A.png
index 0ffc6ec..7199a1f 100644
--- a/docs/html/wear/images/11_bundles_A.png
+++ b/docs/html/wear/images/11_bundles_A.png
Binary files differ
diff --git a/docs/html/wear/images/11_bundles_B.png b/docs/html/wear/images/11_bundles_B.png
index c188d3d..bb751a2 100644
--- a/docs/html/wear/images/11_bundles_B.png
+++ b/docs/html/wear/images/11_bundles_B.png
Binary files differ
diff --git a/docs/html/wear/images/11_bundles_C.png b/docs/html/wear/images/11_bundles_C.png
deleted file mode 100644
index de71c59..0000000
--- a/docs/html/wear/images/11_bundles_C.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/wear/notifications/stacks.jd b/docs/html/wear/notifications/stacks.jd
index e723dab..7f955f6 100644
--- a/docs/html/wear/notifications/stacks.jd
+++ b/docs/html/wear/notifications/stacks.jd
@@ -2,8 +2,7 @@
@jd:body
-<img src="{@docRoot}wear/images/11_bundles_C.png" height="154" width="273" style="float:right;margin:0 0 20px 40px"/>
-<img src="{@docRoot}wear/images/11_bundles_B.png" height="200" width="169" style="clear:both;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" />
<img src="{@docRoot}wear/images/11_bundles_A.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" />
<p>When creating notifications for a handheld device, you should always aggregate similar
@@ -11,7 +10,7 @@
for received messages, you should not show more than one notification
on a handheld device—when more than one is message is received, use a single notification
to provide a summary such as "2 new messages."</p>
-<br />
+
<p>However, a summary notification is less useful on an Android wearable because users
are not able to read details from each message on the wearable (they must open your app on the
handheld to view more information). So for the wearable device, you should
@@ -26,50 +25,25 @@
Wear</a>.</p>
-<h2 id="AddGroup">Create notifications in stacks</h2>
-
-<div style="float:right">
- <script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
- <div style="width:440;height:246; padding-left:20px">
- <object type="application/x-shockwave-flash" id="ytapiplayer" data="//www.youtube.com/v/L4LvKOTkZ7Q?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1" width="440" height="246" style="visibility: visible;"><param name="allowScriptAccess" value="always"></object>
- <script type="text/javascript">
- var params = { allowScriptAccess: "always" };
- var atts = { id: "ytapiplayer" };
- swfobject.embedSWF("//www.youtube.com/v/L4LvKOTkZ7Q?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
- "ytapiplayer", "440", "246", "8", null, null, params, atts);
-
- // Callback used to pause/resume carousel based on video state
- function onytplayerStateChange(newState) {
- var isPaused = $("#pauseButton").hasClass("paused");
- if ((newState == 1) || (newState == 3)) {
- // if playing or buffering, pause the carousel
- if (!isPaused) {
- $("#pauseButton").click();
- }
- } else {
- // otherwise, make sure carousel is running
- if (isPaused) {
- $("#pauseButton").click();
- }
- }
- }
-
- // Callback received when YouTube player loads to setup callback (above)
- function onYouTubePlayerReady(playerId) {
- var ytplayer = document.getElementById("ytapiplayer");
- ytplayer.addEventListener("onStateChange", "onytplayerStateChange");
- }
-
- </script>
- </div>
-</div>
-
+<h2 id="AddGroup">Add Each Notification to a Group</h2>
<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.</p>
+group key. For example:</p>
+<pre style="clear:right">
+final static String GROUP_KEY_EMAILS = "group_key_emails";
+
+NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
+ .setContentTitle("New mail from " + sender)
+ .setContentText(subject)
+ .setSmallIcon(R.drawable.new_mail);
+
+Notification notif = new WearableNotifications.Builder(builder)
+ .setGroup(GROUP_KEY_EMAILS)
+ .build();
+</pre>
<p>By default, notifications appear in the order in which you added them, with the most recent
notification visible at the top. You can define a specific position in the group
@@ -78,82 +52,21 @@
<code>setGroup()</code></a>.</p>
-<p>It's also important that you still provide a summary notification that appears on handheld devices.
+<h2 id="AddSummary">Add a Summary Notification</h2>
+
+<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>
-<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>
-
-
-<p>Here's an example that creates a stack notification for a wearable and
-a summary notification for a handset device:</p>
-
-<pre style="clear:right">
-public void onClick_button_groups () {
- Bitmap bitmapMila = BitmapFactory.decodeResource(getResources(),
- R.drawable.mila128);
-
- // Nuke all previous notifications and generate unique ids
- NotificationManagerCompat.from(this).cancelAll();
- int notificationId = 0;
-
- // String to represent the group all the notifications will be a part of
- final String GROUP_KEY_EMAILS = "group_key_messages";
-
- // Group notification that will be visible on the phone
- NotificationCompat.Builder builderG = new NotificationCompat.Builder(this)
- .setContentTitle("2 Pet Notifications")
- .setContentText("Mila and Dylan both sent messages")
- .setSmallIcon(R.drawable.ic_launcher)
- .setLargeIcon(bitmapMila);
- Notification summaryNotification = new WearableNotifications
- .Builder(builderG)
- .setGroup(GROUP_KEY_EMAILS,
- WearableNotifications.GROUP_ORDER_SUMMARY)
- .build();
-
- // Separate notifications that will be visible on the watch
- Intent viewIntent1 = new Intent(this, MainActivity.class);
- PendingIntent viewPendingIntent1 =
- PendingIntent.getActivity(this, notificationId+1, viewIntent1, 0);
- NotificationCompat.Builder builder1 = new NotificationCompat.Builder(this)
- .addAction(R.drawable.ic_action_done, "Treat Fed",
- viewPendingIntent1)
- .setContentTitle("Message from Mila")
- .setContentText("What's for dinner? "
- + "Can we have steak?")
- .setSmallIcon(R.drawable.ic_launcher);
- Notification notification1 = new WearableNotifications.Builder(builder1)
- .setGroup(GROUP_KEY_EMAILS)
- .build();
-
- Intent viewIntent2 = new Intent(this, MainActivity.class);
- PendingIntent viewPendingIntent2 =
- PendingIntent.getActivity(this, notificationId+2, viewIntent2, 0);
- NotificationCompat.Builder builder2 = new NotificationCompat.Builder(this)
- .addAction(R.drawable.ic_action_done, "Water Filled",
- viewPendingIntent2)
- .setContentTitle("Message from Dylan")
- .setContentText("Can you refill our water bowl?")
- .setSmallIcon(R.drawable.ic_launcher);
- Notification notification2 = new WearableNotifications.Builder(builder2)
- .setGroup(GROUP_KEY_EMAILS)
- .build();
-
- // Issue the group notification
- NotificationManagerCompat notificationManager =
- NotificationManagerCompat.from(this);
- notificationManager.notify(notificationId+0, summaryNotification);
-
- // Issue the separate wear notifications
- notificationManager.notify(notificationId+2, notification2);
- notificationManager.notify(notificationId+1, notification1);
-}
+<pre>
+Notification summaryNotification = new WearableNotifications.Builder(builder)
+ .setGroup(GROUP_KEY_EMAILS, WearableNotifications.GROUP_ORDER_SUMMARY)
+ .build();
</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.
</body>
</html>
diff --git a/graphics/java/android/graphics/Camera.java b/graphics/java/android/graphics/Camera.java
index c263a84..a40085b 100644
--- a/graphics/java/android/graphics/Camera.java
+++ b/graphics/java/android/graphics/Camera.java
@@ -154,7 +154,7 @@
getMatrix(mMatrix);
canvas.concat(mMatrix);
} else {
- nativeApplyToCanvas(canvas.mNativeCanvas);
+ nativeApplyToCanvas(canvas.getNativeCanvas());
}
}
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index ae3eae1..5b18623 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -39,8 +39,12 @@
public class Canvas {
// assigned in constructors or setBitmap, freed in finalizer
+ private long mNativeCanvas;
+
/** @hide */
- public long mNativeCanvas;
+ public long getNativeCanvas() {
+ return mNativeCanvas;
+ }
// may be null
private Bitmap mBitmap;
diff --git a/graphics/java/android/graphics/CanvasProperty.java b/graphics/java/android/graphics/CanvasProperty.java
new file mode 100644
index 0000000..99ea9b1
--- /dev/null
+++ b/graphics/java/android/graphics/CanvasProperty.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;
+
+/**
+ * TODO: Make public?
+ * @hide
+ */
+public final class CanvasProperty<T> {
+ private long mNativeContainer;
+
+ public static CanvasProperty<Float> createFloat(float initialValue) {
+ return new CanvasProperty<Float>(nCreateFloat(initialValue));
+ }
+
+ public static CanvasProperty<Paint> createPaint(Paint initialValue) {
+ return new CanvasProperty<Paint>(nCreatePaint(initialValue.mNativePaint));
+ }
+
+ private CanvasProperty(long nativeContainer) {
+ mNativeContainer = nativeContainer;
+ }
+
+ /** @hide */
+ public long getNativeContainer() {
+ return mNativeContainer;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ nUnref(mNativeContainer);
+ mNativeContainer = 0;
+ } finally {
+ super.finalize();
+ }
+ }
+
+ 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/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index e08ed50..062acaf 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -253,4 +253,31 @@
}
return -1;
}
+
+ /**
+ * Determine whether or not this is a public-visible {@code format}.
+ *
+ * <p>In particular, {@code @hide} formats will return {@code false}.</p>
+ *
+ * <p>Any other formats (including UNKNOWN) will return {@code false}.</p>
+ *
+ * @param format an integer format
+ * @return a boolean
+ *
+ * @hide
+ */
+ public static boolean isPublicFormat(int format) {
+ switch (format) {
+ case RGB_565:
+ case NV16:
+ case YUY2:
+ case YV12:
+ case NV21:
+ case YUV_420_888:
+ case RAW_SENSOR:
+ return true;
+ }
+
+ return false;
+ }
}
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index 69089b1..6ff5f4f 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -164,12 +164,12 @@
}
void drawSoftware(Canvas canvas, RectF location, Paint paint) {
- nativeDraw(canvas.mNativeCanvas, location, mBitmap.ni(), mNativeChunk,
+ nativeDraw(canvas.getNativeCanvas(), location, mBitmap.ni(), mNativeChunk,
paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
}
void drawSoftware(Canvas canvas, Rect location, Paint paint) {
- nativeDraw(canvas.mNativeCanvas, location, mBitmap.ni(), mNativeChunk,
+ nativeDraw(canvas.getNativeCanvas(), location, mBitmap.ni(), mNativeChunk,
paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
}
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index 25188e0..a16c099 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -107,7 +107,7 @@
if (mRecordingCanvas != null) {
endRecording();
}
- nativeDraw(canvas.mNativeCanvas, mNativePicture);
+ nativeDraw(canvas.getNativeCanvas(), mNativePicture);
}
/**
diff --git a/graphics/java/android/graphics/PixelFormat.java b/graphics/java/android/graphics/PixelFormat.java
index d96d6d8..832b9c3 100644
--- a/graphics/java/android/graphics/PixelFormat.java
+++ b/graphics/java/android/graphics/PixelFormat.java
@@ -115,7 +115,7 @@
info.bytesPerPixel = 1;
break;
default:
- throw new IllegalArgumentException("unkonwon pixel format " + format);
+ throw new IllegalArgumentException("unknown pixel format " + format);
}
}
@@ -135,4 +135,29 @@
public int bytesPerPixel;
public int bitsPerPixel;
+
+ /**
+ * Determine whether or not this is a public-visible and non-deprecated {@code format}.
+ *
+ * <p>In particular, {@code @hide} formats will return {@code false}.</p>
+ *
+ * <p>Any other indirect formats (such as {@code TRANSPARENT} or {@code TRANSLUCENT})
+ * will return {@code false}.</p>
+ *
+ * @param format an integer format
+ * @return a boolean
+ *
+ * @hide
+ */
+ public static boolean isPublicFormat(int format) {
+ switch (format) {
+ case RGBA_8888:
+ case RGBX_8888:
+ case RGB_888:
+ case RGB_565:
+ return true;
+ }
+
+ return false;
+ }
}
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index d877502..3f8c45c 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -62,9 +62,8 @@
* #updateTexImage} should not be called directly from the callback.
*/
public class SurfaceTexture {
-
- private EventHandler mEventHandler;
- private OnFrameAvailableListener mOnFrameAvailableListener;
+ private final Looper mCreatorLooper;
+ private Handler mOnFrameAvailableHandler;
/**
* These fields are used by native code, do not access or modify.
@@ -83,7 +82,8 @@
/**
* Exception thrown when a SurfaceTexture couldn't be created or resized.
*
- * @deprecated No longer thrown. {@link Surface.OutOfResourcesException} is used instead.
+ * @deprecated No longer thrown. {@link android.view.Surface.OutOfResourcesException}
+ * is used instead.
*/
@SuppressWarnings("serial")
@Deprecated
@@ -100,10 +100,10 @@
*
* @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
*
- * @throws OutOfResourcesException If the SurfaceTexture cannot be created.
+ * @throws Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
*/
public SurfaceTexture(int texName) {
- init(texName, false);
+ this(texName, false);
}
/**
@@ -121,20 +121,58 @@
* @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
* @param singleBufferMode whether the SurfaceTexture will be in single buffered mode.
*
- * @throws throws OutOfResourcesException If the SurfaceTexture cannot be created.
+ * @throws Surface.OutOfResourcesException If the SurfaceTexture cannot be created.
*/
public SurfaceTexture(int texName, boolean singleBufferMode) {
- init(texName, singleBufferMode);
+ mCreatorLooper = Looper.myLooper();
+ nativeInit(texName, singleBufferMode, new WeakReference<SurfaceTexture>(this));
}
/**
* Register a callback to be invoked when a new image frame becomes available to the
- * SurfaceTexture. Note that this callback may be called on an arbitrary thread, so it is not
+ * SurfaceTexture.
+ * <p>
+ * This callback may be called on an arbitrary thread, so it is not
* safe to call {@link #updateTexImage} without first binding the OpenGL ES context to the
* thread invoking the callback.
+ * </p>
+ *
+ * @param listener The listener to set.
*/
- public void setOnFrameAvailableListener(OnFrameAvailableListener l) {
- mOnFrameAvailableListener = l;
+ public void setOnFrameAvailableListener(OnFrameAvailableListener listener) {
+ setOnFrameAvailableListener(listener, null);
+ }
+
+ /**
+ * Register a callback to be invoked when a new image frame becomes available to the
+ * SurfaceTexture.
+ * <p>
+ * If no handler is specified, then this callback may be called on an arbitrary thread,
+ * so it is not safe to call {@link #updateTexImage} without first binding the OpenGL ES
+ * context to the thread invoking the callback.
+ * </p>
+ *
+ * @param listener The listener to set.
+ * @param handler The handler on which the listener should be invoked, or null
+ * to use an arbitrary thread.
+ */
+ public void setOnFrameAvailableListener(final OnFrameAvailableListener listener,
+ Handler handler) {
+ if (listener != null) {
+ // Although we claim the thread is arbitrary, earlier implementation would
+ // prefer to send the callback on the creating looper or the main looper
+ // so we preserve this behavior here.
+ Looper looper = handler != null ? handler.getLooper() :
+ mCreatorLooper != null ? mCreatorLooper : Looper.getMainLooper();
+ mOnFrameAvailableHandler = new Handler(looper, null, true /*async*/) {
+ @Override
+ public void handleMessage(Message msg) {
+ listener.onFrameAvailable(SurfaceTexture.this);
+ }
+ };
+ } else {
+ mOnFrameAvailableHandler = null;
+ }
}
/**
@@ -285,49 +323,22 @@
}
}
- private class EventHandler extends Handler {
- public EventHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (mOnFrameAvailableListener != null) {
- mOnFrameAvailableListener.onFrameAvailable(SurfaceTexture.this);
- }
- }
- }
-
/**
* This method is invoked from native code only.
*/
@SuppressWarnings({"UnusedDeclaration"})
- private static void postEventFromNative(Object selfRef) {
- WeakReference weakSelf = (WeakReference)selfRef;
- SurfaceTexture st = (SurfaceTexture)weakSelf.get();
- if (st == null) {
- return;
- }
-
- if (st.mEventHandler != null) {
- Message m = st.mEventHandler.obtainMessage();
- st.mEventHandler.sendMessage(m);
+ private static void postEventFromNative(WeakReference<SurfaceTexture> weakSelf) {
+ SurfaceTexture st = weakSelf.get();
+ if (st != null) {
+ Handler handler = st.mOnFrameAvailableHandler;
+ if (handler != null) {
+ handler.sendEmptyMessage(0);
+ }
}
}
- private void init(int texName, boolean singleBufferMode) throws Surface.OutOfResourcesException {
- Looper looper;
- if ((looper = Looper.myLooper()) != null) {
- mEventHandler = new EventHandler(looper);
- } else if ((looper = Looper.getMainLooper()) != null) {
- mEventHandler = new EventHandler(looper);
- } else {
- mEventHandler = null;
- }
- nativeInit(texName, singleBufferMode, new WeakReference<SurfaceTexture>(this));
- }
-
- private native void nativeInit(int texName, boolean singleBufferMode, Object weakSelf)
+ private native void nativeInit(int texName, boolean singleBufferMode,
+ WeakReference<SurfaceTexture> weakSelf)
throws Surface.OutOfResourcesException;
private native void nativeFinalize();
private native void nativeGetTransformMatrix(float[] mtx);
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index e3f57e9..218a057 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -16,20 +16,22 @@
package android.graphics.drawable;
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
-import android.util.MathUtils;
-import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
/**
* Draws a Quantum Paper ripple.
*/
class Ripple {
- private static final TimeInterpolator INTERPOLATOR = new DecelerateInterpolator(2.0f);
+ private static final TimeInterpolator INTERPOLATOR = new DecelerateInterpolator();
/** Starting radius for a ripple. */
private static final int STARTING_RADIUS_DP = 16;
@@ -37,6 +39,9 @@
/** Radius when finger is outside view bounds. */
private static final int OUTSIDE_RADIUS_DP = 16;
+ /** Radius when finger is inside view bounds. */
+ private static final int INSIDE_RADIUS_DP = 96;
+
/** Margin when constraining outside touches (fraction of outer radius). */
private static final float OUTSIDE_MARGIN = 0.8f;
@@ -44,15 +49,53 @@
private static final float OUTSIDE_RESISTANCE = 0.7f;
/** Minimum alpha value during a pulse animation. */
- private static final int PULSE_MIN_ALPHA = 128;
+ private static final float PULSE_MIN_ALPHA = 0.5f;
+ /** Duration for animating the trailing edge of the ripple. */
+ private static final int EXIT_DURATION = 600;
+
+ /** Duration for animating the leading edge of the ripple. */
+ private static final int ENTER_DURATION = 400;
+
+ /** Duration for animating the ripple alpha in and out. */
+ private static final int FADE_DURATION = 50;
+
+ /** Minimum elapsed time between start of enter and exit animations. */
+ private static final int EXIT_MIN_DELAY = 200;
+
+ /** Duration for animating between inside and outside touch. */
+ private static final int OUTSIDE_DURATION = 300;
+
+ /** Duration for animating pulses. */
+ private static final int PULSE_DURATION = 400;
+
+ /** Interval between pulses while inside and fully entered. */
+ private static final int PULSE_INTERVAL = 400;
+
+ /** Delay before pulses start. */
+ private static final int PULSE_DELAY = 500;
+
+ private final Drawable mOwner;
+
+ /** Bounds used for computing max radius and containment. */
private final Rect mBounds;
- private final Rect mPadding;
- private RippleAnimator mAnimator;
+ /** Configured maximum ripple radius when the center is outside the bounds. */
+ private final int mMaxOutsideRadius;
- private int mMinRadius;
- private int mOutsideRadius;
+ /** Configured maximum ripple radius. */
+ private final int mMaxInsideRadius;
+
+ private ObjectAnimator mOuter;
+ private ObjectAnimator mInner;
+ private ObjectAnimator mAlpha;
+
+ /** Maximum ripple radius. */
+ private int mMaxRadius;
+
+ private float mOuterRadius;
+ private float mInnerRadius;
+ private float mAlphaMultiplier;
/** Center x-coordinate. */
private float mX;
@@ -61,46 +104,151 @@
private float mY;
/** Whether the center is within the parent bounds. */
- private boolean mInside;
+ private boolean mInsideBounds;
/** Whether to pulse this ripple. */
- boolean mPulse;
-
- /** Enter state. A value in [0...1] or -1 if not set. */
- float mEnterState = -1;
+ private boolean mPulseEnabled;
- /** Exit state. A value in [0...1] or -1 if not set. */
- float mExitState = -1;
+ /** Temporary hack since we can't check finished state of animator. */
+ private boolean mExitFinished;
- /** Outside state. A value in [0...1] or -1 if not set. */
- float mOutsideState = -1;
-
- /** Pulse state. A value in [0...1] or -1 if not set. */
- float mPulseState = -1;
+ /** Whether this ripple has ever moved. */
+ private boolean mHasMoved;
/**
- * Creates a new ripple with the specified parent bounds, padding, initial
- * position, and screen density.
+ * Creates a new ripple.
*/
- public Ripple(Rect bounds, Rect padding, float x, float y, float density, boolean pulse) {
+ public Ripple(Drawable owner, Rect bounds, float density, boolean pulseEnabled) {
+ mOwner = owner;
mBounds = bounds;
- mPadding = padding;
- mInside = mBounds.contains((int) x, (int) y);
- mPulse = pulse;
+ mPulseEnabled = pulseEnabled;
- mX = x;
- mY = y;
+ mOuterRadius = (int) (density * STARTING_RADIUS_DP + 0.5f);
+ mMaxOutsideRadius = (int) (density * OUTSIDE_RADIUS_DP + 0.5f);
+ mMaxInsideRadius = (int) (density * INSIDE_RADIUS_DP + 0.5f);
+ mMaxRadius = Math.min(mMaxInsideRadius, Math.max(bounds.width(), bounds.height()));
+ }
- mMinRadius = (int) (density * STARTING_RADIUS_DP + 0.5f);
- mOutsideRadius = (int) (density * OUTSIDE_RADIUS_DP + 0.5f);
+ public void setOuterRadius(float r) {
+ mOuterRadius = r;
+ invalidateSelf();
}
-
- public void setMinRadius(int minRadius) {
- mMinRadius = minRadius;
+
+ public float getOuterRadius() {
+ return mOuterRadius;
}
-
- public void setOutsideRadius(int outsideRadius) {
- mOutsideRadius = outsideRadius;
+
+ public void setInnerRadius(float r) {
+ mInnerRadius = r;
+ invalidateSelf();
+ }
+
+ public float getInnerRadius() {
+ return mInnerRadius;
+ }
+
+ public void setAlphaMultiplier(float a) {
+ mAlphaMultiplier = a;
+ invalidateSelf();
+ }
+
+ public float getAlphaMultiplier() {
+ return mAlphaMultiplier;
+ }
+
+ /**
+ * Returns whether this ripple has finished exiting.
+ */
+ public boolean isFinished() {
+ return mExitFinished;
+ }
+
+ /**
+ * Called when the bounds change.
+ */
+ public void onBoundsChanged() {
+ mMaxRadius = Math.min(mMaxInsideRadius, Math.max(mBounds.width(), mBounds.height()));
+
+ updateInsideBounds();
+ }
+
+ private void updateInsideBounds() {
+ final boolean insideBounds = mBounds.contains((int) (mX + 0.5f), (int) (mY + 0.5f));
+ if (mInsideBounds != insideBounds || !mHasMoved) {
+ mInsideBounds = insideBounds;
+ mHasMoved = true;
+
+ if (insideBounds) {
+ enter();
+ } else {
+ outside();
+ }
+ }
+ }
+
+ /**
+ * Draws the ripple using the specified paint.
+ */
+ public boolean draw(Canvas c, Paint p) {
+ final Rect bounds = mBounds;
+ final float outerRadius = mOuterRadius;
+ final float innerRadius = mInnerRadius;
+ final float alphaMultiplier = mAlphaMultiplier;
+
+ // Cache the paint alpha so we can restore it later.
+ final int paintAlpha = p.getAlpha();
+ final int alpha = (int) (paintAlpha * alphaMultiplier + 0.5f);
+
+ // Apply resistance effect when outside bounds.
+ final float x;
+ final float y;
+ if (mInsideBounds) {
+ x = mX;
+ y = mY;
+ } else {
+ // TODO: We need to do this outside of draw() so that our dirty
+ // bounds accurately reflect resistance.
+ x = looseConstrain(mX, bounds.left, bounds.right,
+ mOuterRadius * OUTSIDE_MARGIN, OUTSIDE_RESISTANCE);
+ y = looseConstrain(mY, bounds.top, bounds.bottom,
+ mOuterRadius * OUTSIDE_MARGIN, OUTSIDE_RESISTANCE);
+ }
+
+ final boolean hasContent;
+ if (alphaMultiplier <= 0 || innerRadius >= outerRadius) {
+ // Nothing to draw.
+ hasContent = false;
+ } else if (innerRadius > 0) {
+ // Draw a ring.
+ final float strokeWidth = outerRadius - innerRadius;
+ final float strokeRadius = innerRadius + strokeWidth / 2.0f;
+ p.setAlpha(alpha);
+ p.setStyle(Style.STROKE);
+ p.setStrokeWidth(strokeWidth);
+ c.drawCircle(x, y, strokeRadius, p);
+ hasContent = true;
+ } else if (outerRadius > 0) {
+ // Draw a circle.
+ p.setAlpha(alpha);
+ p.setStyle(Style.FILL);
+ c.drawCircle(x, y, outerRadius, p);
+ hasContent = true;
+ } else {
+ hasContent = false;
+ }
+
+ p.setAlpha(paintAlpha);
+ return hasContent;
+ }
+
+ /**
+ * Returns the maximum bounds for this ripple.
+ */
+ public void getBounds(Rect bounds) {
+ final int x = (int) mX;
+ final int y = (int) mY;
+ final int maxRadius = mMaxRadius;
+ bounds.set(x - maxRadius, y - maxRadius, x + maxRadius, y + maxRadius);
}
/**
@@ -110,117 +258,116 @@
mX = x;
mY = y;
- final boolean inside = mBounds.contains((int) x, (int) y);
- if (mInside != inside) {
- if (mAnimator != null) {
- mAnimator.outside();
- }
- mInside = inside;
+ updateInsideBounds();
+ invalidateSelf();
+ }
+
+ /**
+ * Starts the exit animation. If {@link #enter()} was called recently, the
+ * animation may be postponed.
+ */
+ public void exit() {
+ mExitFinished = false;
+
+ final ObjectAnimator inner = ObjectAnimator.ofFloat(this, "innerRadius", 0, mMaxRadius);
+ inner.setAutoCancel(true);
+ inner.setDuration(EXIT_DURATION);
+ inner.setInterpolator(INTERPOLATOR);
+ inner.addListener(mAnimationListener);
+
+ if (mOuter != null && mOuter.isStarted()) {
+ // If we haven't been running the enter animation for long enough,
+ // delay the exit animator.
+ final int elapsed = (int) (mOuter.getAnimatedFraction() * mOuter.getDuration());
+ final int delay = Math.max(0, EXIT_MIN_DELAY - elapsed);
+ inner.setStartDelay(delay);
+ }
+
+ inner.start();
+
+ final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 0);
+ alpha.setAutoCancel(true);
+ alpha.setDuration(EXIT_DURATION);
+ alpha.start();
+
+ mInner = inner;
+ mAlpha = alpha;
+ }
+
+ /**
+ * Cancel all animations.
+ */
+ public void cancel() {
+ if (mInner != null) {
+ mInner.cancel();
+ }
+
+ if (mOuter != null) {
+ mOuter.cancel();
+ }
+
+ if (mAlpha != null) {
+ mAlpha.cancel();
}
}
- public void onBoundsChanged() {
- final boolean inside = mBounds.contains((int) mX, (int) mY);
- if (mInside != inside) {
- if (mAnimator != null) {
- mAnimator.outside();
- }
- mInside = inside;
- }
+ private void invalidateSelf() {
+ mOwner.invalidateSelf();
}
- public RippleAnimator animate() {
- if (mAnimator == null) {
- mAnimator = new RippleAnimator(this);
- }
- return mAnimator;
- }
+ /**
+ * Starts the enter animation.
+ */
+ private void enter() {
+ final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerRadius", mMaxRadius);
+ outer.setAutoCancel(true);
+ outer.setDuration(ENTER_DURATION);
+ outer.setInterpolator(INTERPOLATOR);
+ outer.start();
- public boolean draw(Canvas c, Paint p) {
- final Rect bounds = mBounds;
- final Rect padding = mPadding;
- final float dX = Math.max(mX - bounds.left, bounds.right - mX);
- final float dY = Math.max(mY - bounds.top, bounds.bottom - mY);
- final int maxRadius = (int) Math.ceil(Math.sqrt(dX * dX + dY * dY));
+ final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 1);
+ if (mPulseEnabled) {
+ alpha.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ final ObjectAnimator pulse = ObjectAnimator.ofFloat(
+ this, "alphaMultiplier", 1, PULSE_MIN_ALPHA);
+ pulse.setAutoCancel(true);
+ pulse.setDuration(PULSE_DURATION + PULSE_INTERVAL);
+ pulse.setRepeatCount(ObjectAnimator.INFINITE);
+ pulse.setRepeatMode(ObjectAnimator.REVERSE);
+ pulse.setStartDelay(PULSE_DELAY);
+ pulse.start();
- final float enterState = mEnterState;
- final float exitState = mExitState;
- final float outsideState = mOutsideState;
- final float pulseState = mPulseState;
- final float insideRadius = MathUtils.lerp(mMinRadius, maxRadius, enterState);
- final float outerRadius = MathUtils.lerp(mOutsideRadius, insideRadius,
- mInside ? outsideState : 1 - outsideState);
-
- // Apply resistance effect when outside bounds.
- final float x = looseConstrain(mX, bounds.left + padding.left, bounds.right - padding.right,
- outerRadius * OUTSIDE_MARGIN, OUTSIDE_RESISTANCE);
- final float y = looseConstrain(mY, bounds.top + padding.top, bounds.bottom - padding.bottom,
- outerRadius * OUTSIDE_MARGIN, OUTSIDE_RESISTANCE);
-
- // Compute maximum alpha, taking pulse into account when active.
- final int maxAlpha;
- if (pulseState < 0 || pulseState >= 1) {
- maxAlpha = 255;
- } else {
- final float pulseAlpha;
- if (pulseState > 0.5) {
- // Pulsing in to max alpha.
- pulseAlpha = MathUtils.lerp(PULSE_MIN_ALPHA, 255, (pulseState - .5f) * 2);
- } else {
- // Pulsing out to min alpha.
- pulseAlpha = MathUtils.lerp(255, PULSE_MIN_ALPHA, pulseState * 2f);
- }
-
- if (exitState > 0) {
- // Animating exit, interpolate pulse with exit state.
- maxAlpha = (int) (MathUtils.lerp(255, pulseAlpha, exitState) + 0.5f);
- } else if (mInside) {
- // No animation, no need to interpolate.
- maxAlpha = (int) (pulseAlpha + 0.5f);
- } else {
- // Animating inside, interpolate pulse with inside state.
- maxAlpha = (int) (MathUtils.lerp(pulseAlpha, 255, outsideState) + 0.5f);
- }
- }
-
- if (maxAlpha > 0) {
- if (exitState <= 0) {
- // Exit state isn't showing, so we can simplify to a solid
- // circle.
- if (outerRadius > 0) {
- p.setAlpha(maxAlpha);
- p.setStyle(Style.FILL);
- c.drawCircle(x, y, outerRadius, p);
- return true;
+ mAlpha = pulse;
}
- } else {
- // Both states are showing, so we need a circular stroke.
- final float innerRadius = MathUtils.lerp(0, outerRadius, exitState);
- final float strokeWidth = outerRadius - innerRadius;
- if (strokeWidth > 0) {
- final float strokeRadius = innerRadius + strokeWidth / 2f;
- final int alpha = (int) (MathUtils.lerp(maxAlpha, 0, exitState) + 0.5f);
- if (alpha > 0) {
- p.setAlpha(alpha);
- p.setStyle(Style.STROKE);
- p.setStrokeWidth(strokeWidth);
- c.drawCircle(x, y, strokeRadius, p);
- return true;
- }
- }
- }
+ });
}
+ alpha.setAutoCancel(true);
+ alpha.setDuration(FADE_DURATION);
+ alpha.start();
- return false;
+ mOuter = outer;
+ mAlpha = alpha;
}
- public void getBounds(Rect bounds) {
- final int x = (int) mX;
- final int y = (int) mY;
- final int dX = Math.max(x, mBounds.right - x);
- final int dY = Math.max(x, mBounds.bottom - y);
- final int maxRadius = (int) Math.ceil(Math.sqrt(dX * dX + dY * dY));
- bounds.set(x - maxRadius, y - maxRadius, x + maxRadius, y + maxRadius);
+ /**
+ * Starts the outside transition animation.
+ */
+ private void outside() {
+ final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerRadius", mMaxOutsideRadius);
+ outer.setAutoCancel(true);
+ outer.setDuration(OUTSIDE_DURATION);
+ outer.setInterpolator(INTERPOLATOR);
+ outer.start();
+
+ final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 1);
+ alpha.setAutoCancel(true);
+ alpha.setDuration(FADE_DURATION);
+ alpha.start();
+
+ mOuter = outer;
+ mAlpha = alpha;
}
/**
@@ -229,6 +376,7 @@
*/
private static float looseConstrain(float value, float min, float max, float margin,
float factor) {
+ // TODO: Can we use actual spring physics here?
if (value < min) {
return min - Math.min(margin, (float) Math.pow(min - value, factor));
} else if (value > max) {
@@ -237,96 +385,16 @@
return value;
}
}
-
- public static class RippleAnimator {
- /** Duration for animating the trailing edge of the ripple. */
- private static final int EXIT_DURATION = 600;
- /** Duration for animating the leading edge of the ripple. */
- private static final int ENTER_DURATION = 400;
-
- /** Minimum elapsed time between start of enter and exit animations. */
- private static final int EXIT_MIN_DELAY = 200;
-
- /** Duration for animating between inside and outside touch. */
- private static final int OUTSIDE_DURATION = 300;
-
- /** Duration for animating pulses. */
- private static final int PULSE_DURATION = 400;
-
- /** Interval between pulses while inside and fully entered. */
- private static final int PULSE_INTERVAL = 400;
-
- /** Delay before pulses start. */
- private static final int PULSE_DELAY = 500;
-
- /** The target ripple being animated. */
- private final Ripple mTarget;
-
- /** When the ripple started appearing. */
- private long mEnterTime = -1;
-
- /** When the ripple started vanishing. */
- private long mExitTime = -1;
-
- /** When the ripple last transitioned between inside and outside touch. */
- private long mOutsideTime = -1;
-
- public RippleAnimator(Ripple target) {
- mTarget = target;
- }
-
- /**
- * Starts the enter animation.
- */
- public void enter() {
- mEnterTime = AnimationUtils.currentAnimationTimeMillis();
- }
-
- /**
- * Starts the exit animation. If {@link #enter()} was called recently, the
- * animation may be postponed.
- */
- public void exit() {
- final long minTime = mEnterTime + EXIT_MIN_DELAY;
- mExitTime = Math.max(minTime, AnimationUtils.currentAnimationTimeMillis());
- }
-
- /**
- * Starts the outside transition animation.
- */
- public void outside() {
- mOutsideTime = AnimationUtils.currentAnimationTimeMillis();
- }
-
- /**
- * Returns whether this ripple is currently animating.
- */
- public boolean isRunning() {
- final long currentTime = AnimationUtils.currentAnimationTimeMillis();
- return mEnterTime >= 0 && mEnterTime <= currentTime
- && (mExitTime < 0 || currentTime <= mExitTime + EXIT_DURATION);
- }
-
- public void update() {
- // Track three states:
- // - Enter: touch begins, affects outer radius
- // - Outside: touch moves outside bounds, affects maximum outer radius
- // - Exit: touch ends, affects inner radius
- final long currentTime = AnimationUtils.currentAnimationTimeMillis();
- mTarget.mEnterState = mEnterTime < 0 ? 0 : INTERPOLATOR.getInterpolation(
- MathUtils.constrain((currentTime - mEnterTime) / (float) ENTER_DURATION, 0, 1));
- mTarget.mExitState = mExitTime < 0 ? 0 : INTERPOLATOR.getInterpolation(
- MathUtils.constrain((currentTime - mExitTime) / (float) EXIT_DURATION, 0, 1));
- mTarget.mOutsideState = mOutsideTime < 0 ? 1 : INTERPOLATOR.getInterpolation(
- MathUtils.constrain((currentTime - mOutsideTime) / (float) OUTSIDE_DURATION, 0, 1));
-
- // Pulse is a little more complicated.
- if (mTarget.mPulse) {
- final long pulseTime = (currentTime - mEnterTime - ENTER_DURATION - PULSE_DELAY);
- mTarget.mPulseState = pulseTime < 0 ? -1
- : (pulseTime % (PULSE_INTERVAL + PULSE_DURATION)) / (float) PULSE_DURATION;
+ private final AnimatorListener mAnimationListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (animation == mInner) {
+ mExitFinished = true;
+ mOuterRadius = 0;
+ mInnerRadius = 0;
+ mAlphaMultiplier = 1;
}
}
- }
+ };
}
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 0e8831f..0097183 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -27,8 +27,6 @@
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
-import android.graphics.drawable.Ripple.RippleAnimator;
-import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -40,7 +38,6 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
-import java.util.Arrays;
/**
* Documentation pending.
@@ -54,7 +51,6 @@
private static final int MAX_RIPPLES = 10;
private final Rect mTempRect = new Rect();
- private final Rect mPaddingRect = new Rect();
/** Current ripple effect bounds, used to constrain ripple effects. */
private final Rect mHotspotBounds = new Rect();
@@ -68,14 +64,11 @@
private final TouchFeedbackState mState;
/** Lazily-created map of touch hotspot IDs to ripples. */
- private SparseArray<Ripple> mTouchedRipples;
+ private SparseArray<Ripple> mRipples;
/** Lazily-created array of actively animating ripples. */
- private Ripple[] mActiveRipples;
- private int mActiveRipplesCount = 0;
-
- /** Lazily-created runnable for scheduling invalidation. */
- private Runnable mAnimationRunnable;
+ private Ripple[] mAnimatingRipples;
+ private int mAnimatingRipplesCount = 0;
/** Paint used to control appearance of ripples. */
private Paint mRipplePaint;
@@ -86,9 +79,6 @@
/** Target density of the display into which ripples are drawn. */
private float mDensity = 1.0f;
- /** Whether the animation runnable has been posted. */
- private boolean mAnimating;
-
/** Whether bounds are being overridden. */
private boolean mOverrideBounds;
@@ -154,28 +144,19 @@
private void onHotspotBoundsChange() {
final int x = mHotspotBounds.centerX();
final int y = mHotspotBounds.centerY();
- final int N = mActiveRipplesCount;
+ final int N = mAnimatingRipplesCount;
for (int i = 0; i < N; i++) {
if (mState.mPinned) {
- mActiveRipples[i].move(x, y);
+ mAnimatingRipples[i].move(x, y);
}
- mActiveRipples[i].onBoundsChanged();
+ mAnimatingRipples[i].onBoundsChanged();
}
}
@Override
public boolean setVisible(boolean visible, boolean restart) {
if (!visible) {
- if (mTouchedRipples != null) {
- mTouchedRipples.clear();
- }
-
- if (mActiveRipplesCount > 0) {
- Arrays.fill(mActiveRipples, null);
- mActiveRipplesCount = 0;
- mAnimating = false;
- unscheduleSelf(mAnimationRunnable);
- }
+ clearHotspots();
}
return super.setVisible(visible, restart);
@@ -348,21 +329,18 @@
@Override
public void setHotspot(int id, float x, float y) {
- if (mTouchedRipples == null) {
- mTouchedRipples = new SparseArray<Ripple>();
- mActiveRipples = new Ripple[MAX_RIPPLES];
+ if (mRipples == null) {
+ mRipples = new SparseArray<Ripple>();
+ mAnimatingRipples = new Ripple[MAX_RIPPLES];
}
- if (mActiveRipplesCount >= MAX_RIPPLES) {
+ if (mAnimatingRipplesCount >= MAX_RIPPLES) {
Log.e(LOG_TAG, "Max ripple count exceeded", new RuntimeException());
return;
}
- final Ripple ripple = mTouchedRipples.get(id);
+ final Ripple ripple = mRipples.get(id);
if (ripple == null) {
- final Rect padding = mPaddingRect;
- getPadding(padding);
-
final Rect bounds = mHotspotBounds;
if (mState.mPinned) {
x = bounds.exactCenterX();
@@ -371,11 +349,11 @@
// TODO: Clean this up in the API.
final boolean pulse = (id != R.attr.state_focused);
- final Ripple newRipple = new Ripple(bounds, padding, x, y, mDensity, pulse);
- newRipple.animate().enter();
+ final Ripple newRipple = new Ripple(this, bounds, mDensity, pulse);
+ newRipple.move(x, y);
- mActiveRipples[mActiveRipplesCount++] = newRipple;
- mTouchedRipples.put(id, newRipple);
+ mAnimatingRipples[mAnimatingRipplesCount++] = newRipple;
+ mRipples.put(id, newRipple);
} else if (mState.mPinned) {
final Rect bounds = mHotspotBounds;
x = bounds.exactCenterX();
@@ -384,41 +362,37 @@
} else {
ripple.move(x, y);
}
-
- scheduleAnimation();
}
@Override
public void removeHotspot(int id) {
- if (mTouchedRipples == null) {
+ if (mRipples == null) {
return;
}
- final Ripple ripple = mTouchedRipples.get(id);
+ final Ripple ripple = mRipples.get(id);
if (ripple != null) {
- ripple.animate().exit();
+ ripple.exit();
- mTouchedRipples.remove(id);
- scheduleAnimation();
+ mRipples.remove(id);
}
}
@Override
public void clearHotspots() {
- if (mTouchedRipples == null) {
- return;
+ if (mRipples != null) {
+ mRipples.clear();
}
- final int n = mTouchedRipples.size();
- for (int i = 0; i < n; i++) {
- // TODO: Use a fast exit, maybe just fade out?
- mTouchedRipples.valueAt(i).animate().exit();
+ final int count = mAnimatingRipplesCount;
+ final Ripple[] ripples = mAnimatingRipples;
+ for (int i = 0; i < count; i++) {
+ ripples[i].cancel();
+ ripples[i] = null;
}
- if (n > 0) {
- mTouchedRipples.clear();
- scheduleAnimation();
- }
+ mAnimatingRipplesCount = 0;
+ invalidateSelf();
}
/**
@@ -431,30 +405,6 @@
onHotspotBoundsChange();
}
- /**
- * Schedules the next animation, if necessary.
- */
- private void scheduleAnimation() {
- if (mActiveRipplesCount == 0) {
- mAnimating = false;
- } else if (!mAnimating) {
- mAnimating = true;
-
- if (mAnimationRunnable == null) {
- mAnimationRunnable = new Runnable() {
- @Override
- public void run() {
- mAnimating = false;
- scheduleAnimation();
- invalidateSelf();
- }
- };
- }
-
- scheduleSelf(mAnimationRunnable, SystemClock.uptimeMillis() + 1000 / 60);
- }
- }
-
@Override
public void draw(Canvas canvas) {
final int N = mLayerState.mNum;
@@ -501,12 +451,12 @@
}
private int drawRippleLayer(Canvas canvas, Rect bounds, boolean maskOnly) {
- final int ripplesCount = mActiveRipplesCount;
- if (ripplesCount == 0) {
+ final int count = mAnimatingRipplesCount;
+ if (count == 0) {
return -1;
}
- final Ripple[] activeRipples = mActiveRipples;
+ final Ripple[] ripples = mAnimatingRipples;
final boolean projected = isProjected();
final Rect layerBounds = projected ? getDirtyBounds() : bounds;
@@ -529,17 +479,15 @@
boolean drewRipples = false;
int restoreToCount = -1;
- int activeRipplesCount = 0;
+ int animatingCount = 0;
- // Draw ripples.
- for (int i = 0; i < ripplesCount; i++) {
- final Ripple ripple = activeRipples[i];
- final RippleAnimator animator = ripple.animate();
- animator.update();
+ // Draw ripples and update the animating ripples array.
+ for (int i = 0; i < count; i++) {
+ final Ripple ripple = ripples[i];
- // Mark and skip inactive ripples.
- if (!animator.isRunning()) {
- activeRipples[i] = null;
+ // Mark and skip finished ripples.
+ if (ripple.isFinished()) {
+ ripples[i] = null;
continue;
}
@@ -565,11 +513,11 @@
drewRipples |= ripple.draw(canvas, ripplePaint);
- activeRipples[activeRipplesCount] = activeRipples[i];
- activeRipplesCount++;
+ ripples[animatingCount] = ripples[i];
+ animatingCount++;
}
- mActiveRipplesCount = activeRipplesCount;
+ mAnimatingRipplesCount = animatingCount;
// If we created a layer with no content, merge it immediately.
if (restoreToCount >= 0 && !drewRipples) {
@@ -596,8 +544,8 @@
drawingBounds.setEmpty();
final Rect rippleBounds = mTempRect;
- final Ripple[] activeRipples = mActiveRipples;
- final int N = mActiveRipplesCount;
+ final Ripple[] activeRipples = mAnimatingRipples;
+ final int N = mAnimatingRipplesCount;
for (int i = 0; i < N; i++) {
activeRipples[i].getBounds(rippleBounds);
drawingBounds.union(rippleBounds);
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 0992717..77712b6 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -182,28 +182,14 @@
public VectorDrawable() {
mVectorState = new VectorDrawableState(null);
- mVectorState.mBasicAnimator = ObjectAnimator.ofFloat(this, "AnimationFraction", 0, 0);
-
- setDuration(DEFAULT_DURATION);
}
private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) {
mVectorState = new VectorDrawableState(state);
- mVectorState.mBasicAnimator = ObjectAnimator.ofFloat(this, "AnimationFraction", 0, 0);
if (theme != null && canApplyTheme()) {
applyTheme(theme);
}
-
- long duration = mVectorState.mVAnimatedPath.getTotalAnimationDuration();
- if (duration == -1) {
- // If duration is infinite, set to 1 hour.
- // TODO: Define correct approach for infinite.
- duration = DEFAULT_INFINITE_DURATION;
- mVectorState.mBasicAnimator.setFloatValues(0, duration / 1000);
- mVectorState.mBasicAnimator.setInterpolator(new LinearInterpolator());
- }
- setDuration(duration);
}
@Override
@@ -212,118 +198,6 @@
}
@Override
- public void jumpToCurrentState() {
- stop();
- }
-
- /**
- * Starts the animation.
- */
- public void start() {
- mVectorState.mBasicAnimator.start();
- }
-
- /**
- * Stops the animation and moves to the end state.
- */
- public void stop() {
- mVectorState.mBasicAnimator.end();
- }
-
- /**
- * Returns the current completion value for the animation.
- *
- * @return the current point on the animation, typically between 0 and 1
- */
- public float geAnimationFraction() {
- return mVectorState.mVAnimatedPath.getValue();
- }
-
- /**
- * Set the current completion value for the animation.
- *
- * @param value the point along the animation, typically between 0 and 1
- */
- public void setAnimationFraction(float value) {
- mVectorState.mVAnimatedPath.setAnimationFraction(value);
- invalidateSelf();
- }
-
- /**
- * set the amount of time the animation will take
- *
- * @param duration amount of time in milliseconds
- */
- public void setDuration(long duration) {
- mVectorState.mBasicAnimator.setDuration(duration);
- }
-
- /**
- * Defines what this animation should do when it reaches the end. This
- * setting is applied only when the repeat count is either greater than 0 or
- * {@link ValueAnimator#INFINITE}.
- *
- * @param mode the animation mode, either {@link ValueAnimator#RESTART} or
- * {@link ValueAnimator#REVERSE}
- */
- public void setRepeatMode(int mode) {
- mVectorState.mBasicAnimator.setRepeatMode(mode);
- }
-
- /**
- * Sets animation to repeat
- *
- * @param repeat True if this drawable repeats its animation
- */
- public void setRepeatCount(int repeat) {
- mVectorState.mBasicAnimator.setRepeatCount(repeat);
- }
-
- /**
- * @return the animation repeat count, either a value greater than 0 or
- * {@link ValueAnimator#INFINITE}
- */
- public int getRepeatCount() {
- return mVectorState.mBasicAnimator.getRepeatCount();
- }
-
- @Override
- public boolean isStateful() {
- return true;
- }
-
- @Override
- protected boolean onStateChange(int[] state) {
- super.onStateChange(state);
-
- mVectorState.mVAnimatedPath.setState(state);
-
- final int direction = mVectorState.mVAnimatedPath.getTrigger(state);
- if (direction > 0) {
- animateForward();
- } else if (direction < 0) {
- animateBackward();
- }
-
- invalidateSelf();
- return true;
- }
-
- private void animateForward() {
- if (!mVectorState.mBasicAnimator.isStarted()) {
- mVectorState.mBasicAnimator.setFloatValues(0, 1);
- start();
- }
- }
-
- private void animateBackward() {
- if (!mVectorState.mBasicAnimator.isStarted()) {
- mVectorState.mBasicAnimator.setFloatValues(1, 0);
- start();
- }
- }
-
- @Override
public void draw(Canvas canvas) {
final int saveCount = canvas.save();
final Rect bounds = getBounds();
@@ -432,7 +306,6 @@
final VectorDrawable drawable = new VectorDrawable();
drawable.inflate(resources, xpp, attrs);
- drawable.setAnimationFraction(0);
return drawable;
} catch (XmlPullParserException e) {
@@ -536,35 +409,10 @@
private void setAnimatedPath(VAnimatedPath animatedPath) {
mVectorState.mVAnimatedPath = animatedPath;
-
- long duration = mVectorState.mVAnimatedPath.getTotalAnimationDuration();
- if (duration == -1) { // if it set to infinite set to 1 hour
- duration = DEFAULT_INFINITE_DURATION; // TODO define correct
- // approach for infinite
- mVectorState.mBasicAnimator.setFloatValues(0, duration / 1000);
- mVectorState.mBasicAnimator.setInterpolator(new LinearInterpolator());
- }
-
- setDuration(duration);
- setAnimationFraction(0);
- }
-
- @Override
- public boolean setVisible(boolean visible, boolean restart) {
- boolean changed = super.setVisible(visible, restart);
- if (visible) {
- if (changed || restart) {
- setAnimationFraction(0);
- }
- } else {
- stop();
- }
- return changed;
}
private static class VectorDrawableState extends ConstantState {
int mChangingConfigurations;
- ValueAnimator mBasicAnimator;
VAnimatedPath mVAnimatedPath;
Rect mPadding;
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index d324439..eb0cac8 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -59,7 +59,8 @@
renderthread/DrawFrameTask.cpp \
renderthread/RenderProxy.cpp \
renderthread/RenderTask.cpp \
- renderthread/RenderThread.cpp
+ renderthread/RenderThread.cpp \
+ renderthread/TimeLord.cpp
intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index ee16586..6a3003e 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -20,130 +20,13 @@
#include <set>
+#include "RenderNode.h"
#include "RenderProperties.h"
namespace android {
namespace uirenderer {
/************************************************************
- * Private header
- ************************************************************/
-
-typedef void (RenderProperties::*SetFloatProperty)(float value);
-typedef float (RenderProperties::*GetFloatProperty)() const;
-
-struct PropertyAccessors {
- GetFloatProperty getter;
- SetFloatProperty setter;
-};
-
-// Maps RenderProperty enum to accessors
-static const PropertyAccessors 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 },
-};
-
-// Helper class to contain generic animator helpers
-class BaseAnimator {
-public:
- BaseAnimator();
- virtual ~BaseAnimator();
-
- void setInterpolator(Interpolator* interpolator);
- void setDuration(nsecs_t durationInMs);
-
- bool isFinished() { return mPlayState == FINISHED; }
-
-protected:
- // 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(nsecs_t frameTime);
-
- // Called when PlayState switches from PENDING to RUNNING
- virtual void onAnimationStarted() {}
- virtual void onAnimationUpdated(float fraction) = 0;
- virtual void onAnimationFinished() {}
-
-private:
- enum PlayState {
- PENDING,
- RUNNING,
- FINISHED,
- };
-
- Interpolator* mInterpolator;
- PlayState mPlayState;
- long mStartTime;
- long mDuration;
-};
-
-// Hide the base classes & private bits from the exported RenderPropertyAnimator
-// in this Impl class so that subclasses of RenderPropertyAnimator don't require
-// knowledge of the inner guts but only the public virtual methods.
-// Animates a single property
-class RenderPropertyAnimatorImpl : public BaseAnimator {
-public:
- RenderPropertyAnimatorImpl(GetFloatProperty getter, SetFloatProperty setter,
- RenderPropertyAnimator::DeltaValueType deltaType, float delta);
- ~RenderPropertyAnimatorImpl();
-
- bool animate(RenderProperties* target, TreeInfo& info);
-
-protected:
- virtual void onAnimationStarted();
- virtual void onAnimationUpdated(float fraction);
-
-private:
- // mTarget is only valid inside animate()
- RenderProperties* mTarget;
- GetFloatProperty mGetter;
- SetFloatProperty mSetter;
-
- RenderPropertyAnimator::DeltaValueType mDeltaValueType;
- float mDeltaValue;
- float mFromValue;
-};
-
-RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property,
- DeltaValueType deltaType, float deltaValue) {
- PropertyAccessors pa = PROPERTY_ACCESSOR_LUT[property];
- mImpl = new RenderPropertyAnimatorImpl(pa.getter, pa.setter, deltaType, deltaValue);
-}
-
-RenderPropertyAnimator::~RenderPropertyAnimator() {
- delete mImpl;
- mImpl = NULL;
-}
-
-void RenderPropertyAnimator::setInterpolator(Interpolator* interpolator) {
- mImpl->setInterpolator(interpolator);
-}
-
-void RenderPropertyAnimator::setDuration(nsecs_t durationInMs) {
- mImpl->setDuration(durationInMs);
-}
-
-bool RenderPropertyAnimator::isFinished() {
- return mImpl->isFinished();
-}
-
-bool RenderPropertyAnimator::animate(RenderProperties* target, TreeInfo& info) {
- return mImpl->animate(target, info);
-}
-
-
-/************************************************************
* Base animator
************************************************************/
@@ -168,10 +51,10 @@
mDuration = duration;
}
-bool BaseAnimator::animateFrame(nsecs_t frameTime) {
+bool BaseAnimator::animateFrame(TreeInfo& info) {
if (mPlayState == PENDING) {
mPlayState = RUNNING;
- mStartTime = frameTime;
+ mStartTime = info.frameTimeMs;
// No interpolator was set, use the default
if (!mInterpolator) {
setInterpolator(Interpolator::createDefaultInterpolator());
@@ -181,7 +64,7 @@
float fraction = 1.0f;
if (mPlayState == RUNNING) {
- fraction = mDuration > 0 ? (float)(frameTime - mStartTime) / mDuration : 1.0f;
+ fraction = mDuration > 0 ? (float)(info.frameTimeMs - mStartTime) / mDuration : 1.0f;
if (fraction >= 1.0f) {
fraction = 1.0f;
mPlayState = FINISHED;
@@ -192,48 +75,140 @@
if (mPlayState == FINISHED) {
onAnimationFinished();
+ callOnFinishedListener(info);
return true;
}
return false;
}
+void BaseAnimator::callOnFinishedListener(TreeInfo& info) {
+ if (mListener.get()) {
+ if (!info.animationHook) {
+ mListener->onAnimationFinished(this);
+ } else {
+ info.animationHook->callOnFinished(this, mListener.get());
+ }
+ }
+}
+
+/************************************************************
+ * 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
************************************************************/
-RenderPropertyAnimatorImpl::RenderPropertyAnimatorImpl(
- GetFloatProperty getter, SetFloatProperty setter,
- RenderPropertyAnimator::DeltaValueType deltaType, float delta)
- : mTarget(0)
- , mGetter(getter)
- , mSetter(setter)
- , mDeltaValueType(deltaType)
- , mDeltaValue(delta)
- , mFromValue(-1) {
+// 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 },
+};
+
+RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property,
+ DeltaValueType deltaType, float deltaValue)
+ : BaseRenderNodeAnimator(deltaType, deltaValue)
+ , mPropertyAccess(PROPERTY_ACCESSOR_LUT[property]) {
}
-RenderPropertyAnimatorImpl::~RenderPropertyAnimatorImpl() {
+float RenderPropertyAnimator::getValue() const {
+ return (target()->animatorProperties().*mPropertyAccess.getter)();
}
-bool RenderPropertyAnimatorImpl::animate(RenderProperties* target, TreeInfo& info) {
- mTarget = target;
- bool finished = animateFrame(info.frameTimeMs);
- mTarget = NULL;
- return finished;
+void RenderPropertyAnimator::setValue(float value) {
+ (target()->animatorProperties().*mPropertyAccess.setter)(value);
}
-void RenderPropertyAnimatorImpl::onAnimationStarted() {
- mFromValue = (mTarget->*mGetter)();
+/************************************************************
+ * CanvasPropertyPrimitiveAnimator
+ ************************************************************/
- if (mDeltaValueType == RenderPropertyAnimator::ABSOLUTE) {
- mDeltaValue = (mDeltaValue - mFromValue);
- mDeltaValueType = RenderPropertyAnimator::DELTA;
+CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(
+ CanvasPropertyPrimitive* property, DeltaValueType deltaType, float deltaValue)
+ : BaseRenderNodeAnimator(deltaType, deltaValue)
+ , mProperty(property) {
+}
+
+float CanvasPropertyPrimitiveAnimator::getValue() const {
+ return mProperty->value;
+}
+
+void CanvasPropertyPrimitiveAnimator::setValue(float value) {
+ mProperty->value = value;
+}
+
+/************************************************************
+ * CanvasPropertySkPaintAnimator
+ ************************************************************/
+
+CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
+ CanvasPropertyPaint* property, PaintField field,
+ DeltaValueType deltaType, float deltaValue)
+ : BaseRenderNodeAnimator(deltaType, deltaValue)
+ , mProperty(property)
+ , mField(field) {
+}
+
+float CanvasPropertyPaintAnimator::getValue() const {
+ switch (mField) {
+ case STROKE_WIDTH:
+ return mProperty->value.getStrokeWidth();
+ case ALPHA:
+ return mProperty->value.getAlpha();
}
+ LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
+ return -1;
}
-void RenderPropertyAnimatorImpl::onAnimationUpdated(float fraction) {
- float value = mFromValue + (mDeltaValue * fraction);
- (mTarget->*mSetter)(value);
+void CanvasPropertyPaintAnimator::setValue(float value) {
+ switch (mField) {
+ case STROKE_WIDTH:
+ mProperty->value.setStrokeWidth(value);
+ return;
+ case ALPHA:
+ mProperty->value.setAlpha(value);
+ return;
+ }
+ LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
}
} /* namespace uirenderer */
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index 1c8361b..0b074cc 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -17,18 +17,72 @@
#define ANIMATOR_H
#include <cutils/compiler.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 {
+class RenderNode;
class RenderProperties;
-class RenderPropertyAnimatorImpl;
-class RenderPropertyAnimator : public VirtualLightRefBase {
+class AnimationListener : public VirtualLightRefBase {
+public:
+ ANDROID_API virtual void onAnimationFinished(BaseAnimator*) = 0;
+protected:
+ ANDROID_API virtual ~AnimationListener() {}
+};
+
+// Helper class to contain generic animator helpers
+class BaseAnimator : public VirtualLightRefBase {
+ PREVENT_COPY_AND_ASSIGN(BaseAnimator);
+public:
+
+ ANDROID_API void setInterpolator(Interpolator* interpolator);
+ ANDROID_API void setDuration(nsecs_t durationInMs);
+ ANDROID_API void setListener(AnimationListener* listener) {
+ mListener = listener;
+ }
+
+ bool isFinished() { return mPlayState == FINISHED; }
+
+protected:
+ BaseAnimator();
+ virtual ~BaseAnimator();
+
+ // 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() {}
+
+private:
+ void callOnFinishedListener(TreeInfo& info);
+
+ enum PlayState {
+ PENDING,
+ RUNNING,
+ FINISHED,
+ };
+
+ Interpolator* mInterpolator;
+ PlayState mPlayState;
+ long mStartTime;
+ long mDuration;
+
+ 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
@@ -43,6 +97,29 @@
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 {
TRANSLATION_X = 0,
TRANSLATION_Y,
@@ -58,19 +135,53 @@
ALPHA,
};
- ANDROID_API void setInterpolator(Interpolator* interpolator);
- ANDROID_API void setDuration(nsecs_t durationInMs);
- ANDROID_API bool isFinished();
-
- bool animate(RenderProperties* target, TreeInfo& info);
+ ANDROID_API RenderPropertyAnimator(RenderProperty property,
+ DeltaValueType deltaType, float deltaValue);
protected:
- ANDROID_API RenderPropertyAnimator(RenderProperty property, DeltaValueType deltaType,
- float deltaValue);
- ANDROID_API virtual ~RenderPropertyAnimator();
+ ANDROID_API virtual float getValue() const;
+ ANDROID_API virtual void setValue(float value);
private:
- RenderPropertyAnimatorImpl* mImpl;
+ typedef void (RenderProperties::*SetFloatProperty)(float value);
+ typedef float (RenderProperties::*GetFloatProperty)() const;
+
+ struct PropertyAccessors {
+ GetFloatProperty getter;
+ SetFloatProperty setter;
+ };
+
+ PropertyAccessors mPropertyAccess;
+
+ static const PropertyAccessors PROPERTY_ACCESSOR_LUT[];
+};
+
+class CanvasPropertyPrimitiveAnimator : public BaseRenderNodeAnimator {
+public:
+ ANDROID_API CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
+ DeltaValueType deltaType, float deltaValue);
+protected:
+ ANDROID_API virtual float getValue() const;
+ ANDROID_API virtual void setValue(float value);
+private:
+ sp<CanvasPropertyPrimitive> mProperty;
+};
+
+class CanvasPropertyPaintAnimator : public BaseRenderNodeAnimator {
+public:
+ enum PaintField {
+ STROKE_WIDTH = 0,
+ ALPHA,
+ };
+
+ ANDROID_API CanvasPropertyPaintAnimator(CanvasPropertyPaint* property,
+ PaintField field, DeltaValueType deltaType, float deltaValue);
+protected:
+ ANDROID_API virtual float getValue() const;
+ ANDROID_API virtual void setValue(float value);
+private:
+ sp<CanvasPropertyPaint> mProperty;
+ PaintField mField;
};
} /* namespace uirenderer */
diff --git a/libs/hwui/CanvasProperty.h b/libs/hwui/CanvasProperty.h
new file mode 100644
index 0000000..2e1d176
--- /dev/null
+++ b/libs/hwui/CanvasProperty.h
@@ -0,0 +1,46 @@
+/*
+ * 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 CANVASPROPERTY_H
+#define CANVASPROPERTY_H
+
+#include "utils/Macros.h"
+#include "utils/VirtualLightRefBase.h"
+
+#include <SkPaint.h>
+
+namespace android {
+namespace uirenderer {
+
+class CanvasPropertyPrimitive : public VirtualLightRefBase {
+ PREVENT_COPY_AND_ASSIGN(CanvasPropertyPrimitive);
+public:
+ CanvasPropertyPrimitive(float initialValue) : value(initialValue) {}
+
+ float value;
+};
+
+class CanvasPropertyPaint : public VirtualLightRefBase {
+ PREVENT_COPY_AND_ASSIGN(CanvasPropertyPaint);
+public:
+ CanvasPropertyPaint(const SkPaint& initialValue) : value(initialValue) {}
+
+ SkPaint value;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* CANVASPROPERTY_H */
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index fe70d13..eaeb772 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -140,6 +140,14 @@
void addChild(DrawDisplayListOp* childOp);
const Vector<DrawDisplayListOp*>& children() { return mChildren; }
+ void refProperty(CanvasPropertyPrimitive* prop) {
+ mReferenceHolders.push(prop);
+ }
+
+ void refProperty(CanvasPropertyPaint* prop) {
+ mReferenceHolders.push(prop);
+ }
+
private:
Vector< sp<VirtualLightRefBase> > mReferenceHolders;
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 77afc97..f1d70eb 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1167,6 +1167,27 @@
float mRadius;
};
+class DrawCirclePropsOp : public DrawOp {
+public:
+ DrawCirclePropsOp(float* x, float* y, float* radius, const SkPaint* paint)
+ : DrawOp(paint), mX(x), mY(y), mRadius(radius) {}
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
+ return renderer.drawCircle(*mX, *mY, *mRadius, getPaint(renderer));
+ }
+
+ virtual void output(int level, uint32_t logFlags) const {
+ OP_LOG("Draw Circle Props x %p, y %p, r %p", mX, mY, mRadius);
+ }
+
+ virtual const char* name() { return "DrawCircleProps"; }
+
+private:
+ float* mX;
+ float* mY;
+ float* mRadius;
+};
+
class DrawOvalOp : public DrawStrokableOp {
public:
DrawOvalOp(float left, float top, float right, float bottom, const SkPaint* paint)
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 1b8eb82..c2ce6ed 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -299,6 +299,17 @@
return DrawGlInfo::kStatusDone;
}
+status_t DisplayListRenderer::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
+ CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
+ mDisplayListData->refProperty(x);
+ mDisplayListData->refProperty(y);
+ mDisplayListData->refProperty(radius);
+ mDisplayListData->refProperty(paint);
+ addDrawOp(new (alloc()) DrawCirclePropsOp(&x->value, &y->value,
+ &radius->value, &paint->value));
+ return DrawGlInfo::kStatusDone;
+}
+
status_t DisplayListRenderer::drawOval(float left, float top, float right, float bottom,
const SkPaint* paint) {
paint = refPaint(paint);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index bd75952..185179a 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -132,6 +132,8 @@
virtual status_t drawRoundRect(float left, float top, float right, float bottom,
float rx, float ry, const SkPaint* paint);
virtual status_t drawCircle(float x, float y, float radius, const SkPaint* paint);
+ virtual status_t drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
+ CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint);
virtual status_t drawOval(float left, float top, float right, float bottom,
const SkPaint* paint);
virtual status_t drawArc(float left, float top, float right, float bottom,
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index b52003c..647c281 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -737,30 +737,34 @@
// a null path is OK because there are no custom kernels used
// hence nothing gets cached by RS
if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
+ mRs.clear();
ALOGE("blur RS failed to init");
+ } else {
+ mRsElement = RSC::Element::A_8(mRs);
+ mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
}
-
- mRsElement = RSC::Element::A_8(mRs);
- mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
}
+ if (mRs != 0) {
+ RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
+ RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
+ RS_ALLOCATION_MIPMAP_NONE,
+ RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
+ *image);
+ RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
+ RS_ALLOCATION_MIPMAP_NONE,
+ RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
+ outImage);
- RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
- RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
- RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
- *image);
- RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
- RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
- outImage);
+ mRsScript->setRadius(radius);
+ mRsScript->setInput(ain);
+ mRsScript->forEach(aout);
- mRsScript->setRadius(radius);
- mRsScript->setInput(ain);
- mRsScript->forEach(aout);
+ // replace the original image's pointer, avoiding a copy back to the original buffer
+ free(*image);
+ *image = outImage;
- // replace the original image's pointer, avoiding a copy back to the original buffer
- free(*image);
- *image = outImage;
-
- return;
+ return;
+ }
}
#endif
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 3f2f43e..87b07b3 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -379,49 +379,9 @@
dirtyClip();
}
-void OpenGLRenderer::detachFunctor(Functor* functor) {
- mFunctors.remove(functor);
-}
-
-void OpenGLRenderer::attachFunctor(Functor* functor) {
- mFunctors.add(functor);
-}
-
-status_t OpenGLRenderer::invokeFunctors(Rect& dirty) {
- status_t result = DrawGlInfo::kStatusDone;
- size_t count = mFunctors.size();
-
- if (count > 0) {
- interrupt();
- SortedVector<Functor*> functors(mFunctors);
- mFunctors.clear();
-
- DrawGlInfo info;
- info.clipLeft = 0;
- info.clipTop = 0;
- info.clipRight = 0;
- info.clipBottom = 0;
- info.isLayer = false;
- info.width = 0;
- info.height = 0;
- memset(info.transform, 0, sizeof(float) * 16);
-
- for (size_t i = 0; i < count; i++) {
- Functor* f = functors.itemAt(i);
- result |= (*f)(DrawGlInfo::kModeProcess, &info);
- }
- resume();
- }
-
- return result;
-}
-
status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
- detachFunctor(functor);
-
-
Rect clip(*currentClipRect());
clip.snapToPixelBoundaries();
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index e8e9885..1d46945 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -50,6 +50,7 @@
#include "UvMapper.h"
#include "Vertex.h"
#include "Caches.h"
+#include "CanvasProperty.h"
namespace android {
namespace uirenderer {
@@ -144,9 +145,6 @@
return mCountOverdraw ? mOverdraw : 0.0f;
}
- ANDROID_API status_t invokeFunctors(Rect& dirty);
- ANDROID_API void detachFunctor(Functor* functor);
- ANDROID_API void attachFunctor(Functor* functor);
virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty);
ANDROID_API void pushLayerUpdate(Layer* layer);
@@ -194,6 +192,12 @@
virtual status_t drawRoundRect(float left, float top, float right, float bottom,
float rx, float ry, const SkPaint* paint);
virtual status_t drawCircle(float x, float y, float radius, const SkPaint* paint);
+ virtual status_t drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
+ CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
+ // TODO: Remove once android_view_GLES20Canvas uses DisplayListRenderer
+ // directly
+ return drawCircle(x->value, y->value, radius->value, &paint->value);
+ }
virtual status_t drawOval(float left, float top, float right, float bottom,
const SkPaint* paint);
virtual status_t drawArc(float left, float top, float right, float bottom,
@@ -968,8 +972,6 @@
// List of rectangles to clear after saveLayer() is invoked
Vector<Rect*> mLayers;
- // List of functors to invoke after a frame is drawn
- SortedVector<Functor*> mFunctors;
// List of layers to update at the beginning of a frame
Vector<Layer*> mLayerUpdates;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 7a9c181..9902ff1 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -109,7 +109,7 @@
prepareSubTree(info, mDisplayListData);
}
-static bool is_finished(const sp<RenderPropertyAnimator>& animator) {
+static bool is_finished(const sp<BaseRenderNodeAnimator>& animator) {
return animator->isFinished();
}
@@ -120,7 +120,7 @@
}
if (mNeedsAnimatorsSync) {
mAnimators.resize(mStagingAnimators.size());
- std::vector< sp<RenderPropertyAnimator> >::iterator it;
+ std::vector< sp<BaseRenderNodeAnimator> >::iterator it;
// hint: this means copy_if_not()
it = std::remove_copy_if(mStagingAnimators.begin(), mStagingAnimators.end(),
mAnimators.begin(), is_finished);
@@ -141,36 +141,32 @@
class AnimateFunctor {
public:
- AnimateFunctor(RenderProperties* target, TreeInfo& info)
+ AnimateFunctor(RenderNode* target, TreeInfo& info)
: mTarget(target), mInfo(info) {}
- bool operator() (sp<RenderPropertyAnimator>& animator) {
- bool finished = animator->animate(mTarget, mInfo);
- if (finished && mInfo.animationListener) {
- mInfo.animationListener->onAnimationFinished(animator);
- }
- return finished;
+ bool operator() (sp<BaseRenderNodeAnimator>& animator) {
+ return animator->animate(mTarget, mInfo);
}
private:
- RenderProperties* mTarget;
+ RenderNode* mTarget;
TreeInfo& mInfo;
};
void RenderNode::evaluateAnimations(TreeInfo& info) {
if (!mAnimators.size()) return;
- AnimateFunctor functor(&mProperties, info);
- std::vector< sp<RenderPropertyAnimator> >::iterator newEnd;
+ AnimateFunctor functor(this, info);
+ std::vector< sp<BaseRenderNodeAnimator> >::iterator newEnd;
newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
mAnimators.erase(newEnd, mAnimators.end());
mProperties.updateMatrix();
- info.hasAnimations |= mAnimators.size();
+ info.out.hasAnimations |= mAnimators.size();
}
void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
if (subtree) {
TextureCache& cache = Caches::getInstance().textureCache;
- info.hasFunctors |= subtree->functorCount;
+ info.out.hasFunctors |= subtree->functorCount;
// TODO: Fix ownedBitmapResources to not require disabling prepareTextures
// and thus falling out of async drawing path.
if (subtree->ownedBitmapResources.size()) {
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 294f436..159903c 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -128,6 +128,10 @@
return mProperties;
}
+ RenderProperties& animatorProperties() {
+ return mProperties;
+ }
+
const RenderProperties& stagingProperties() {
return mStagingProperties;
}
@@ -148,13 +152,13 @@
ANDROID_API virtual void prepareTree(TreeInfo& info);
// UI thread only!
- ANDROID_API void addAnimator(const sp<RenderPropertyAnimator>& animator) {
+ ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
mStagingAnimators.insert(animator);
mNeedsAnimatorsSync = true;
}
// UI thread only!
- ANDROID_API void removeAnimator(const sp<RenderPropertyAnimator>& animator) {
+ ANDROID_API void removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
mStagingAnimators.erase(animator);
mNeedsAnimatorsSync = true;
}
@@ -233,8 +237,8 @@
DisplayListData* mStagingDisplayListData;
bool mNeedsAnimatorsSync;
- std::set< sp<RenderPropertyAnimator> > mStagingAnimators;
- std::vector< sp<RenderPropertyAnimator> > mAnimators;
+ std::set< sp<BaseRenderNodeAnimator> > mStagingAnimators;
+ std::vector< sp<BaseRenderNodeAnimator> > mAnimators;
/**
* Draw time state - these properties are only set and used during rendering
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index 8957607..fc5994c 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -16,44 +16,51 @@
#ifndef TREEINFO_H
#define TREEINFO_H
-#include <cutils/compiler.h>
#include <utils/Timers.h>
-#include <utils/StrongPointer.h>
namespace android {
namespace uirenderer {
-class RenderPropertyAnimator;
+class BaseAnimator;
+class AnimationListener;
-class AnimationListener {
+class AnimationHook {
public:
- ANDROID_API virtual void onAnimationFinished(const sp<RenderPropertyAnimator>&) = 0;
+ virtual void callOnFinished(BaseAnimator* animator, AnimationListener* listener) = 0;
protected:
- ANDROID_API virtual ~AnimationListener() {}
+ ~AnimationHook() {}
};
struct TreeInfo {
// The defaults here should be safe for everyone but DrawFrameTask to use as-is.
TreeInfo()
- : hasFunctors(false)
- , prepareTextures(false)
- , performStagingPush(true)
- , frameTimeMs(0)
- , evaluateAnimations(false)
- , hasAnimations(false)
- , animationListener(0)
+ : frameTimeMs(0)
+ , animationHook(NULL)
+ , prepareTextures(false)
+ , performStagingPush(true)
+ , evaluateAnimations(false)
{}
- bool hasFunctors;
+ nsecs_t frameTimeMs;
+ AnimationHook* animationHook;
bool prepareTextures;
bool performStagingPush;
-
- // Animations
- nsecs_t frameTimeMs;
bool evaluateAnimations;
- // This is only updated if evaluateAnimations is true
- bool hasAnimations;
- AnimationListener* animationListener;
+
+ struct Out {
+ Out()
+ : hasFunctors(false)
+ , hasAnimations(false)
+ , requiresUiRedraw(false)
+ {}
+ bool hasFunctors;
+ // This is only updated if evaluateAnimations is true
+ bool hasAnimations;
+ // This is set to true if there is an animation that RenderThread cannot
+ // animate itself, such as if hasFunctors is true
+ // This is only set if hasAnimations is true
+ bool requiresUiRedraw;
+ } out;
// TODO: Damage calculations
};
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 63f4b95..5a23158 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -349,6 +349,8 @@
mDirtyRegionsEnabled = mGlobalContext->enableDirtyRegions(mEglSurface);
mHaveNewSurface = true;
makeCurrent();
+ } else {
+ mRenderThread.removeFrameCallback(this);
}
}
@@ -385,16 +387,30 @@
mCanvas->setViewport(width, height);
}
+void CanvasContext::setOpaque(bool opaque) {
+ mOpaque = opaque;
+}
+
void CanvasContext::makeCurrent() {
// TODO: Figure out why this workaround is needed, see b/13913604
// In the meantime this matches the behavior of GLRenderer, so it is not a regression
mHaveNewSurface |= mGlobalContext->makeCurrent(mEglSurface);
}
+void CanvasContext::prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters,
+ TreeInfo& info) {
+ LOG_ALWAYS_FATAL_IF(!mCanvas, "Cannot prepareDraw without a canvas!");
+ makeCurrent();
+
+ processLayerUpdates(layerUpdaters, info);
+ if (info.out.hasAnimations) {
+ // TODO: Uh... crap?
+ }
+ prepareTree(info);
+}
+
void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters,
TreeInfo& info) {
- LOG_ALWAYS_FATAL_IF(!mCanvas, "Cannot process layer updates without a canvas!");
- makeCurrent();
for (size_t i = 0; i < layerUpdaters->size(); i++) {
DeferredLayerUpdater* update = layerUpdaters->itemAt(i);
bool success = update->apply(info);
@@ -406,11 +422,19 @@
}
void CanvasContext::prepareTree(TreeInfo& info) {
+ mRenderThread.removeFrameCallback(this);
+
+ info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
mRootRenderNode->prepareTree(info);
- if (info.hasAnimations && !info.hasFunctors) {
- // TODO: Functors
- mRenderThread.postFrameCallback(this);
+ if (info.out.hasAnimations) {
+ if (info.out.hasFunctors) {
+ info.out.requiresUiRedraw = true;
+ } else if (!info.out.requiresUiRedraw) {
+ // If animationsNeedsRedraw is set don't bother posting for an RT anim
+ // as we will just end up fighting the UI thread.
+ mRenderThread.postFrameCallback(this);
+ }
}
}
@@ -449,12 +473,15 @@
}
// Called by choreographer to do an RT-driven animation
-void CanvasContext::doFrame(nsecs_t frameTimeNanos) {
+void CanvasContext::doFrame() {
+ if (CC_UNLIKELY(!mCanvas || mEglSurface == EGL_NO_SURFACE)) {
+ return;
+ }
+
ATRACE_CALL();
TreeInfo info;
info.evaluateAnimations = true;
- info.frameTimeMs = nanoseconds_to_milliseconds(frameTimeNanos);
info.performStagingPush = false;
info.prepareTextures = false;
@@ -469,10 +496,7 @@
requireGlContext();
mode = DrawGlInfo::kModeProcess;
}
- // TODO: Remove the dummy info in the future
- DrawGlInfo dummyInfo;
- memset(&dummyInfo, 0, sizeof(DrawGlInfo));
- (*functor)(mode, &dummyInfo);
+ (*functor)(mode, NULL);
if (mCanvas) {
mCanvas->resume();
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 0873ad4..dcb9858 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -52,14 +52,14 @@
void updateSurface(EGLNativeWindowType window);
void pauseSurface(EGLNativeWindowType window);
void setup(int width, int height);
+ void setOpaque(bool opaque);
void makeCurrent();
- void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
- void prepareTree(TreeInfo& info);
+ void prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
void draw(Rect* dirty);
void destroyCanvasAndSurface();
// IFrameCallback, Chroreographer-driven frame callback entry point
- virtual void doFrame(nsecs_t frameTimeNanos);
+ virtual void doFrame();
bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
@@ -71,6 +71,9 @@
Layer* createTextureLayer();
private:
+ void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
+ void prepareTree(TreeInfo& info);
+
void setSurface(EGLNativeWindowType window);
void swapBuffers();
void requireSurface();
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index ff4be71..3b8786c 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -30,13 +30,18 @@
namespace uirenderer {
namespace renderthread {
-DrawFrameTask::DrawFrameTask() : mContext(0) {
+DrawFrameTask::DrawFrameTask()
+ : mRenderThread(NULL)
+ , mContext(NULL)
+ , mFrameTimeNanos(0)
+ , mSyncResult(kSync_OK) {
}
DrawFrameTask::~DrawFrameTask() {
}
-void DrawFrameTask::setContext(CanvasContext* context) {
+void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context) {
+ mRenderThread = thread;
mContext = context;
}
@@ -59,18 +64,23 @@
mDirty.set(left, top, right, bottom);
}
-void DrawFrameTask::drawFrame(RenderThread* renderThread) {
+int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos) {
LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
- postAndWait(renderThread);
+ mSyncResult = kSync_OK;
+ mFrameTimeNanos = frameTimeNanos;
+ postAndWait();
// Reset the single-frame data
+ mFrameTimeNanos = 0;
mDirty.setEmpty();
+
+ return mSyncResult;
}
-void DrawFrameTask::postAndWait(RenderThread* renderThread) {
+void DrawFrameTask::postAndWait() {
AutoMutex _lock(mLock);
- renderThread->queue(this);
+ mRenderThread->queue(this);
mSignal.wait(mLock);
}
@@ -99,21 +109,25 @@
info.prepareTextures = true;
info.performStagingPush = true;
info.evaluateAnimations = true;
- // TODO: Get this from Choreographer
- nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC);
- info.frameTimeMs = nanoseconds_to_milliseconds(frameTimeNs);
}
bool DrawFrameTask::syncFrameState() {
ATRACE_CALL();
+ mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos);
mContext->makeCurrent();
Caches::getInstance().textureCache.resetMarkInUse();
TreeInfo info;
initTreeInfo(info);
- mContext->processLayerUpdates(&mLayers, info);
- mContext->prepareTree(info);
+ mContext->prepareDraw(&mLayers, info);
+ if (info.out.hasAnimations) {
+ // TODO: dirty calculations, for now just do a full-screen inval
+ mDirty.setEmpty();
+ if (info.out.requiresUiRedraw) {
+ mSyncResult |= kSync_UIRedrawRequired;
+ }
+ }
// If prepareTextures is false, we ran out of texture cache space
- return !info.hasFunctors && info.prepareTextures;
+ return !info.out.hasFunctors && info.prepareTextures;
}
void DrawFrameTask::unblockUiThread() {
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index c280868..b9307e1 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -37,6 +37,11 @@
class CanvasContext;
class RenderThread;
+enum SyncResult {
+ kSync_OK = 0,
+ kSync_UIRedrawRequired = 1 << 1,
+};
+
/*
* This is a special Super Task. It is re-used multiple times by RenderProxy,
* and contains state (such as layer updaters & new DisplayListDatas) that is
@@ -48,30 +53,34 @@
DrawFrameTask();
virtual ~DrawFrameTask();
- void setContext(CanvasContext* context);
+ void setContext(RenderThread* thread, CanvasContext* context);
void addLayer(DeferredLayerUpdater* layer);
void removeLayer(DeferredLayerUpdater* layer);
void setDirty(int left, int top, int right, int bottom);
- void drawFrame(RenderThread* renderThread);
+ int drawFrame(nsecs_t frameTimeNanos);
virtual void run();
private:
- void postAndWait(RenderThread* renderThread);
+ void postAndWait();
bool syncFrameState();
void unblockUiThread();
Mutex mLock;
Condition mSignal;
+ RenderThread* mRenderThread;
CanvasContext* mContext;
/*********************************************
* Single frame data
*********************************************/
Rect mDirty;
+ nsecs_t mFrameTimeNanos;
+
+ int mSyncResult;
/*********************************************
* Multi frame data
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 87886e6..82a2dbc 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -62,7 +62,7 @@
args->translucent = translucent;
args->rootRenderNode = rootRenderNode;
mContext = (CanvasContext*) postAndWait(task);
- mDrawFrameTask.setContext(mContext);
+ mDrawFrameTask.setContext(&mRenderThread, mContext);
}
RenderProxy::~RenderProxy() {
@@ -79,13 +79,38 @@
SETUP_TASK(destroyContext);
args->context = mContext;
mContext = 0;
- mDrawFrameTask.setContext(0);
+ mDrawFrameTask.setContext(NULL, NULL);
// This is also a fence as we need to be certain that there are no
// outstanding mDrawFrame tasks posted before it is destroyed
postAndWait(task);
}
}
+CREATE_BRIDGE2(setFrameInterval, RenderThread* thread, nsecs_t frameIntervalNanos) {
+ args->thread->timeLord().setFrameInterval(args->frameIntervalNanos);
+ return NULL;
+}
+
+void RenderProxy::setFrameInterval(nsecs_t frameIntervalNanos) {
+ SETUP_TASK(setFrameInterval);
+ args->thread = &mRenderThread;
+ args->frameIntervalNanos = frameIntervalNanos;
+ post(task);
+}
+
+CREATE_BRIDGE0(loadSystemProperties) {
+ bool needsRedraw = false;
+ if (Caches::hasInstance()) {
+ needsRedraw = Caches::getInstance().initProperties();
+ }
+ return (void*) needsRedraw;
+}
+
+bool RenderProxy::loadSystemProperties() {
+ SETUP_TASK(loadSystemProperties);
+ return (bool) postAndWait(task);
+}
+
CREATE_BRIDGE2(initialize, CanvasContext* context, EGLNativeWindowType window) {
return (void*) args->context->initialize(args->window);
}
@@ -134,10 +159,22 @@
post(task);
}
-void RenderProxy::syncAndDrawFrame(
+CREATE_BRIDGE2(setOpaque, CanvasContext* context, bool opaque) {
+ args->context->setOpaque(args->opaque);
+ return NULL;
+}
+
+void RenderProxy::setOpaque(bool opaque) {
+ SETUP_TASK(setOpaque);
+ args->context = mContext;
+ args->opaque = opaque;
+ post(task);
+}
+
+int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos,
int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) {
mDrawFrameTask.setDirty(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
- mDrawFrameTask.drawFrame(&mRenderThread);
+ return mDrawFrameTask.drawFrame(frameTimeNanos);
}
CREATE_BRIDGE1(destroyCanvasAndSurface, CanvasContext* context) {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index eab1395..4a7e70a 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -25,6 +25,7 @@
#include <utils/Condition.h>
#include <utils/Functor.h>
#include <utils/Mutex.h>
+#include <utils/Timers.h>
#include <utils/StrongPointer.h>
#include <utils/Vector.h>
@@ -59,11 +60,15 @@
ANDROID_API RenderProxy(bool translucent, RenderNode* rootNode);
ANDROID_API virtual ~RenderProxy();
+ ANDROID_API void setFrameInterval(nsecs_t frameIntervalNanos);
+ ANDROID_API bool loadSystemProperties();
+
ANDROID_API bool initialize(const sp<ANativeWindow>& window);
ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
ANDROID_API void pauseSurface(const sp<ANativeWindow>& window);
ANDROID_API void setup(int width, int height);
- ANDROID_API void syncAndDrawFrame(
+ ANDROID_API void setOpaque(bool opaque);
+ ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos,
int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
ANDROID_API void destroyCanvasAndSurface();
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index e95707a..35a3eab 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -129,8 +129,7 @@
, mDisplayEventReceiver(0)
, mVsyncRequested(false)
, mFrameCallbackTaskPending(false)
- , mFrameCallbackTask(0)
- , mFrameTime(0) {
+ , mFrameCallbackTask(0) {
mFrameCallbackTask = new DispatchFrameCallbacks(this);
mLooper = new Looper(false);
run("RenderThread");
@@ -193,7 +192,7 @@
nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver);
if (vsyncEvent > 0) {
mVsyncRequested = false;
- mFrameTime = vsyncEvent;
+ mTimeLord.vsyncReceived(vsyncEvent);
if (!mFrameCallbackTaskPending) {
mFrameCallbackTaskPending = true;
//queueDelayed(mFrameCallbackTask, DISPATCH_FRAME_CALLBACKS_DELAY);
@@ -209,7 +208,7 @@
mFrameCallbacks.swap(callbacks);
for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) {
- (*it)->doFrame(mFrameTime);
+ (*it)->doFrame();
}
}
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index b93dfd6..215d294 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -28,6 +28,8 @@
#include <utils/Singleton.h>
#include <utils/Thread.h>
+#include "TimeLord.h"
+
namespace android {
class DisplayEventReceiver;
@@ -53,7 +55,7 @@
// Mimics android.view.Choreographer.FrameCallback
class IFrameCallback {
public:
- virtual void doFrame(nsecs_t frameTimeNanos) = 0;
+ virtual void doFrame() = 0;
protected:
~IFrameCallback() {}
@@ -71,6 +73,8 @@
void postFrameCallback(IFrameCallback* callback);
void removeFrameCallback(IFrameCallback* callback);
+ TimeLord& timeLord() { return mTimeLord; }
+
protected:
virtual bool threadLoop();
@@ -102,7 +106,8 @@
std::set<IFrameCallback*> mFrameCallbacks;
bool mFrameCallbackTaskPending;
DispatchFrameCallbacks* mFrameCallbackTask;
- nsecs_t mFrameTime;
+
+ TimeLord mTimeLord;
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp
new file mode 100644
index 0000000..758d96e
--- /dev/null
+++ b/libs/hwui/renderthread/TimeLord.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 "TimeLord.h"
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+TimeLord::TimeLord()
+ : mFrameIntervalNanos(0)
+ , mFrameTimeNanos(0) {
+}
+
+void TimeLord::vsyncReceived(nsecs_t vsync) {
+ if (vsync > mFrameTimeNanos) {
+ mFrameTimeNanos = vsync;
+ }
+}
+
+nsecs_t TimeLord::frameTimeMs() {
+ // Logic copied from Choreographer.java
+ nsecs_t now = systemTime(CLOCK_MONOTONIC);
+ nsecs_t jitterNanos = now - mFrameTimeNanos;
+ if (jitterNanos >= mFrameIntervalNanos) {
+ nsecs_t lastFrameOffset = jitterNanos % mFrameIntervalNanos;
+ mFrameTimeNanos = now - lastFrameOffset;
+ }
+ return nanoseconds_to_milliseconds(mFrameTimeNanos);
+}
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/TimeLord.h b/libs/hwui/renderthread/TimeLord.h
new file mode 100644
index 0000000..52c6d9ef
--- /dev/null
+++ b/libs/hwui/renderthread/TimeLord.h
@@ -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.
+ */
+#ifndef TIMELORD_H
+#define TIMELORD_H
+
+#include <utils/Timers.h>
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+class RenderThread;
+
+// This class serves as a helper to filter & manage frame times from multiple sources
+// ensuring that time flows linearly and smoothly
+class TimeLord {
+public:
+ void setFrameInterval(nsecs_t intervalNanos) { mFrameIntervalNanos = intervalNanos; }
+ void vsyncReceived(nsecs_t vsync);
+ nsecs_t frameTimeMs();
+
+private:
+ friend class RenderThread;
+
+ TimeLord();
+ ~TimeLord() {}
+
+ nsecs_t mFrameIntervalNanos;
+ nsecs_t mFrameTimeNanos;
+};
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* TIMELORD_H */
diff --git a/core/res/res/drawable/stat_sys_adb.xml b/libs/hwui/utils/Macros.h
similarity index 61%
copy from core/res/res/drawable/stat_sys_adb.xml
copy to libs/hwui/utils/Macros.h
index dfc8563..14a3ec0 100644
--- a/core/res/res/drawable/stat_sys_adb.xml
+++ b/libs/hwui/utils/Macros.h
@@ -1,13 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
/*
- * Copyright 2013, 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.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,9 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
--->
+#ifndef MACROS_H
+#define MACROS_H
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/stat_sys_adb_am"
- android:autoMirrored="true">
-</bitmap>
+#define PREVENT_COPY_AND_ASSIGN(Type) \
+ private: \
+ Type(const Type&); \
+ void operator=(const Type&)
+
+
+#endif /* MACROS_H */
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index ad0d459..6b2a247 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -32,11 +32,13 @@
/** Default audio data format */
public static final int ENCODING_DEFAULT = 1;
- // These two values must be kept in sync with core/jni/android_media_AudioFormat.h
+ // These values must be kept in sync with core/jni/android_media_AudioFormat.h
/** Audio data format: PCM 16 bit per sample. Guaranteed to be supported by devices. */
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 */
+ public static final int ENCODING_PCM_FLOAT = 4;
/** Invalid audio channel configuration */
/** @deprecated use CHANNEL_INVALID instead */
@@ -139,4 +141,19 @@
public static final int CHANNEL_IN_FRONT_BACK = CHANNEL_IN_FRONT | CHANNEL_IN_BACK;
// CHANNEL_IN_ALL is not yet defined; if added then it should match AUDIO_CHANNEL_IN_ALL
+ /** @hide */
+ public static int getBytesPerSample(int audioFormat)
+ {
+ switch (audioFormat) {
+ case ENCODING_PCM_8BIT:
+ return 1;
+ case ENCODING_PCM_16BIT:
+ case ENCODING_DEFAULT:
+ return 2;
+ case ENCODING_INVALID:
+ default:
+ throw new IllegalArgumentException("Bad audio format " + audioFormat);
+ }
+ }
+
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 8ae06e0..1dcfcb8 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -25,6 +25,7 @@
import android.content.Context;
import android.content.Intent;
import android.media.RemoteController.OnClientUpdateListener;
+import android.media.session.MediaSessionLegacyHelper;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -48,6 +49,12 @@
*/
public class AudioManager {
+ // If we should use the new sessions APIs.
+ private final static boolean USE_SESSIONS = true;
+ // If we should use the legacy APIs. If both are true information will be
+ // duplicated through both paths. Currently this flag isn't used.
+ private final static boolean USE_LEGACY = true;
+
private final Context mContext;
private long mVolumeKeyUpTime;
private final boolean mUseMasterVolume;
@@ -421,6 +428,7 @@
public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
private static IAudioService sService;
+ private MediaSessionLegacyHelper mSessionHelper;
/**
* @hide
@@ -431,6 +439,9 @@
com.android.internal.R.bool.config_useMasterVolume);
mUseVolumeKeySounds = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_useVolumeKeySounds);
+ if (USE_SESSIONS) {
+ mSessionHelper = MediaSessionLegacyHelper.getHelper(context);
+ }
}
private static IAudioService getService()
@@ -2166,6 +2177,9 @@
} catch (RemoteException e) {
Log.e(TAG, "Dead object in registerMediaButtonIntent"+e);
}
+ if (USE_SESSIONS) {
+ mSessionHelper.addMediaButtonListener(pi, mContext);
+ }
}
/**
@@ -2239,6 +2253,9 @@
} catch (RemoteException e) {
Log.e(TAG, "Dead object in unregisterMediaButtonIntent"+e);
}
+ if (USE_SESSIONS) {
+ mSessionHelper.removeMediaButtonListener(pi);
+ }
}
/**
@@ -2263,6 +2280,9 @@
} catch (RemoteException e) {
Log.e(TAG, "Dead object in registerRemoteControlClient"+e);
}
+ if (USE_SESSIONS) {
+ rcClient.registerWithSession(mSessionHelper);
+ }
}
/**
@@ -2282,6 +2302,9 @@
} catch (RemoteException e) {
Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e);
}
+ if (USE_SESSIONS) {
+ rcClient.unregisterWithSession(mSessionHelper);
+ }
}
/**
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index a4891f8..384e120 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -319,7 +319,7 @@
// NB: this section is only valid with PCM data.
// To update when supporting compressed formats
int frameSizeInBytes = mChannelCount
- * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
+ * (AudioFormat.getBytesPerSample(mAudioFormat));
if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
throw new IllegalArgumentException("Invalid audio buffer size.");
}
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 4513ead..0c8a823 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -1787,6 +1787,11 @@
/** @see AudioManager#playSoundEffect(int, float) */
public void playSoundEffectVolume(int effectType, float volume) {
+ if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
+ Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
+ return;
+ }
+
sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
effectType, (int) (volume * 1000), null, 0);
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 17840f2..1899685 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -518,7 +518,7 @@
// NB: this section is only valid with PCM data.
// To update when supporting compressed formats
int frameSizeInBytes = mChannelCount
- * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
+ * (AudioFormat.getBytesPerSample(mAudioFormat));
if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
throw new IllegalArgumentException("Invalid audio buffer size.");
}
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index bd91fc5..7735e78 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -169,9 +169,11 @@
native_setup(new WeakReference<JetPlayer>(this),
JetPlayer.getMaxTracks(),
- // bytes to frame conversion: sample format is ENCODING_PCM_16BIT, 2 channels
+ // bytes to frame conversion:
// 1200 == minimum buffer size in frames on generation 1 hardware
- Math.max(1200, buffSizeInBytes / 4));
+ Math.max(1200, buffSizeInBytes /
+ (AudioFormat.getBytesPerSample(AudioFormat.ENCODING_PCM_16BIT) *
+ 2 /*channels*/)));
}
}
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index eb91668..d3b1520 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -28,9 +28,12 @@
import java.net.URL;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
+import java.net.NoRouteToHostException;
import java.util.HashMap;
import java.util.Map;
+import static android.media.MediaPlayer.MEDIA_ERROR_UNSUPPORTED;
+
/** @hide */
public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
private static final String TAG = "MediaHTTPConnection";
@@ -43,6 +46,12 @@
private long mTotalSize = -1;
private InputStream mInputStream = null;
+ private boolean mAllowCrossDomainRedirect = true;
+
+ // from com.squareup.okhttp.internal.http
+ private final static int HTTP_TEMP_REDIRECT = 307;
+ private final static int MAX_REDIRECTS = 20;
+
public MediaHTTPConnection() {
if (CookieHandler.getDefault() == null) {
CookieHandler.setDefault(new CookieManager());
@@ -59,6 +68,7 @@
try {
disconnect();
+ mAllowCrossDomainRedirect = true;
mURL = new URL(uri);
mHeaders = convertHeaderStringToMap(headers);
} catch (MalformedURLException e) {
@@ -68,6 +78,25 @@
return native_getIMemory();
}
+ private boolean parseBoolean(String val) {
+ try {
+ return Long.parseLong(val) != 0;
+ } catch (NumberFormatException e) {
+ return "true".equalsIgnoreCase(val) ||
+ "yes".equalsIgnoreCase(val);
+ }
+ }
+
+ /* returns true iff header is internal */
+ private boolean filterOutInternalHeaders(String key, String val) {
+ if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) {
+ mAllowCrossDomainRedirect = parseBoolean(val);
+ } else {
+ return false;
+ }
+ return true;
+ }
+
private Map<String, String> convertHeaderStringToMap(String headers) {
HashMap<String, String> map = new HashMap<String, String>();
@@ -78,7 +107,9 @@
String key = pair.substring(0, colonPos);
String val = pair.substring(colonPos + 1);
- map.put(key, val);
+ if (!filterOutInternalHeaders(key, val)) {
+ map.put(key, val);
+ }
}
}
@@ -107,24 +138,75 @@
teardownConnection();
try {
- mConnection = (HttpURLConnection)mURL.openConnection();
+ int response;
+ int redirectCount = 0;
- if (mHeaders != null) {
- for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
+ URL url = mURL;
+ while (true) {
+ mConnection = (HttpURLConnection)url.openConnection();
+ // handle redirects ourselves if we do not allow cross-domain redirect
+ mConnection.setInstanceFollowRedirects(mAllowCrossDomainRedirect);
+
+ if (mHeaders != null) {
+ for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
+ mConnection.setRequestProperty(
+ entry.getKey(), entry.getValue());
+ }
+ }
+
+ if (offset > 0) {
mConnection.setRequestProperty(
- entry.getKey(), entry.getValue());
+ "Range", "bytes=" + offset + "-");
+ }
+
+ response = mConnection.getResponseCode();
+ if (response != HttpURLConnection.HTTP_MULT_CHOICE &&
+ response != HttpURLConnection.HTTP_MOVED_PERM &&
+ response != HttpURLConnection.HTTP_MOVED_TEMP &&
+ response != HttpURLConnection.HTTP_SEE_OTHER &&
+ response != HTTP_TEMP_REDIRECT) {
+ // not a redirect, or redirect handled by HttpURLConnection
+ break;
+ }
+
+ if (++redirectCount > MAX_REDIRECTS) {
+ throw new NoRouteToHostException("Too many redirects: " + redirectCount);
+ }
+
+ String method = mConnection.getRequestMethod();
+ if (response == HTTP_TEMP_REDIRECT &&
+ !method.equals("GET") && !method.equals("HEAD")) {
+ // "If the 307 status code is received in response to a
+ // request other than GET or HEAD, the user agent MUST NOT
+ // automatically redirect the request"
+ throw new NoRouteToHostException("Invalid redirect");
+ }
+ String location = mConnection.getHeaderField("Location");
+ if (location == null) {
+ throw new NoRouteToHostException("Invalid redirect");
+ }
+ url = new URL(mURL /* TRICKY: don't use url! */, location);
+ if (!url.getProtocol().equals("https") &&
+ !url.getProtocol().equals("http")) {
+ throw new NoRouteToHostException("Unsupported protocol redirect");
+ }
+ boolean sameHost = mURL.getHost().equals(url.getHost());
+ if (!sameHost) {
+ throw new NoRouteToHostException("Cross-domain redirects are disallowed");
+ }
+
+ if (response != HTTP_TEMP_REDIRECT) {
+ // update effective URL, unless it is a Temporary Redirect
+ mURL = url;
}
}
- if (offset > 0) {
- mConnection.setRequestProperty(
- "Range", "bytes=" + offset + "-");
+ if (mAllowCrossDomainRedirect) {
+ // remember the current, potentially redirected URL if redirects
+ // were handled by HttpURLConnection
+ mURL = mConnection.getURL();
}
- int response = mConnection.getResponseCode();
- // remember the current, possibly redirected URL
- mURL = mConnection.getURL();
-
if (response == HttpURLConnection.HTTP_PARTIAL) {
// Partial content, we cannot just use getContentLength
// because what we want is not just the length of the range
@@ -207,6 +289,9 @@
}
return n;
+ } catch (NoRouteToHostException e) {
+ Log.w(TAG, "readAt " + offset + " / " + size + " => " + e);
+ return MEDIA_ERROR_UNSUPPORTED;
} catch (IOException e) {
if (VERBOSE) {
Log.d(TAG, "readAt " + offset + " / " + size + " => -1");
diff --git a/media/java/android/media/MediaMetadataEditor.java b/media/java/android/media/MediaMetadataEditor.java
index 3bfdb5a..1a4e8da 100644
--- a/media/java/android/media/MediaMetadataEditor.java
+++ b/media/java/android/media/MediaMetadataEditor.java
@@ -17,6 +17,7 @@
package android.media;
import android.graphics.Bitmap;
+import android.media.session.MediaMetadata;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
@@ -106,6 +107,10 @@
*/
protected Bundle mEditorMetadata;
+ /**
+ * @hide
+ */
+ protected MediaMetadata.Builder mMetadataBuilder;
/**
* Clears all the pending metadata changes set since the MediaMetadataEditor instance was
@@ -120,6 +125,7 @@
}
mEditorMetadata.clear();
mEditorArtwork = null;
+ mMetadataBuilder = new MediaMetadata.Builder();
}
/**
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index c2c61d3..8368df94 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -24,6 +24,11 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
+import android.media.session.MediaMetadata;
+import android.media.session.MediaSessionLegacyHelper;
+import android.media.session.PlaybackState;
+import android.media.session.Session;
+import android.media.session.TransportPerformer;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -336,6 +341,8 @@
*/
public final static int FLAG_INFORMATION_REQUEST_ALBUM_ART = 1 << 3;
+ private Session mSession;
+
/**
* Class constructor.
* @param mediaButtonIntent The intent that will be sent for the media button events sent
@@ -385,6 +392,22 @@
}
/**
+ * @hide
+ */
+ public void registerWithSession(MediaSessionLegacyHelper helper) {
+ helper.addRccListener(mRcMediaIntent, mTransportListener);
+ mSession = helper.getSession(mRcMediaIntent);
+ }
+
+ /**
+ * @hide
+ */
+ public void unregisterWithSession(MediaSessionLegacyHelper helper) {
+ helper.removeRccListener(mRcMediaIntent);
+ mSession = null;
+ }
+
+ /**
* Class used to modify metadata in a {@link RemoteControlClient} object.
* Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor,
* on which you set the metadata for the RemoteControlClient instance. Once all the information
@@ -438,6 +461,15 @@
public synchronized MetadataEditor putString(int key, String value)
throws IllegalArgumentException {
super.putString(key, value);
+ if (mMetadataBuilder != null) {
+ // MediaMetadata supports all the same fields as MetadataEditor
+ String metadataKey = MediaMetadata.getKeyFromMetadataEditorKey(key);
+ // But just in case, don't add things we don't understand
+ if (metadataKey != null) {
+ mMetadataBuilder.putString(metadataKey, value);
+ }
+ }
+
return this;
}
@@ -459,6 +491,14 @@
public synchronized MetadataEditor putLong(int key, long value)
throws IllegalArgumentException {
super.putLong(key, value);
+ if (mMetadataBuilder != null) {
+ // MediaMetadata supports all the same fields as MetadataEditor
+ String metadataKey = MediaMetadata.getKeyFromMetadataEditorKey(key);
+ // But just in case, don't add things we don't understand
+ if (metadataKey != null) {
+ mMetadataBuilder.putLong(metadataKey, value);
+ }
+ }
return this;
}
@@ -476,6 +516,14 @@
public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap)
throws IllegalArgumentException {
super.putBitmap(key, bitmap);
+ if (mMetadataBuilder != null) {
+ // MediaMetadata supports all the same fields as MetadataEditor
+ String metadataKey = MediaMetadata.getKeyFromMetadataEditorKey(key);
+ // But just in case, don't add things we don't understand
+ if (metadataKey != null) {
+ mMetadataBuilder.putBitmap(metadataKey, bitmap);
+ }
+ }
return this;
}
@@ -501,7 +549,7 @@
Log.e(TAG, "Can't apply a previously applied MetadataEditor");
return;
}
- synchronized(mCacheLock) {
+ synchronized (mCacheLock) {
// assign the edited data
mMetadata = new Bundle(mEditorMetadata);
// add the information about editable keys
@@ -521,6 +569,11 @@
// send to remote control display if conditions are met
sendArtwork_syncCacheLock(null, 0, 0);
}
+
+ // USE_SESSIONS
+ if (mSession != null && mMetadataBuilder != null) {
+ mSession.getTransportPerformer().setMetadata(mMetadataBuilder.build());
+ }
mApplied = true;
}
}
@@ -546,6 +599,12 @@
editor.mMetadataChanged = false;
editor.mArtworkChanged = false;
}
+ // USE_SESSIONS
+ if (startEmpty || mMediaMetadata == null) {
+ editor.mMetadataBuilder = new MediaMetadata.Builder();
+ } else {
+ editor.mMetadataBuilder = new MediaMetadata.Builder(mMediaMetadata);
+ }
return editor;
}
@@ -624,6 +683,15 @@
// handle automatic playback position refreshes
initiateCheckForDrift_syncCacheLock();
+
+ // USE_SESSIONS
+ if (mSession != null) {
+ int pbState = PlaybackState.getStateFromRccState(state);
+ mSessionPlaybackState.setState(pbState, hasPosition ?
+ mPlaybackPositionMs : PlaybackState.PLAYBACK_POSITION_UNKNOWN,
+ playbackSpeed);
+ mSession.getTransportPerformer().setPlaybackState(mSessionPlaybackState);
+ }
}
}
}
@@ -704,6 +772,13 @@
// send to remote control display if conditions are met
sendTransportControlInfo_syncCacheLock(null);
+
+ // USE_SESSIONS
+ if (mSession != null) {
+ mSessionPlaybackState.setActions(PlaybackState
+ .getActionsFromRccControlFlags(transportControlFlags));
+ mSession.getTransportPerformer().setPlaybackState(mSessionPlaybackState);
+ }
}
}
@@ -1038,6 +1113,16 @@
private boolean mNeedsPositionSync = false;
/**
+ * Cache for the current playback state using Session APIs.
+ */
+ private final PlaybackState mSessionPlaybackState = new PlaybackState();
+
+ /**
+ * Cache for metadata using Session APIs. This is re-initialized in apply().
+ */
+ private MediaMetadata mMediaMetadata;
+
+ /**
* A class to encapsulate all the information about a remote control display.
* A RemoteControlClient's metadata and state may be displayed on multiple IRemoteControlDisplay
*/
@@ -1219,6 +1304,26 @@
return mRcseId;
}
+ // USE_SESSIONS
+ private TransportPerformer.Listener mTransportListener = new TransportPerformer.Listener() {
+
+ @Override
+ public void onSeekTo(long pos) {
+ RemoteControlClient.this.onSeekTo(mCurrentClientGenId, pos);
+ }
+
+ @Override
+ public void onRate(Rating rating) {
+ if ((mTransportControlFlags & FLAG_KEY_MEDIA_RATING) != 0) {
+ if (mEventHandler != null) {
+ mEventHandler.sendMessage(mEventHandler.obtainMessage(
+ MSG_UPDATE_METADATA, mCurrentClientGenId,
+ MetadataEditor.RATING_KEY_BY_USER, rating));
+ }
+ }
+ }
+ };
+
private EventHandler mEventHandler;
private final static int MSG_REQUEST_PLAYBACK_STATE = 1;
private final static int MSG_REQUEST_METADATA = 2;
@@ -1325,7 +1430,7 @@
// target == null implies all displays must be updated
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+ final DisplayInfoForClient di = displayIterator.next();
if (di.mEnabled) {
try {
di.mRcDisplay.setPlaybackState(mInternalClientGenId,
@@ -1353,7 +1458,7 @@
// target == null implies all displays must be updated
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+ final DisplayInfoForClient di = displayIterator.next();
if (di.mEnabled) {
try {
di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
@@ -1381,7 +1486,7 @@
// target == null implies all displays must be updated
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+ final DisplayInfoForClient di = displayIterator.next();
if (di.mEnabled) {
try {
di.mRcDisplay.setTransportControlInfo(mInternalClientGenId,
@@ -1407,7 +1512,7 @@
// target == null implies all displays must be updated
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
- if (!sendArtworkToDisplay((DisplayInfoForClient) displayIterator.next())) {
+ if (!sendArtworkToDisplay(displayIterator.next())) {
displayIterator.remove();
}
}
@@ -1453,7 +1558,7 @@
// target == null implies all displays must be updated
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+ final DisplayInfoForClient di = displayIterator.next();
try {
if (di.mEnabled) {
if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) {
@@ -1537,7 +1642,7 @@
boolean displayKnown = false;
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext() && !displayKnown) {
- final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+ final DisplayInfoForClient di = displayIterator.next();
displayKnown = di.mRcDisplay.asBinder().equals(rcd.asBinder());
if (displayKnown) {
// this display was known but the change in artwork size will cause the
@@ -1562,7 +1667,7 @@
synchronized(mCacheLock) {
Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+ final DisplayInfoForClient di = displayIterator.next();
if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
displayIterator.remove();
break;
@@ -1573,7 +1678,7 @@
boolean newNeedsPositionSync = false;
displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+ final DisplayInfoForClient di = displayIterator.next();
if (di.mWantsPositionSync) {
newNeedsPositionSync = true;
break;
@@ -1592,7 +1697,7 @@
synchronized(mCacheLock) {
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+ final DisplayInfoForClient di = displayIterator.next();
if (di.mRcDisplay.asBinder().equals(rcd.asBinder()) &&
((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h))) {
di.mArtworkExpectedWidth = w;
@@ -1617,7 +1722,7 @@
// go through the list of RCDs and for each entry, check both whether this is the RCD
// that gets upated, and whether the list has one entry that wants position sync
while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+ final DisplayInfoForClient di = displayIterator.next();
if (di.mEnabled) {
if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
di.mWantsPositionSync = wantsSync;
@@ -1640,7 +1745,7 @@
synchronized(mCacheLock) {
final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+ final DisplayInfoForClient di = displayIterator.next();
if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
di.mEnabled = enable;
}
diff --git a/media/java/android/media/routeprovider/RouteRequest.java b/media/java/android/media/routeprovider/RouteRequest.java
index 9913566..68475c0 100644
--- a/media/java/android/media/routeprovider/RouteRequest.java
+++ b/media/java/android/media/routeprovider/RouteRequest.java
@@ -20,6 +20,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.io.PrintWriter;
+
/**
* A request to connect or discover routes with certain capabilities.
* <p>
@@ -70,6 +72,17 @@
}
@Override
+ public String toString() {
+ StringBuilder bob = new StringBuilder();
+ bob.append("RouteRequest {");
+ bob.append("active=").append(mActive);
+ bob.append(", info=").append(mSessionInfo.toString());
+ bob.append(", options=").append(mOptions.toString());
+ bob.append("}");
+ return bob.toString();
+ }
+
+ @Override
public int describeContents() {
return 0;
}
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index ca77f04..3ff07d9 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -31,8 +31,8 @@
interface ISession {
void sendEvent(String event, in Bundle data);
ISessionController getController();
- void setTransportPerformerEnabled();
- void publish();
+ void setFlags(int flags);
+ void setActive(boolean active);
void destroy();
// These commands are for setting up and communicating with routes
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 84b9a0f..7a8c22e 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -15,6 +15,7 @@
package android.media.session;
+import android.content.ComponentName;
import android.media.session.ISession;
import android.media.session.ISessionCallback;
import android.os.Bundle;
@@ -25,4 +26,5 @@
*/
interface ISessionManager {
ISession createSession(String packageName, in ISessionCallback cb, String tag);
+ List<IBinder> getSessions(in ComponentName compName);
}
\ No newline at end of file
diff --git a/media/java/android/media/session/MediaMetadata.java b/media/java/android/media/session/MediaMetadata.java
index e2330f7..8a8af45 100644
--- a/media/java/android/media/session/MediaMetadata.java
+++ b/media/java/android/media/session/MediaMetadata.java
@@ -16,12 +16,15 @@
package android.media.session;
import android.graphics.Bitmap;
+import android.media.MediaMetadataEditor;
+import android.media.MediaMetadataRetriever;
import android.media.Rating;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.SparseArray;
/**
* Contains metadata about an item, such as the title, artist, etc.
@@ -40,7 +43,8 @@
public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
/**
- * The duration of the media in ms. A duration of 0 is the default.
+ * The duration of the media in ms. A negative duration indicates that the
+ * duration is unknown (or infinite).
*/
public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
@@ -65,12 +69,17 @@
public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
/**
+ * The compilation status of the media.
+ */
+ public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+
+ /**
* The date the media was created or published as TODO determine format.
*/
public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
/**
- * The year the media was created or published as a numeric String.
+ * The year the media was created or published as a long.
*/
public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
@@ -151,8 +160,9 @@
METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_STRING);
METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_STRING);
METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_COMPILATION, METADATA_TYPE_STRING);
METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_STRING);
- METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_STRING);
+ METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_LONG);
METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_STRING);
METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG);
METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG);
@@ -165,6 +175,36 @@
METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING);
METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING);
}
+
+ private static final SparseArray<String> EDITOR_KEY_MAPPING;
+
+ static {
+ EDITOR_KEY_MAPPING = new SparseArray<String>();
+ EDITOR_KEY_MAPPING.put(MediaMetadataEditor.BITMAP_KEY_ARTWORK, METADATA_KEY_ART);
+ EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_OTHERS, METADATA_KEY_RATING);
+ EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_USER, METADATA_KEY_USER_RATING);
+ EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_KEY_ALBUM);
+ EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
+ METADATA_KEY_ALBUM_ARTIST);
+ EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_KEY_ARTIST);
+ EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_KEY_AUTHOR);
+ EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
+ METADATA_KEY_TRACK_NUMBER);
+ EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_KEY_COMPOSER);
+ EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPILATION,
+ METADATA_KEY_COMPILATION);
+ EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_KEY_DATE);
+ EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
+ METADATA_KEY_DISC_NUMBER);
+ EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_KEY_DURATION);
+ EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_KEY_GENRE);
+ EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS,
+ METADATA_KEY_NUM_TRACKS);
+ EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_KEY_TITLE);
+ EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_KEY_WRITER);
+ EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_KEY_YEAR);
+ }
+
private final Bundle mBundle;
private MediaMetadata(Bundle bundle) {
@@ -176,6 +216,16 @@
}
/**
+ * Returns true if the given key is contained in the metadata
+ *
+ * @param key a String key
+ * @return true if the key exists in this metadata, false otherwise
+ */
+ public boolean containsKey(String key) {
+ return mBundle.containsKey(key);
+ }
+
+ /**
* Returns the value associated with the given key, or null if no mapping of
* the desired type exists for the given key or a null value is explicitly
* associated with the key.
@@ -195,7 +245,7 @@
* @return a long value
*/
public long getLong(String key) {
- return mBundle.getLong(key);
+ return mBundle.getLong(key, 0);
}
/**
@@ -244,6 +294,27 @@
dest.writeBundle(mBundle);
}
+ /**
+ * Get the number of fields in this metadata.
+ *
+ * @return The number of fields in the metadata.
+ */
+ public int size() {
+ return mBundle.size();
+ }
+
+ /**
+ * Helper for getting the String key used by {@link MediaMetadata} from the
+ * integer key that {@link MediaMetadataEditor} uses.
+ *
+ * @param editorKey The key used by the editor
+ * @return The key used by this class or null if no mapping exists
+ * @hide
+ */
+ public static String getKeyFromMetadataEditorKey(int editorKey) {
+ return EDITOR_KEY_MAPPING.get(editorKey, null);
+ }
+
public static final Parcelable.Creator<MediaMetadata> CREATOR
= new Parcelable.Creator<MediaMetadata>() {
@Override
@@ -295,10 +366,9 @@
* <li>{@link #METADATA_KEY_WRITER}</li>
* <li>{@link #METADATA_KEY_COMPOSER}</li>
* <li>{@link #METADATA_KEY_DATE}</li>
- * <li>{@link #METADATA_KEY_YEAR}</li>
* <li>{@link #METADATA_KEY_GENRE}</li>
- * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>li>
- * <li>{@link #METADATA_KEY_ART_URI}</li>li>
+ * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
+ * <li>{@link #METADATA_KEY_ART_URI}</li>
* <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
* </ul>
*
@@ -326,6 +396,7 @@
* <li>{@link #METADATA_KEY_TRACK_NUMBER}</li>
* <li>{@link #METADATA_KEY_NUM_TRACKS}</li>
* <li>{@link #METADATA_KEY_DISC_NUMBER}</li>
+ * <li>{@link #METADATA_KEY_YEAR}</li>
* </ul>
*
* @param key The key for referencing this value
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
new file mode 100644
index 0000000..c07229d
--- /dev/null
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.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 android.media.session;
+
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.view.KeyEvent;
+
+/**
+ * Helper for connecting existing APIs up to the new session APIs. This can be
+ * used by RCC, AudioFocus, etc. to create a single session that translates to
+ * all those components.
+ *
+ * @hide
+ */
+public class MediaSessionLegacyHelper {
+ private static final String TAG = "MediaSessionHelper";
+
+ private static final Object sLock = new Object();
+ private static MediaSessionLegacyHelper sInstance;
+
+ private SessionManager mSessionManager;
+ private Handler mHandler = new Handler(Looper.getMainLooper());
+ // The legacy APIs use PendingIntents to register/unregister media button
+ // receivers and these are associated with RCC.
+ private ArrayMap<PendingIntent, SessionHolder> mSessions
+ = new ArrayMap<PendingIntent, SessionHolder>();
+
+ private MediaSessionLegacyHelper(Context context) {
+ mSessionManager = (SessionManager) context
+ .getSystemService(Context.MEDIA_SESSION_SERVICE);
+ }
+
+ public static MediaSessionLegacyHelper getHelper(Context context) {
+ synchronized (sLock) {
+ if (sInstance == null) {
+ sInstance = new MediaSessionLegacyHelper(context);
+ }
+ }
+ return sInstance;
+ }
+
+ public Session getSession(PendingIntent pi) {
+ SessionHolder holder = mSessions.get(pi);
+ return holder == null ? null : holder.mSession;
+ }
+
+ public void addRccListener(PendingIntent pi, TransportPerformer.Listener listener) {
+
+ SessionHolder holder = getHolder(pi, true);
+ TransportPerformer performer = holder.mSession.getTransportPerformer();
+ if (holder.mRccListener != null) {
+ if (holder.mRccListener == listener) {
+ // This is already the registered listener, ignore
+ return;
+ }
+ // Otherwise it changed so we need to switch to the new one
+ performer.removeListener(holder.mRccListener);
+ }
+ performer.addListener(listener, mHandler);
+ holder.mRccListener = listener;
+ holder.mFlags |= Session.FLAG_HANDLES_TRANSPORT_CONTROLS;
+ holder.mSession.setFlags(holder.mFlags);
+ holder.update();
+ }
+
+ public void removeRccListener(PendingIntent pi) {
+ SessionHolder holder = getHolder(pi, false);
+ if (holder != null && holder.mRccListener != null) {
+ holder.mSession.getTransportPerformer().removeListener(holder.mRccListener);
+ holder.mRccListener = null;
+ holder.mFlags &= ~Session.FLAG_HANDLES_TRANSPORT_CONTROLS;
+ holder.mSession.setFlags(holder.mFlags);
+ holder.update();
+ }
+ }
+
+ public void addMediaButtonListener(PendingIntent pi,
+ Context context) {
+ SessionHolder holder = getHolder(pi, true);
+ if (holder.mMediaButtonListener != null) {
+ // Already have this listener registered
+ return;
+ }
+ holder.mMediaButtonListener = new MediaButtonListener(pi, context);
+ holder.mFlags |= Session.FLAG_HANDLES_MEDIA_BUTTONS;
+ holder.mSession.setFlags(holder.mFlags);
+ holder.mSession.getTransportPerformer().addListener(holder.mMediaButtonListener, mHandler);
+ }
+
+ public void removeMediaButtonListener(PendingIntent pi) {
+ SessionHolder holder = getHolder(pi, false);
+ if (holder != null && holder.mMediaButtonListener != null) {
+ holder.mSession.getTransportPerformer().removeListener(holder.mMediaButtonListener);
+ holder.mFlags &= ~Session.FLAG_HANDLES_MEDIA_BUTTONS;
+ holder.mSession.setFlags(holder.mFlags);
+ holder.mMediaButtonListener = null;
+ holder.update();
+ }
+ }
+
+ private SessionHolder getHolder(PendingIntent pi, boolean createIfMissing) {
+ SessionHolder holder = mSessions.get(pi);
+ if (holder == null && createIfMissing) {
+ Session session = mSessionManager.createSession(TAG);
+ session.setActive(true);
+ holder = new SessionHolder(session, pi);
+ mSessions.put(pi, holder);
+ }
+ return holder;
+ }
+
+ public static class MediaButtonListener extends TransportPerformer.Listener {
+ private final PendingIntent mPendingIntent;
+ private final Context mContext;
+
+ public MediaButtonListener(PendingIntent pi, Context context) {
+ mPendingIntent = pi;
+ mContext = context;
+ }
+
+ @Override
+ public void onPlay() {
+ sendKeyEvent(KeyEvent.KEYCODE_MEDIA_PLAY);
+ }
+
+ @Override
+ public void onPause() {
+ sendKeyEvent(KeyEvent.KEYCODE_MEDIA_PAUSE);
+ }
+
+ @Override
+ public void onNext() {
+ sendKeyEvent(KeyEvent.KEYCODE_MEDIA_NEXT);
+ }
+
+ @Override
+ public void onPrevious() {
+ sendKeyEvent(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
+ }
+
+ @Override
+ public void onFastForward() {
+ sendKeyEvent(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD);
+ }
+
+ @Override
+ public void onRewind() {
+ sendKeyEvent(KeyEvent.KEYCODE_MEDIA_REWIND);
+ }
+
+ @Override
+ public void onStop() {
+ sendKeyEvent(KeyEvent.KEYCODE_MEDIA_STOP);
+ }
+
+ private void sendKeyEvent(int keyCode) {
+ KeyEvent ke = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
+ Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+
+ intent.putExtra(Intent.EXTRA_KEY_EVENT, ke);
+ try {
+ mPendingIntent.send(mContext, 0, intent);
+ } catch (CanceledException e) {
+ Log.e(TAG, "Error sending media key down event:", e);
+ // Don't bother sending up if down failed
+ return;
+ }
+
+ ke = new KeyEvent(KeyEvent.ACTION_UP, keyCode);
+ intent.putExtra(Intent.EXTRA_KEY_EVENT, ke);
+ try {
+ mPendingIntent.send(mContext, 0, intent);
+ } catch (CanceledException e) {
+ Log.e(TAG, "Error sending media key up event:", e);
+ }
+ }
+ }
+
+ private class SessionHolder {
+ public final Session mSession;
+ public final PendingIntent mPi;
+ public MediaButtonListener mMediaButtonListener;
+ public TransportPerformer.Listener mRccListener;
+ public int mFlags;
+
+ public SessionHolder(Session session, PendingIntent pi) {
+ mSession = session;
+ mPi = pi;
+ }
+
+ public void update() {
+ if (mMediaButtonListener == null && mRccListener == null) {
+ mSession.release();
+ mSessions.remove(mPi);
+ } else if (mMediaButtonListener != null && mRccListener != null) {
+ // TODO set session to active
+ } else {
+ // TODO set session to inactive
+ }
+ }
+ }
+}
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 14d9fb1..3254e5d 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -15,8 +15,10 @@
*/
package android.media.session;
+import android.media.RemoteControlClient;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemClock;
/**
* Playback state for a {@link Session}. This includes a state like
@@ -88,6 +90,13 @@
public static final long ACTION_SEEK_TO = 1 << 8;
/**
+ * Indicates this performer supports the play/pause toggle command.
+ *
+ * @see #setActions
+ */
+ public static final long ACTION_PLAY_PAUSE = 1 << 9;
+
+ /**
* This is the default playback state and indicates that no media has been
* added yet, or the performer has been reset and has no content to play.
*
@@ -154,12 +163,32 @@
*/
public final static int PLAYSTATE_CONNECTING = 8;
+ /**
+ * State indicating the player is currently skipping to the previous item.
+ *
+ * @see #setState
+ */
+ public final static int PLAYSTATE_SKIPPING_BACKWARDS = 9;
+
+ /**
+ * State indicating the player is currently skipping to the next item.
+ *
+ * @see #setState
+ */
+ public final static int PLAYSTATE_SKIPPING_FORWARDS = 10;
+
+ /**
+ * Use this value for the position to indicate the position is not known.
+ */
+ public final static long PLAYBACK_POSITION_UNKNOWN = -1;
+
private int mState;
private long mPosition;
private long mBufferPosition;
- private float mSpeed;
- private long mCapabilities;
+ private float mRate;
+ private long mActions;
private String mErrorMessage;
+ private long mUpdateTime;
/**
* Create an empty PlaybackState. At minimum a state and actions should be
@@ -175,21 +204,38 @@
* @param from The PlaybackState to duplicate
*/
public PlaybackState(PlaybackState from) {
- this.setState(from.getState());
- this.setPosition(from.getPosition());
- this.setBufferPosition(from.getBufferPosition());
- this.setSpeed(from.getSpeed());
- this.setActions(from.getActions());
- this.setErrorMessage(from.getErrorMessage());
+ mState = from.mState;
+ mPosition = from.mPosition;
+ mRate = from.mRate;
+ mUpdateTime = from.mUpdateTime;
+ mBufferPosition = from.mBufferPosition;
+ mActions = from.mActions;
+ mErrorMessage = from.mErrorMessage;
}
private PlaybackState(Parcel in) {
- this.setState(in.readInt());
- this.setPosition(in.readLong());
- this.setBufferPosition(in.readLong());
- this.setSpeed(in.readFloat());
- this.setActions(in.readLong());
- this.setErrorMessage(in.readString());
+ mState = in.readInt();
+ mPosition = in.readLong();
+ mRate = in.readFloat();
+ mUpdateTime = in.readLong();
+ mBufferPosition = in.readLong();
+ mActions = in.readLong();
+ mErrorMessage = in.readString();
+
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder bob = new StringBuilder("PlaybackState {");
+ bob.append("state=").append(mState);
+ bob.append(", position=").append(mPosition);
+ bob.append(", buffered position=").append(mBufferPosition);
+ bob.append(", rate=").append(mRate);
+ bob.append(", updated=").append(mUpdateTime);
+ bob.append(", actions=").append(mActions);
+ bob.append(", error=").append(mErrorMessage);
+ bob.append("}");
+ return bob.toString();
}
@Override
@@ -199,12 +245,13 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(getState());
- dest.writeLong(getPosition());
- dest.writeLong(getBufferPosition());
- dest.writeFloat(getSpeed());
- dest.writeLong(getActions());
- dest.writeString(getErrorMessage());
+ dest.writeInt(mState);
+ dest.writeLong(mPosition);
+ dest.writeFloat(mRate);
+ dest.writeLong(mUpdateTime);
+ dest.writeLong(mBufferPosition);
+ dest.writeLong(mActions);
+ dest.writeString(mErrorMessage);
}
/**
@@ -224,7 +271,16 @@
}
/**
- * Set the current state of playback. One of the following:
+ * Set the current state of playback.
+ * <p>
+ * The position must be in ms and indicates the current playback position
+ * within the track. If the position is unknown use
+ * {@link #PLAYBACK_POSITION_UNKNOWN}.
+ * <p>
+ * The rate is a multiple of normal playback and should be 0 when paused and
+ * negative when rewinding. Normal playback rate is 1.0.
+ * <p>
+ * The state must be one of the following:
* <ul>
* <li> {@link PlaybackState#PLAYSTATE_NONE}</li>
* <li> {@link PlaybackState#PLAYSTATE_STOPPED}</li>
@@ -234,9 +290,18 @@
* <li> {@link PlaybackState#PLAYSTATE_REWINDING}</li>
* <li> {@link PlaybackState#PLAYSTATE_BUFFERING}</li>
* <li> {@link PlaybackState#PLAYSTATE_ERROR}</li>
+ * </ul>
+ *
+ * @param state The current state of playback.
+ * @param position The position in the current track in ms.
+ * @param rate The current rate of playback as a multiple of normal
+ * playback.
*/
- public void setState(int mState) {
- this.mState = mState;
+ public void setState(int state, long position, float rate) {
+ this.mState = state;
+ this.mPosition = position;
+ this.mRate = rate;
+ mUpdateTime = SystemClock.elapsedRealtime();
}
/**
@@ -247,13 +312,6 @@
}
/**
- * Set the current playback position in ms.
- */
- public void setPosition(long position) {
- mPosition = position;
- }
-
- /**
* Get the current buffer position in ms. This is the farthest playback
* point that can be reached from the current position using only buffered
* content.
@@ -272,21 +330,14 @@
}
/**
- * Get the current playback speed as a multiple of normal playback. This
+ * Get the current playback rate as a multiple of normal playback. This
* should be negative when rewinding. A value of 1 means normal playback and
* 0 means paused.
+ *
+ * @return The current rate of playback.
*/
- public float getSpeed() {
- return mSpeed;
- }
-
- /**
- * Set the current playback speed as a multiple of normal playback. This
- * should be negative when rewinding. A value of 1 means normal playback and
- * 0 means paused.
- */
- public void setSpeed(float speed) {
- mSpeed = speed;
+ public float getRate() {
+ return mRate;
}
/**
@@ -305,7 +356,7 @@
* </ul>
*/
public long getActions() {
- return mCapabilities;
+ return mActions;
}
/**
@@ -324,7 +375,7 @@
* </ul>
*/
public void setActions(long capabilities) {
- mCapabilities = capabilities;
+ mActions = capabilities;
}
/**
@@ -336,6 +387,17 @@
}
/**
+ * Get the elapsed real time at which position was last updated. If the
+ * position has never been set this will return 0;
+ *
+ * @return The last time the position was updated.
+ * @hide
+ */
+ public long getLastPositionUpdateTime() {
+ return mUpdateTime;
+ }
+
+ /**
* Set a user readable error message. This should be set when the state is
* {@link PlaybackState#PLAYSTATE_ERROR}.
*/
@@ -343,6 +405,80 @@
mErrorMessage = errorMessage;
}
+ /**
+ * Get the {@link PlaybackState} state for the given
+ * {@link RemoteControlClient} state.
+ *
+ * @param rccState The state used by {@link RemoteControlClient}.
+ * @return The equivalent state used by {@link PlaybackState}.
+ * @hide
+ */
+ public static int getStateFromRccState(int rccState) {
+ switch (rccState) {
+ case RemoteControlClient.PLAYSTATE_BUFFERING:
+ return PLAYSTATE_BUFFERING;
+ case RemoteControlClient.PLAYSTATE_ERROR:
+ return PLAYSTATE_ERROR;
+ case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
+ return PLAYSTATE_FAST_FORWARDING;
+ case RemoteControlClient.PLAYSTATE_NONE:
+ return PLAYSTATE_NONE;
+ case RemoteControlClient.PLAYSTATE_PAUSED:
+ return PLAYSTATE_PAUSED;
+ case RemoteControlClient.PLAYSTATE_PLAYING:
+ return PLAYSTATE_PLAYING;
+ case RemoteControlClient.PLAYSTATE_REWINDING:
+ return PLAYSTATE_REWINDING;
+ case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
+ return PLAYSTATE_SKIPPING_BACKWARDS;
+ case RemoteControlClient.PLAYSTATE_STOPPED:
+ return PLAYSTATE_STOPPED;
+ default:
+ return -1;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static long getActionsFromRccControlFlags(int rccFlags) {
+ long actions = 0;
+ long flag = 1;
+ while (flag <= rccFlags) {
+ if ((flag & rccFlags) != 0) {
+ actions |= getActionForRccFlag((int) flag);
+ }
+ flag = flag << 1;
+ }
+ return actions;
+ }
+
+ private static long getActionForRccFlag(int flag) {
+ switch (flag) {
+ case RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS:
+ return ACTION_PREVIOUS_ITEM;
+ case RemoteControlClient.FLAG_KEY_MEDIA_REWIND:
+ return ACTION_REWIND;
+ case RemoteControlClient.FLAG_KEY_MEDIA_PLAY:
+ return ACTION_PLAY;
+ case RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE:
+ return ACTION_PLAY_PAUSE;
+ case RemoteControlClient.FLAG_KEY_MEDIA_PAUSE:
+ return ACTION_PAUSE;
+ case RemoteControlClient.FLAG_KEY_MEDIA_STOP:
+ return ACTION_STOP;
+ case RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD:
+ return ACTION_FASTFORWARD;
+ case RemoteControlClient.FLAG_KEY_MEDIA_NEXT:
+ return ACTION_NEXT_ITEM;
+ case RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE:
+ return ACTION_SEEK_TO;
+ case RemoteControlClient.FLAG_KEY_MEDIA_RATING:
+ return ACTION_RATING;
+ }
+ return 0;
+ }
+
public static final Parcelable.Creator<PlaybackState> CREATOR
= new Parcelable.Creator<PlaybackState>() {
@Override
diff --git a/media/java/android/media/session/Session.java b/media/java/android/media/session/Session.java
index 8ccd788..194679e7 100644
--- a/media/java/android/media/session/Session.java
+++ b/media/java/android/media/session/Session.java
@@ -45,12 +45,13 @@
* media to multiple routes or to provide finer grain controls of media.
* <p>
* A MediaSession is created by calling
- * {@link SessionManager#createSession(String)}. Once a session is created
- * apps that have the MEDIA_CONTENT_CONTROL permission can interact with the
- * session through {@link SessionManager#getActiveSessions()}. The owner of
- * the session may also use {@link #getSessionToken()} to allow apps without
- * this permission to create a {@link SessionController} to interact with this
- * session.
+ * {@link SessionManager#createSession(String)}. Once a session is created apps
+ * that have the MEDIA_CONTENT_CONTROL permission can interact with the session
+ * through
+ * {@link SessionManager#getActiveSessions(android.content.ComponentName)}. The
+ * owner of the session may also use {@link #getSessionToken()} to allow apps
+ * without this permission to create a {@link SessionController} to interact
+ * with this session.
* <p>
* To receive commands, media keys, and other events a Callback must be set with
* {@link #addCallback(Callback)}.
@@ -63,6 +64,28 @@
public final class Session {
private static final String TAG = "Session";
+ /**
+ * Set this flag on the session to indicate that it can handle media button
+ * events.
+ */
+ public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1 << 0;
+
+ /**
+ * Set this flag on the session to indicate that it handles commands through
+ * the {@link TransportPerformer}. The performer can be retrieved by calling
+ * {@link #getTransportPerformer()}.
+ */
+ public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
+
+ /**
+ * System only flag for a session that needs to have priority over all other
+ * sessions. This flag ensures this session will receive media button events
+ * regardless of the current ordering in the system.
+ *
+ * @hide
+ */
+ public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 1 << 16;
+
private static final int MSG_MEDIA_BUTTON = 1;
private static final int MSG_COMMAND = 2;
private static final int MSG_ROUTE_CHANGE = 3;
@@ -86,7 +109,7 @@
private TransportPerformer mPerformer;
private Route mRoute;
- private boolean mPublished = false;;
+ private boolean mActive = false;;
/**
* @hide
@@ -101,6 +124,7 @@
throw new RuntimeException("Dead object in MediaSessionController constructor: ", e);
}
mSessionToken = new SessionToken(controllerBinder);
+ mPerformer = new TransportPerformer(mBinder);
}
/**
@@ -148,56 +172,57 @@
}
/**
- * Start using a TransportPerformer with this media session. This must be
- * called before calling publish and cannot be called more than once.
- * Calling this will allow MediaControllers to retrieve a
- * TransportController.
+ * Retrieves the {@link TransportPerformer} for this session. To receive
+ * commands through the performer you must also set the
+ * {@link #FLAG_HANDLES_TRANSPORT_CONTROLS} flag using
+ * {@link #setFlags(int)}.
*
- * @see TransportController
- * @return The TransportPerformer created for this session
- */
- public TransportPerformer setTransportPerformerEnabled() {
- if (mPerformer != null) {
- throw new IllegalStateException("setTransportPerformer can only be called once.");
- }
- if (mPublished) {
- throw new IllegalStateException("setTransportPerformer cannot be called after publish");
- }
-
- mPerformer = new TransportPerformer(mBinder);
- try {
- mBinder.setTransportPerformerEnabled();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failure in setTransportPerformerEnabled.", e);
- }
- return mPerformer;
- }
-
- /**
- * Retrieves the TransportPerformer used by this session. If called before
- * {@link #setTransportPerformerEnabled} null will be returned.
- *
- * @return The TransportPerformer associated with this session or null
+ * @return The performer associated with this session.
*/
public TransportPerformer getTransportPerformer() {
return mPerformer;
}
/**
- * Call after you have finished setting up the session. This will make it
- * available to listeners and begin pushing updates to MediaControllers.
- * This can only be called once.
+ * Set any flags for the session.
+ *
+ * @param flags The flags to set for this session.
*/
- public void publish() {
- if (mPublished) {
- throw new RuntimeException("publish() may only be called once.");
+ public void setFlags(int flags) {
+ try {
+ mBinder.setFlags(flags);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Failure in setFlags.", e);
+ }
+ }
+
+ /**
+ * Set if this session is currently active and ready to receive commands. If
+ * set to false your session's controller may not be discoverable. You must
+ * set the session to active before it can start receiving media button
+ * events or transport commands.
+ *
+ * @param active Whether this session is active or not.
+ */
+ public void setActive(boolean active) {
+ if (mActive == active) {
+ return;
}
try {
- mBinder.publish();
+ mBinder.setActive(active);
+ mActive = active;
} catch (RemoteException e) {
- Log.wtf(TAG, "Failure in publish.", e);
+ Log.wtf(TAG, "Failure in setActive.", e);
}
- mPublished = true;
+ }
+
+ /**
+ * Get the current active state of this session.
+ *
+ * @return True if the session is active, false otherwise.
+ */
+ public boolean isActive() {
+ return mActive;
}
/**
diff --git a/media/java/android/media/session/SessionInfo.java b/media/java/android/media/session/SessionInfo.java
index 22d8ab1..2b65528 100644
--- a/media/java/android/media/session/SessionInfo.java
+++ b/media/java/android/media/session/SessionInfo.java
@@ -57,6 +57,11 @@
}
@Override
+ public String toString() {
+ return "SessionInfo {id=" + mId + ", pkg=" + mPackageName + "}";
+ }
+
+ @Override
public int describeContents() {
return 0;
}
diff --git a/media/java/android/media/session/SessionManager.java b/media/java/android/media/session/SessionManager.java
index 15bf0e3..fd022fc 100644
--- a/media/java/android/media/session/SessionManager.java
+++ b/media/java/android/media/session/SessionManager.java
@@ -16,11 +16,13 @@
package android.media.session;
+import android.content.ComponentName;
import android.content.Context;
import android.media.session.ISessionManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.service.notification.NotificationListenerService;
import android.util.Log;
import java.util.ArrayList;
@@ -79,12 +81,27 @@
/**
* Get a list of controllers for all ongoing sessions. This requires the
* android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by
- * the calling app.
+ * the calling app. You may also retrieve this list if your app is an
+ * enabled notification listener using the
+ * {@link NotificationListenerService} APIs, in which case you must pass the
+ * {@link ComponentName} of your enabled listener.
*
- * @return a list of controllers for ongoing sessions
+ * @param notificationListener The enabled notification listener component.
+ * May be null.
+ * @return A list of controllers for ongoing sessions
*/
- public List<SessionController> getActiveSessions() {
- // TODO
- return new ArrayList<SessionController>();
+ public List<SessionController> getActiveSessions(ComponentName notificationListener) {
+ ArrayList<SessionController> controllers = new ArrayList<SessionController>();
+ try {
+ List<IBinder> binders = mService.getSessions(notificationListener);
+ for (int i = binders.size() - 1; i >= 0; i--) {
+ SessionController controller = SessionController.fromBinder(ISessionController.Stub
+ .asInterface(binders.get(i)));
+ controllers.add(controller);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get active sessions: ", e);
+ }
+ return controllers;
}
}
diff --git a/media/java/android/media/session/TransportPerformer.java b/media/java/android/media/session/TransportPerformer.java
index eddffd1..187f48d 100644
--- a/media/java/android/media/session/TransportPerformer.java
+++ b/media/java/android/media/session/TransportPerformer.java
@@ -280,18 +280,11 @@
/**
* Report that audio focus has changed on the app. This only happens if
* you have indicated you have started playing with
- * {@link #setPlaybackState}. TODO figure out route focus apis/handling.
+ * {@link #setPlaybackState}.
*
- * @param focusChange The type of focus change, TBD. The default
- * implementation will deliver a call to {@link #onPause}
- * when focus is lost.
+ * @param focusChange The type of focus change, TBD.
*/
public void onRouteFocusChange(int focusChange) {
- switch (focusChange) {
- case AudioManager.AUDIOFOCUS_LOSS:
- onPause();
- break;
- }
}
}
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index abebd48..6f42057 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -648,7 +648,7 @@
return;
}
- clazz = env->FindClass("android/net/ProxyProperties");
+ clazz = env->FindClass("android/net/ProxyInfo");
if (clazz == NULL) {
return;
}
@@ -660,7 +660,7 @@
env->GetMethodID(clazz, "getPort", "()I");
fields.proxyConfigGetExclusionList =
- env->GetMethodID(clazz, "getExclusionList", "()Ljava/lang/String;");
+ env->GetMethodID(clazz, "getExclusionListAsString", "()Ljava/lang/String;");
}
static void
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index 492fde7..af7c282 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -29,7 +29,7 @@
<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="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/Keyguard/res/layout/keyguard_bouncer.xml b/packages/Keyguard/res/layout/keyguard_bouncer.xml
index 8716ebc..975a139 100644
--- a/packages/Keyguard/res/layout/keyguard_bouncer.xml
+++ b/packages/Keyguard/res/layout/keyguard_bouncer.xml
@@ -19,7 +19,7 @@
android:layout_height="match_parent">
<View android:id="@+id/bouncer_background"
- android:background="#aa000000"
+ android:background="#cc000000"
android:clickable="true"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
diff --git a/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml b/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml
index 0e2b33a..e167817 100644
--- a/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_sim_pin_view.xml
@@ -92,7 +92,7 @@
>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key1"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -101,7 +101,7 @@
/>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key2"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -110,7 +110,7 @@
/>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key3"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -126,7 +126,7 @@
>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key4"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -135,7 +135,7 @@
/>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key5"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -144,7 +144,7 @@
/>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key6"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -160,7 +160,7 @@
>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key7"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -169,7 +169,7 @@
/>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key8"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -178,7 +178,7 @@
/>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key9"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -199,7 +199,7 @@
/>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key0"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -208,7 +208,7 @@
/>
<ImageButton
android:id="@+id/key_enter"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
diff --git a/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml b/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml
index 88049a7..ac798ca 100644
--- a/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_sim_puk_view.xml
@@ -93,7 +93,7 @@
>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key1"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -102,7 +102,7 @@
/>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key2"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -111,7 +111,7 @@
/>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key3"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -127,7 +127,7 @@
>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key4"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -136,7 +136,7 @@
/>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key5"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -145,7 +145,7 @@
/>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key6"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -161,7 +161,7 @@
>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key7"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -170,7 +170,7 @@
/>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key8"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -179,7 +179,7 @@
/>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key9"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -200,7 +200,7 @@
/>
<view class="com.android.keyguard.NumPadKey"
android:id="@+id/key0"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -209,7 +209,7 @@
/>
<ImageButton
android:id="@+id/key_enter"
- style="@style/Widget.Button.NumPadKey"
+ style="@style/Widget.Button.NumPadKey.Sim"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
diff --git a/packages/Keyguard/res/values/styles.xml b/packages/Keyguard/res/values/styles.xml
index b54ac50..5ab00d2 100644
--- a/packages/Keyguard/res/values/styles.xml
+++ b/packages/Keyguard/res/values/styles.xml
@@ -33,6 +33,10 @@
<item name="android:paddingLeft">20dp</item>
<item name="android:paddingRight">6dp</item>
</style>
+ <style name="Widget.Button.NumPadKey.Sim" >
+ <item name="android:paddingTop">3dp</item>
+ <item name="android:paddingBottom">4dp</item>
+ </style>
<style name="TextAppearance.NumPadKey"
parent="@android:style/TextAppearance">
<item name="android:textSize">34dp</item>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 862931e..7be4cec 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -168,9 +168,9 @@
/**
* Called when the screen turns off
- * @param why {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER},
- * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or
- * {@link WindowManagerPolicy#OFF_BECAUSE_OF_PROX_SENSOR}.
+ * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_ADMIN},
+ * {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER}, or
+ * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}.
*/
public void onScreenTurnedOff(int why) { }
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 327df8d..6b62c25 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -98,6 +98,9 @@
<uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
<uses-permission android:name="android.permission.TRUST_LISTENER" />
+ <!-- Recents -->
+ <uses-permission android:name="android.permission.BIND_APPWIDGET" />
+
<!-- Wifi Display -->
<uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
@@ -138,7 +141,7 @@
android:exported="true" />
<receiver android:name=".BootReceiver" androidprv:primaryUserOnly="true">
- <intent-filter>
+ <intent-filter android:priority="1000">
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_camera_alt_24dp.png b/packages/SystemUI/res/drawable-hdpi/ic_camera_alt_24dp.png
new file mode 100644
index 0000000..253c73792
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_camera_alt_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_ime_switcher_default.png b/packages/SystemUI/res/drawable-hdpi/ic_ime_switcher_default.png
new file mode 100644
index 0000000..369c88d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_ime_switcher_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-hdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..c779437
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_phone_24dp.png b/packages/SystemUI/res/drawable-hdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..a6a6448
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_phone_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png
deleted file mode 100644
index c6f03c4..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_camera.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_camera_alt_24dp.png b/packages/SystemUI/res/drawable-mdpi/ic_camera_alt_24dp.png
new file mode 100644
index 0000000..ee1187b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_camera_alt_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_ime_switcher_default.png b/packages/SystemUI/res/drawable-mdpi/ic_ime_switcher_default.png
new file mode 100644
index 0000000..7d97eb5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_ime_switcher_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-mdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..98ba690
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_phone_24dp.png b/packages/SystemUI/res/drawable-mdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..2286bb4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_phone_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png
deleted file mode 100644
index 1c2d7aa..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_camera.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_camera_alt_24dp.png b/packages/SystemUI/res/drawable-xhdpi/ic_camera_alt_24dp.png
new file mode 100644
index 0000000..268eba0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_camera_alt_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_ime_switcher_default.png b/packages/SystemUI/res/drawable-xhdpi/ic_ime_switcher_default.png
new file mode 100644
index 0000000..900801a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_ime_switcher_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-xhdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..61947ea
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_phone_24dp.png b/packages/SystemUI/res/drawable-xhdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..cd9ff60
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_phone_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png
deleted file mode 100644
index fbd4d6b..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_camera.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_camera_alt_24dp.png b/packages/SystemUI/res/drawable-xxhdpi/ic_camera_alt_24dp.png
new file mode 100644
index 0000000..9175118
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_camera_alt_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_ime_switcher_default.png b/packages/SystemUI/res/drawable-xxhdpi/ic_ime_switcher_default.png
new file mode 100644
index 0000000..6c8222e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_ime_switcher_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-xxhdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..0b563b1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_phone_24dp.png b/packages/SystemUI/res/drawable-xxhdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..3c546e5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_phone_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png
deleted file mode 100644
index 86df881..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_camera.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_camera_alt_24dp.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_camera_alt_24dp.png
new file mode 100644
index 0000000..20e26b8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_camera_alt_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..3600ee6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_phone_24dp.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_phone_24dp.png
new file mode 100644
index 0000000..4f7da0a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_phone_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml b/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
index aa7256b..5f12706 100644
--- a/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-ldrtl/navigation_bar.xml
@@ -43,7 +43,7 @@
<!-- navigation controls -->
<View
- android:layout_width="40dp"
+ android:layout_width="@dimen/navigation_extra_key_width"
android:layout_height="match_parent"
android:layout_weight="0"
android:visibility="invisible"
@@ -88,16 +88,29 @@
systemui:glowBackground="@drawable/ic_sysbar_highlight"
android:contentDescription="@string/accessibility_recent"
/>
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
- android:layout_width="@dimen/navigation_menu_key_width"
+ <FrameLayout
+ android:layout_width="@dimen/navigation_extra_key_width"
android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_menu"
- systemui:keyCode="82"
- android:layout_weight="0"
- android:visibility="invisible"
- android:contentDescription="@string/accessibility_menu"
- systemui:glowBackground="@drawable/ic_sysbar_highlight"
- />
+ android:layout_weight="0" >
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/menu"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:contentDescription="@string/accessibility_menu"
+ android:src="@drawable/ic_sysbar_menu"
+ android:visibility="invisible"
+ systemui:glowBackground="@drawable/ic_sysbar_highlight"
+ systemui:keyCode="82" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/ime_switcher"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:contentDescription="@string/accessibility_ime_switch_button"
+ android:scaleType="centerInside"
+ android:src="@drawable/ic_ime_switcher_default"
+ android:visibility="invisible"
+ systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+ </FrameLayout>
</LinearLayout>
<!-- lights out layout to match exactly -->
@@ -187,16 +200,29 @@
>
<!-- navigation controls -->
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
- android:layout_height="40dp"
- android:layout_width="match_parent"
- android:src="@drawable/ic_sysbar_menu_land"
- systemui:keyCode="82"
- android:layout_weight="0"
- android:visibility="invisible"
- android:contentDescription="@string/accessibility_menu"
- systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
- />
+ <FrameLayout
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:layout_weight="0" >
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+ android:layout_height="@dimen/navigation_extra_key_width"
+ android:layout_width="match_parent"
+ android:src="@drawable/ic_sysbar_menu_land"
+ systemui:keyCode="82"
+ android:layout_weight="0"
+ android:visibility="invisible"
+ android:contentDescription="@string/accessibility_menu"
+ systemui:glowBackground="@drawable/ic_sysbar_highlight_land" />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/ime_switcher"
+ android:layout_height="@dimen/navigation_extra_key_width"
+ android:layout_width="match_parent"
+ android:contentDescription="@string/accessibility_ime_switch_button"
+ android:scaleType="centerInside"
+ android:src="@drawable/ic_ime_switcher_default"
+ android:visibility="invisible"
+ systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+ </FrameLayout>
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
android:layout_height="80dp"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout-sw600dp/heads_up.xml b/packages/SystemUI/res/layout-sw600dp/heads_up.xml
index 71f7c21..f7035fe 100644
--- a/packages/SystemUI/res/layout-sw600dp/heads_up.xml
+++ b/packages/SystemUI/res/layout-sw600dp/heads_up.xml
@@ -25,7 +25,6 @@
android:id="@+id/content_holder"
android:layout_height="wrap_content"
android:layout_width="@dimen/notification_panel_width"
- android:layout_marginStart="@dimen/notification_panel_margin_left"
android:background="@drawable/heads_up_window_bg"
/>
</com.android.systemui.statusbar.policy.HeadsUpNotificationView>
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
index b9ad799..6a2e3c6 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
@@ -42,7 +42,7 @@
<!-- navigation controls -->
<View
- android:layout_width="48dp"
+ android:layout_width="@dimen/navigation_extra_key_width"
android:layout_height="match_parent"
android:layout_weight="0"
android:layout_marginStart="2dp"
@@ -85,17 +85,32 @@
android:layout_height="match_parent"
android:layout_weight="1"
/>
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
- android:layout_width="48dp"
+ <FrameLayout
+ android:layout_width="@dimen/navigation_extra_key_width"
android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_menu"
- android:layout_marginEnd="2dp"
- systemui:keyCode="82"
android:layout_weight="0"
- android:visibility="invisible"
- android:contentDescription="@string/accessibility_menu"
- systemui:glowBackground="@drawable/ic_sysbar_highlight"
- />
+ android:layout_marginEnd="2dp" >
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_menu"
+ android:layout_marginEnd="2dp"
+ systemui:keyCode="82"
+ android:visibility="invisible"
+ android:contentDescription="@string/accessibility_menu"
+ systemui:glowBackground="@drawable/ic_sysbar_highlight"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/ime_switcher"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="2dp"
+ android:scaleType="centerInside"
+ android:src="@drawable/ic_ime_switcher_default"
+ android:visibility="invisible"
+ android:contentDescription="@string/accessibility_ime_switch_button"
+ systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+ </FrameLayout>
</LinearLayout>
<!-- lights out layout to match exactly -->
@@ -184,7 +199,7 @@
<!-- navigation controls -->
<View
- android:layout_width="48dp"
+ android:layout_width="@dimen/navigation_extra_key_width"
android:layout_height="match_parent"
android:layout_weight="0"
android:layout_marginStart="2dp"
@@ -227,17 +242,32 @@
android:layout_height="match_parent"
android:layout_weight="1"
/>
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
- android:layout_width="48dp"
+ <FrameLayout
+ android:layout_width="@dimen/navigation_extra_key_width"
android:layout_height="match_parent"
android:layout_marginEnd="2dp"
- android:src="@drawable/ic_sysbar_menu"
- systemui:keyCode="82"
- android:layout_weight="0"
- android:visibility="invisible"
- android:contentDescription="@string/accessibility_menu"
- systemui:glowBackground="@drawable/ic_sysbar_highlight"
- />
+ android:layout_weight="0" >
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="2dp"
+ android:src="@drawable/ic_sysbar_menu"
+ systemui:keyCode="82"
+ android:visibility="invisible"
+ android:contentDescription="@string/accessibility_menu"
+ systemui:glowBackground="@drawable/ic_sysbar_highlight"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/ime_switcher"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="2dp"
+ android:src="@drawable/ic_ime_switcher_default"
+ android:visibility="invisible"
+ android:contentDescription="@string/accessibility_ime_switch_button"
+ android:scaleType="centerInside"
+ systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+ </FrameLayout>
</LinearLayout>
<!-- lights out layout to match exactly -->
diff --git a/packages/SystemUI/res/layout/flip_settings.xml b/packages/SystemUI/res/layout/flip_settings.xml
index f3c1b90..28d9625 100644
--- a/packages/SystemUI/res/layout/flip_settings.xml
+++ b/packages/SystemUI/res/layout/flip_settings.xml
@@ -22,5 +22,4 @@
android:layout_height="wrap_content"
android:background="#5f000000"
android:animateLayoutChanges="true"
- android:visibility="gone"
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 3a58b84..e4954e7 100644
--- a/packages/SystemUI/res/layout/heads_up.xml
+++ b/packages/SystemUI/res/layout/heads_up.xml
@@ -22,6 +22,5 @@
android:layout_height="wrap_content"
android:layout_width="@dimen/notification_panel_width"
android:id="@+id/content_holder"
- android:layout_marginStart="@dimen/notification_panel_margin_left"
android:background="@drawable/notification_panel_bg"
/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 809adcd..194829d 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -22,15 +22,29 @@
android:layout_height="match_parent"
android:layout_width="match_parent"
>
- <com.android.systemui.statusbar.policy.KeyButtonView
+ <com.android.systemui.statusbar.phone.SwipeAffordanceView
android:id="@+id/camera_button"
- android:layout_height="80dp"
- android:layout_width="80dp"
- android:layout_gravity="bottom|right"
- android:src="@drawable/ic_sysbar_camera"
+ android:layout_height="64dp"
+ android:layout_width="64dp"
+ android:layout_gravity="bottom|end"
+ android:tint="#ffffffff"
+ android:src="@drawable/ic_camera_alt_24dp"
android:scaleType="center"
android:contentDescription="@string/accessibility_camera_button"
- systemui:glowBackground="@drawable/ic_sysbar_highlight_land" />
+ systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
+ systemui:swipeDirection="start"/>
+
+ <com.android.systemui.statusbar.phone.SwipeAffordanceView
+ android:id="@+id/phone_button"
+ android:layout_height="64dp"
+ android:layout_width="64dp"
+ android:layout_gravity="bottom|start"
+ android:tint="#ffffffff"
+ android:src="@drawable/ic_phone_24dp"
+ android:scaleType="center"
+ android:contentDescription="@string/accessibility_phone_button"
+ systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
+ systemui:swipeDirection="end"/>
<com.android.systemui.statusbar.phone.KeyguardIndicationTextView
android:id="@+id/keyguard_indication_text"
@@ -41,4 +55,14 @@
android:textStyle="italic"
android:textAppearance="?android:attr/textAppearanceMedium"/>
+ <ImageView
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_gravity="bottom|center_horizontal"
+ android:src="@drawable/ic_lock_24dp"
+ android:scaleType="center"
+ android:alpha="0.7"
+ android:layerType="hardware"
+ android:tint="#ffffffff"/>
+
</com.android.systemui.statusbar.phone.KeyguardBottomAreaView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index 2398849..7470409 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -88,16 +88,31 @@
systemui:glowBackground="@drawable/ic_sysbar_highlight"
android:contentDescription="@string/accessibility_recent"
/>
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
- android:layout_width="@dimen/navigation_menu_key_width"
+ <FrameLayout
+ android:layout_width="@dimen/navigation_extra_key_width"
android:layout_height="match_parent"
- android:src="@drawable/ic_sysbar_menu"
- systemui:keyCode="82"
- android:layout_weight="0"
- android:visibility="invisible"
- android:contentDescription="@string/accessibility_menu"
- systemui:glowBackground="@drawable/ic_sysbar_highlight"
- />
+ android:layout_weight="0" >
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/menu"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:contentDescription="@string/accessibility_menu"
+ android:src="@drawable/ic_sysbar_menu"
+ android:visibility="invisible"
+ systemui:glowBackground="@drawable/ic_sysbar_highlight"
+ systemui:keyCode="82" />
+
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/ime_switcher"
+ android:layout_width="@dimen/navigation_extra_key_width"
+ android:layout_height="match_parent"
+ android:contentDescription="@string/accessibility_ime_switch_button"
+ android:scaleType="centerInside"
+ android:src="@drawable/ic_ime_switcher_default"
+ android:visibility="invisible"
+ systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+ </FrameLayout>
+
</LinearLayout>
<!-- lights out layout to match exactly -->
@@ -190,18 +205,33 @@
android:id="@+id/nav_buttons"
android:animateLayoutChanges="true"
>
-
+
<!-- navigation controls -->
- <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
- android:layout_height="40dp"
- android:layout_width="match_parent"
- android:src="@drawable/ic_sysbar_menu_land"
- systemui:keyCode="82"
+ <FrameLayout
android:layout_weight="0"
- android:visibility="invisible"
- android:contentDescription="@string/accessibility_menu"
- systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
- />
+ android:layout_width="match_parent"
+ android:layout_height="40dp" >
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/ime_switcher"
+ android:layout_width="match_parent"
+ android:layout_height="40dp"
+ android:contentDescription="@string/accessibility_ime_switch_button"
+ android:scaleType="centerInside"
+ android:src="@drawable/ic_ime_switcher_default"
+ android:visibility="invisible"
+ systemui:glowBackground="@drawable/ic_sysbar_highlight" />
+
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/menu"
+ android:layout_width="match_parent"
+ android:layout_height="40dp"
+ android:contentDescription="@string/accessibility_menu"
+ android:src="@drawable/ic_sysbar_menu_land"
+ android:visibility="invisible"
+ systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
+ systemui:keyCode="82" />
+ </FrameLayout>
+
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
android:layout_height="80dp"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index ddc0dbf..f7df18eb 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -58,7 +58,7 @@
android:textSize="22sp"
android:textColor="#ffffffff"
android:text="@string/recents_empty_message"
- android:fontFamily="sans-serif-thin"
+ android:fontFamily="sans-serif-light"
android:singleLine="true"
android:maxLines="2"
android:ellipsize="marquee"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 761ad42..3267c36 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -23,9 +23,7 @@
xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:id="@+id/notification_panel"
android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/notification_panel_padding_top"
- android:layout_marginStart="@dimen/notification_panel_margin_left"
+ android:layout_height="match_parent"
>
<include
@@ -36,15 +34,6 @@
android:layout_gravity="bottom"
/>
- <include
- layout="@layout/status_bar_flip_button"
- android:id="@+id/keyguard_flipper"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:layout_gravity="right|top"
- android:layout_marginTop="@dimen/status_bar_height"
- android:visibility="gone" />
-
<com.android.keyguard.CarrierText
android:id="@+id/keyguard_carrier_text"
android:layout_width="wrap_content"
@@ -54,11 +43,6 @@
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceMedium" />
- <include layout="@layout/status_bar_expanded_header"
- android:layout_width="match_parent"
- android:layout_height="@dimen/notification_panel_header_height"
- />
-
<include
layout="@layout/keyguard_status_view"
android:layout_height="wrap_content"
@@ -74,27 +58,54 @@
android:visibility="gone"
/>
- <FrameLayout
+ <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
android:id="@+id/notification_container_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/close_handle_underlap"
- >
- <include
- layout="@layout/flip_settings"
- android:layout_marginTop="@dimen/notification_panel_header_height"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <com.android.systemui.statusbar.phone.ObservableScrollView
+ android:id="@+id/scroll_view"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- />
+ android:layout_height="match_parent"
+ android:visibility="invisible"
+ android:scrollbars="none"
+ android:fillViewport="true">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <include
+ layout="@layout/flip_settings"
+ android:layout_marginTop="@dimen/status_bar_header_height_expanded"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <!-- A view to reserve space for the collapsed stack -->
+ <View
+ android:layout_height="@dimen/collapsed_stack_height"
+ android:layout_width="match_parent"/>
+ </LinearLayout>
+ </com.android.systemui.statusbar.phone.ObservableScrollView>
+
<com.android.systemui.statusbar.stack.NotificationStackScrollLayout
android:id="@+id/notification_stack_scroller"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- />
- </FrameLayout>
+ android:layout_height="match_parent"
+ android:layout_marginBottom="@dimen/close_handle_underlap"/>
+
+ </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/keyguard_bottom_area"
android:visibility="gone" />
+
</com.android.systemui.statusbar.phone.NotificationPanelView><!-- end of sliding panel -->
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 8975728..460dd4b 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -15,21 +15,30 @@
** limitations under the License.
-->
-<LinearLayout
+<!-- Extends RelativeLayout -->
+<com.android.systemui.statusbar.phone.StatusBarHeaderView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:id="@+id/header"
android:layout_width="match_parent"
- android:layout_height="@dimen/notification_panel_header_height"
- android:background="@drawable/notification_header_bg"
+ android:layout_height="@dimen/status_bar_header_height"
android:orientation="horizontal"
android:gravity="center_vertical"
android:baselineAligned="false"
>
+
+ <View
+ android:id="@+id/background"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/notification_header_bg"
+ android:clickable="true"
+ />
<RelativeLayout
android:id="@+id/datetime"
android:layout_width="wrap_content"
android:layout_height="match_parent"
+ android:layout_gravity="start"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:background="@drawable/ic_notify_button_bg"
@@ -55,12 +64,6 @@
/>
</RelativeLayout>
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"
- />
-
<TextView
android:id="@+id/header_debug_info"
android:visibility="invisible"
@@ -74,18 +77,22 @@
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"
/>
- <include layout="@layout/status_bar_flip_button"
- android:id="@+id/header_flipper"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:layout_marginStart="12dp" />
-</LinearLayout>
+
+
+</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
index b7dff8c..f4d7033 100644
--- a/packages/SystemUI/res/layout/status_bar_flip_button.xml
+++ b/packages/SystemUI/res/layout/status_bar_flip_button.xml
@@ -15,22 +15,11 @@
~ limitations under the License
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="50dp"
- android:layout_height="50dp">
- <ImageView android:id="@+id/settings_button"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:scaleType="center"
- android:src="@drawable/ic_notify_settings"
- android:background="@drawable/ic_notify_button_bg"
- android:contentDescription="@string/accessibility_desc_quick_settings" />
- <ImageView android:id="@+id/notification_button"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:scaleType="center"
- android:src="@drawable/ic_notifications"
- android:background="@drawable/ic_notify_button_bg"
- android:visibility="gone"
- android:contentDescription="@string/accessibility_notifications_button" />
-</FrameLayout>
\ No newline at end of file
+<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_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
index 2e08bff..30eedee 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
@@ -18,7 +18,7 @@
<com.android.systemui.statusbar.NotificationOverflowContainer
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="32dp"
+ android:layout_height="40dp"
android:focusable="true"
android:clickable="true"
>
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 61d43d7..f9b022c 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -33,11 +33,10 @@
<com.android.systemui.statusbar.phone.PanelHolder
android:id="@+id/panel_holder"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginTop="@dimen/panel_holder_padding_top">
+ android:layout_height="match_parent" >
<include layout="@layout/status_bar_expanded"
android:layout_width="@dimen/notification_panel_width"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_gravity="start|top" />
</com.android.systemui.statusbar.phone.PanelHolder>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index d8a3114..8ec48c8 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -78,6 +78,8 @@
<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_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 9d1e036..7aaaaf3 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -78,6 +78,8 @@
<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_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 22a032a..1c06615 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -78,6 +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>
+ <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-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 00ac707..febcab6 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -78,6 +78,8 @@
<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_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 bfad5bc..658ece0 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -78,6 +78,8 @@
<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_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 94ba5c7..c7d2703 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -78,6 +78,8 @@
<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_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 df442ab..c740051 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -78,6 +78,7 @@
<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>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 3c4e0d3..40ecc49 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -78,6 +78,7 @@
<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>
@@ -222,6 +223,6 @@
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d mehr"</item>
</plurals>
- <string name="notification_tap_again" msgid="7590196980943943842">"Zum Öffnen erneut tippen"</string>
+ <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 6dcffcf..0e98ce0 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -78,6 +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>
+ <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-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 91a334a..f4098b7 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -78,6 +78,7 @@
<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>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 91a334a..f4098b7 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -78,6 +78,7 @@
<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>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 2150cbe..51198e6 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -78,6 +78,8 @@
<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_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 3424166..1b73e18 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -78,6 +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>
+ <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-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 8dbf9af..0f95c60 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -78,6 +78,8 @@
<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_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 b2ac990..f36d04b 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -78,6 +78,8 @@
<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_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 af0df4d..4ae3851 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -78,6 +78,8 @@
<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_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 f01c99a..c55a5fc 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -78,6 +78,8 @@
<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_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 5efbd2f..1121918 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -78,6 +78,8 @@
<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_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 e6d38ef..f9e6aad 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -78,6 +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>
+ <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-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index b777b8f..435f701 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -78,6 +78,7 @@
<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>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 10732fe..7685477 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -78,6 +78,7 @@
<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>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index f1c4869..7a8ab10 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -78,6 +78,8 @@
<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_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 f0b0713..cdb0816 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -78,6 +78,7 @@
<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>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 6a57682..401dbce 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -78,6 +78,7 @@
<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>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 3e87b76..08ffc54 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -78,6 +78,8 @@
<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_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 1edb630..2caa0693 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -78,6 +78,8 @@
<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_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 9d4344a..62e40d0 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -78,6 +78,8 @@
<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_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 bb2d3b9..35a6917 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -78,6 +78,8 @@
<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_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-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 83ffa9f..d7cd13b 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -78,6 +78,8 @@
<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_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-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 9a3d483..991fb66 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -78,6 +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>
+ <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-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 0e9f5b7..87087b4 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 leistuvę (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,6 +78,7 @@
<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>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index ca07095..04571e7 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -78,6 +78,7 @@
<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>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 4545301..3e7b660 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -78,6 +78,8 @@
<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_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 aa7e6eb..af50786 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -78,6 +78,8 @@
<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_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>
@@ -220,8 +222,6 @@
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d lagi"</item>
</plurals>
- <!-- no translation found for notification_tap_again (7590196980943943842) -->
- <skip />
- <!-- no translation found for keyguard_unlock (8043466894212841998) -->
- <skip />
+ <string name="notification_tap_again" msgid="7590196980943943842">"Ketik lagi untuk membuka"</string>
+ <string name="keyguard_unlock" msgid="8043466894212841998">"Leret ke atas untuk membuka kunci"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 001e733..9fa68b9 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -78,6 +78,7 @@
<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>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 8a6e33b..8cf16bf 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -78,6 +78,7 @@
<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>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 4862d1bc..e51341d 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -78,6 +78,8 @@
<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_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 012283a..11843b6 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -78,6 +78,7 @@
<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>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 0978d18..162d763 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -78,6 +78,8 @@
<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_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 25f643f..9f82651 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -126,6 +126,8 @@
<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) -->
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 6281110..75ba35b 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -78,6 +78,8 @@
<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_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>
@@ -220,8 +222,6 @@
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Încă %d"</item>
</plurals>
- <!-- no translation found for notification_tap_again (7590196980943943842) -->
- <skip />
- <!-- no translation found for keyguard_unlock (8043466894212841998) -->
- <skip />
+ <string name="notification_tap_again" msgid="7590196980943943842">"Atingeți din nou pentru a deschide"</string>
+ <string name="keyguard_unlock" msgid="8043466894212841998">"Glisați în sus pentru a debloca"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 976a793..6bdc6f4 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -78,6 +78,8 @@
<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_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 1224c3a..12c90ec 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -78,6 +78,8 @@
<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_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 10011bc..48d7727 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -78,6 +78,7 @@
<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>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 0c6a939..dba27a1 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -78,6 +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>
+ <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-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index d8bd1b1..0d58ed3 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -78,6 +78,7 @@
<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>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index d308b518..b626f78 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -76,6 +76,8 @@
<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_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-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
deleted file mode 100644
index c6c0719..0000000
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ /dev/null
@@ -1,22 +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.
-*/
--->
-<resources>
- <!-- Layout parameters for the notification panel -->
- <dimen name="notification_panel_margin_bottom">0dp</dimen>
- <dimen name="notification_panel_margin_left">32dp</dimen>
-</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 5b5587d..7372181 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -19,10 +19,6 @@
<!-- The width of the notification panel window: 446 + 16 + 16 (padding in the bg drawable) -->
<dimen name="notification_panel_width">478dp</dimen>
- <!-- Layout parameters for the notification panel -->
- <dimen name="notification_panel_margin_bottom">192dp</dimen>
- <dimen name="notification_panel_margin_left">16dp</dimen>
-
<!-- Gravity for the notification panel -->
<!-- 0x31 = top|center_horizontal -->
<integer name="notification_panel_layout_gravity">0x31</integer>
@@ -36,13 +32,13 @@
<!-- Height of search panel including navigation bar height -->
<dimen name="navbar_search_panel_height">280dip</dimen>
+ <!-- The width of the view containing the menu/ime navigation bar icons -->
+ <dimen name="navigation_extra_key_width">48dip</dimen>
+
<!-- Size of application thumbnail -->
<dimen name="status_bar_recents_thumbnail_width">200dp</dimen>
<dimen name="status_bar_recents_thumbnail_height">177dp</dimen>
- <!-- On tablets, panels drop from the statusbar instead of overlapping it. -->
- <dimen name="panel_holder_padding_top">@*android:dimen/status_bar_height</dimen>
-
<!-- Minimum fraction of the screen that should be taken up by the notification panel. -->
<item type="dimen" name="notification_panel_min_height_frac">40%</item>
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
index bf01a8d..7cf711a 100644
--- a/packages/SystemUI/res/values-sw720dp/config.xml
+++ b/packages/SystemUI/res/values-sw720dp/config.xml
@@ -32,5 +32,8 @@
<!-- Min alpha % that recent items will fade to while being dismissed -->
<integer name="config_recent_item_min_alpha">0</integer>
+
+ <!-- Transposes the search bar layout in landscape -->
+ <bool name="recents_transpose_search_layout_with_orientation">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index b1fc00a..a1c5b66 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -24,8 +24,6 @@
<!-- The width of the ticker, including the icon -->
<dimen name="notification_ticker_width">360dp</dimen>
- <!-- Status bar panel bottom offset (height of status bar - overlap) -->
- <dimen name="status_bar_panel_bottom_offset">36dp</dimen>
<!-- gap on either side of status bar notification icons -->
<dimen name="status_bar_icon_padding">1dp</dimen>
<!-- The width of the notification panel window -->
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 7929a30..6cb4a48 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -78,6 +78,8 @@
<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_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 92473a4..17e720e 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -78,6 +78,8 @@
<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_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 9837ff8..1bf033f5 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -78,6 +78,8 @@
<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_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 534f520..a5284ae 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -78,6 +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>
+ <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-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 56fc89c..8df2449 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -78,6 +78,8 @@
<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_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 442fdb7..8643ca8 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -78,6 +78,8 @@
<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_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 54a3b1e..9d93094 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -78,6 +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>
+ <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-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index fc74f53..07b7841 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -78,6 +78,8 @@
<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_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 dfe8838..48a1ace 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -78,6 +78,7 @@
<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>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 734abdc..f5674d2 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -45,6 +45,12 @@
<declare-styleable name="BatteryMeterView">
<attr name="frameColor" format="color" />
</declare-styleable>
+ <declare-styleable name="SwipeAffordanceView">
+ <attr name="swipeDirection" format="enum">
+ <enum name="start" value="0" />
+ <enum name="end" value="1" />
+ </attr>
+ </declare-styleable>
<attr name="orientation">
<enum name="horizontal" value="0" />
<enum name="vertical" value="1" />
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 722ca15..93a75bc 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -99,9 +99,6 @@
<integer name="blinds_pop_duration_ms">10</integer>
- <!-- The device supports quick settings. -->
- <bool name="config_hasQuickSettings">true</bool>
-
<!-- Should "4G" be shown instead of "LTE" when the network is NETWORK_TYPE_LTE? -->
<bool name="config_show4GForLTE">true</bool>
@@ -115,12 +112,16 @@
<integer name="recents_filter_animate_current_views_min_duration">175</integer>
<!-- The min animation duration for animating views that are newly visible. -->
<integer name="recents_filter_animate_new_views_min_duration">125</integer>
- <!-- The min animation duration for animating views that are newly visible. -->
+ <!-- The min animation duration for animating the task bar in. -->
<integer name="recents_animate_task_bar_enter_duration">200</integer>
+ <!-- The min animation duration for animating the task bar out. -->
+ <integer name="recents_animate_task_bar_exit_duration">150</integer>
<!-- The animation duration for animating in the info pane. -->
<integer name="recents_animate_task_view_info_pane_duration">150</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 -->
+ <bool name="recents_transpose_search_layout_with_orientation">true</bool>
<!-- Whether to enable KeyguardService or not -->
<bool name="config_enableKeyguardService">true</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9837d9b..8d3a565 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -128,8 +128,8 @@
<!-- The width of the view containing non-menu status bar icons -->
<dimen name="navigation_key_width">80dip</dimen>
- <!-- The width of the view containing the menu status bar icon -->
- <dimen name="navigation_menu_key_width">40dip</dimen>
+ <!-- The width of the view containing the menu/ime navigation bar icons -->
+ <dimen name="navigation_extra_key_width">40dip</dimen>
<!-- Default distance beyond which snaps to the matching target -->
<dimen name="navbar_search_snap_margin">40dip</dimen>
@@ -152,21 +152,11 @@
<!-- Amount of close_handle that will NOT overlap the notification list -->
<dimen name="close_handle_underlap">32dp</dimen>
- <!-- Height of the notification panel header bar -->
- <dimen name="notification_panel_header_height">48dp</dimen>
+ <!-- Height of the status bar header bar -->
+ <dimen name="status_bar_header_height">48dp</dimen>
- <!-- Extra space above the panel -->
- <dimen name="notification_panel_padding_top">0dp</dimen>
-
- <!-- Extra space above the clock in the panel -->
- <dimen name="notification_panel_header_padding_top">0dp</dimen>
-
- <!-- Extra space above the panel holder -->
- <dimen name="panel_holder_padding_top">0dp</dimen>
-
- <!-- Layout parameters for the notification panel -->
- <dimen name="notification_panel_margin_bottom">0dp</dimen>
- <dimen name="notification_panel_margin_left">0dp</dimen>
+ <!-- Height of the status bar header bar when expanded -->
+ <dimen name="status_bar_header_height_expanded">144dp</dimen>
<!-- Gravity for the notification panel -->
<!-- 0x37 = fill_horizontal|top -->
@@ -227,14 +217,17 @@
<!-- The radius of the rounded corners on a task view. -->
<dimen name="recents_task_view_rounded_corners_radius">2dp</dimen>
+ <!-- The min translation in the Z index for the last task. -->
+ <dimen name="recents_task_view_z_min">3dp</dimen>
+
+ <!-- The translation in the Z index for each task above the last task. -->
+ <dimen name="recents_task_view_z_increment">5dp</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>
<!-- The height of the search bar space. -->
- <dimen name="recents_search_bar_space_height">40dp</dimen>
-
- <!-- The search bar edge margins. -->
- <dimen name="recents_search_bar_space_edge_margins">12dp</dimen>
+ <dimen name="recents_search_bar_space_height">64dp</dimen>
<!-- Used to calculate the translation animation duration, the expected amount of movement
in dps over one second of time. -->
@@ -258,14 +251,20 @@
<!-- The padding between the individual notification cards. -->
<dimen name="notification_padding">3dp</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>
+
<!-- Width of the zen mode interstitial dialog. -->
<dimen name="zen_mode_dialog_width">320dp</dimen>
- <!-- Camera affordance drag distance -->
- <dimen name="camera_drag_distance">100dp</dimen>
+ <!-- Lockscreen affordance drag distance for camera and phone. -->
+ <dimen name="affordance_drag_distance">100dp</dimen>
<dimen name="quick_settings_tmp_scrim_stroke_width">8dp</dimen>
<dimen name="quick_settings_tmp_scrim_text_size">30dp</dimen>
<dimen name="notifications_top_padding">8dp</dimen>
+
+ <!-- Minimum distance the user has to drag down to go to the full shade. -->
+ <dimen name="keyguard_drag_down_min_distance">100dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
new file mode 100644
index 0000000..6418930
--- /dev/null
+++ b/packages/SystemUI/res/values/ids.xml
@@ -0,0 +1,38 @@
+<?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>
+ <item type="id" name="translation_y_animator_tag"/>
+ <item type="id" name="translation_z_animator_tag"/>
+ <item type="id" name="scale_animator_tag"/>
+ <item type="id" name="alpha_animator_tag"/>
+ <item type="id" name="top_inset_animator_tag"/>
+ <item type="id" name="height_animator_tag"/>
+ <item type="id" name="translation_y_animator_end_value_tag"/>
+ <item type="id" name="translation_z_animator_end_value_tag"/>
+ <item type="id" name="scale_animator_end_value_tag"/>
+ <item type="id" name="alpha_animator_end_value_tag"/>
+ <item type="id" name="top_inset_animator_end_value_tag"/>
+ <item type="id" name="height_animator_end_value_tag"/>
+ <item type="id" name="translation_y_animator_start_value_tag"/>
+ <item type="id" name="translation_z_animator_start_value_tag"/>
+ <item type="id" name="scale_animator_start_value_tag"/>
+ <item type="id" name="alpha_animator_start_value_tag"/>
+ <item type="id" name="top_inset_animator_start_value_tag"/>
+ <item type="id" name="height_animator_start_value_tag"/>
+</resources>
+
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b4a13d4..3f0a60f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -196,6 +196,8 @@
<string name="accessibility_search_light">Search</string>
<!-- Content description of the camera button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_camera_button">Camera</string>
+ <!-- Content description of the phone button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_phone_button">Phone</string>
<!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_ime_switch_button">Switch input method button.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 61c268e..4d6d815c 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -29,17 +29,16 @@
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.ViewConfiguration;
-import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.policy.ScrollAdapter;
-public class ExpandHelper implements Gefingerpoken, OnClickListener {
+public class ExpandHelper implements Gefingerpoken {
public interface Callback {
- View getChildAtRawPosition(float x, float y);
- View getChildAtPosition(float x, float y);
+ ExpandableView getChildAtRawPosition(float x, float y);
+ ExpandableView getChildAtPosition(float x, float y);
boolean canChildBeExpanded(View v);
void setUserExpandedChild(View v, boolean userExpanded);
void setUserLockedChild(View v, boolean userLocked);
@@ -48,9 +47,7 @@
private static final String TAG = "ExpandHelper";
protected static final boolean DEBUG = false;
protected static final boolean DEBUG_SCALE = false;
- protected static final boolean DEBUG_GLOW = false;
private static final long EXPAND_DURATION = 250;
- private static final long GLOW_DURATION = 150;
// Set to false to disable focus-based gestures (spread-finger vertical pull).
private static final boolean USE_DRAG = true;
@@ -115,7 +112,7 @@
float focusX = detector.getFocusX();
float focusY = detector.getFocusY();
- final View underFocus = findView(focusX, focusY);
+ final ExpandableView underFocus = findView(focusX, focusY);
startExpanding(underFocus, STRETCH);
return mExpanding;
}
@@ -172,24 +169,6 @@
mPopDuration = mContext.getResources().getInteger(R.integer.blinds_pop_duration_ms);
mPullGestureMinXSpan = mContext.getResources().getDimension(R.dimen.pull_span_min);
- AnimatorListenerAdapter glowVisibilityController = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- View target = (View) ((ObjectAnimator) animation).getTarget();
- if (target.getAlpha() <= 0.0f) {
- target.setVisibility(View.VISIBLE);
- }
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- View target = (View) ((ObjectAnimator) animation).getTarget();
- if (target.getAlpha() <= 0.0f) {
- target.setVisibility(View.INVISIBLE);
- }
- }
- };
-
final ViewConfiguration configuration = ViewConfiguration.get(mContext);
mTouchSlop = configuration.getScaledTouchSlop();
@@ -221,8 +200,8 @@
return out;
}
- private View findView(float x, float y) {
- View v = null;
+ private ExpandableView findView(float x, float y) {
+ ExpandableView v;
if (mEventSource != null) {
int[] location = new int[2];
mEventSource.getLocationOnScreen(location);
@@ -271,15 +250,6 @@
mScrollAdapter = adapter;
}
- private float calculateGlow(float target, float actual) {
- // glow if overscale
- if (DEBUG_GLOW) Log.d(TAG, "target: " + target + " actual: " + actual);
- float stretch = Math.abs((target - actual) / mMaximumStretch);
- float strength = 1f / (1f + (float) Math.pow(Math.E, -1 * ((8f * stretch) - 5f)));
- if (DEBUG_GLOW) Log.d(TAG, "stretch: " + stretch + " strength: " + strength);
- return (GLOW_BASE + strength * (1f - GLOW_BASE));
- }
-
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
@@ -313,7 +283,7 @@
// detect a vertical pulling gesture with fingers somewhat separated
if (DEBUG_SCALE) Log.v(TAG, "got pull gesture (xspan=" + xspan + "px)");
- final View underFocus = findView(x, y);
+ final ExpandableView underFocus = findView(x, y);
startExpanding(underFocus, PULL);
return true;
}
@@ -328,7 +298,7 @@
if (yDiff > mTouchSlop) {
if (DEBUG) Log.v(TAG, "got venetian gesture (dy=" + yDiff + "px)");
mLastMotionY = y;
- final View underFocus = findView(x, y);
+ final ExpandableView underFocus = findView(x, y);
if (startExpanding(underFocus, BLINDS)) {
mInitialTouchY = mLastMotionY;
mHasPopped = false;
@@ -394,7 +364,7 @@
final int x = (int) mSGD.getFocusX();
final int y = (int) mSGD.getFocusY();
- View underFocus = findView(x, y);
+ ExpandableView underFocus = findView(x, y);
if (isFinished && underFocus != null && underFocus != mCurrView) {
finishExpanding(false); // @@@ needed?
startExpanding(underFocus, BLINDS);
@@ -432,7 +402,7 @@
/**
* @return True if the view is expandable, false otherwise.
*/
- private boolean startExpanding(View v, int expandType) {
+ private boolean startExpanding(ExpandableView v, int expandType) {
if (!(v instanceof ExpandableNotificationRow)) {
return false;
}
@@ -512,13 +482,6 @@
mCurrView = v;
}
- @Override
- public void onClick(View v) {
- startExpanding(v, STRETCH);
- finishExpanding(true);
- clearView();
- }
-
/**
* Use this to abort any pending expansions in progress.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index d38d828..6387a92 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -322,6 +322,7 @@
anim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animator) {
updateAlphaFromOffset(animView, canAnimViewBeDismissed);
+ mCallback.onChildSnappedBack(animView);
}
});
anim.start();
@@ -407,5 +408,7 @@
void onChildDismissed(View v);
void onDragCancelled(View v);
+
+ void onChildSnappedBack(View animView);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 103991a..217074f 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -65,6 +65,8 @@
// the theme set there.
setTheme(R.style.systemui_theme);
+ IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -80,7 +82,7 @@
}
}
}
- }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+ }, filter);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index ffdb620..f812e8c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -542,9 +542,8 @@
/**
* Called to let us know the screen was turned off.
- * @param why either {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_USER},
- * {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or
- * {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_PROX_SENSOR}.
+ * @param why either {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_USER} or
+ * {@link android.view.WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}.
*/
public void onScreenTurnedOff(int why) {
synchronized (this) {
@@ -576,8 +575,6 @@
} else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT
|| (why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)) {
doKeyguardLaterLocked();
- } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) {
- // Do not enable the keyguard if the prox sensor forced the screen off.
} else {
doKeyguardLocked(null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 35c824b..0759b8e 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -217,6 +217,10 @@
public void onDragCancelled(View v) {
}
+ @Override
+ public void onChildSnappedBack(View animView) {
+ }
+
public View getChildAtPosition(MotionEvent ev) {
final float x = ev.getX() + getScrollX();
final float y = ev.getY() + getScrollY();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 297fe0d..c2dde6a 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -225,6 +225,10 @@
public void onDragCancelled(View v) {
}
+ @Override
+ public void onChildSnappedBack(View animView) {
+ }
+
public View getChildAtPosition(MotionEvent ev) {
final float x = ev.getX() + getScrollX();
final float y = ev.getY() + getScrollY();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index f2e322d..3ef8316 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -64,6 +64,17 @@
mSingleCountFirstTaskRect.offset(0, (int) statusBarHeight);
mMultipleCountFirstTaskRect = replyData.getParcelable(KEY_MULTIPLE_TASK_STACK_RECT);
mMultipleCountFirstTaskRect.offset(0, (int) statusBarHeight);
+ Console.log(Constants.Log.App.RecentsComponent,
+ "[RecentsComponent|RecentsMessageHandler|handleMessage]",
+ "singleTaskRect: " + mSingleCountFirstTaskRect +
+ " multipleTaskRect: " + mMultipleCountFirstTaskRect);
+
+ // If we had the update the animation rects as a result of onServiceConnected, then
+ // we check for whether we need to toggle the recents here.
+ if (mToggleRecentsUponServiceBound) {
+ startAlternateRecentsActivity();
+ mToggleRecentsUponServiceBound = false;
+ }
}
}
}
@@ -72,22 +83,27 @@
class RecentsServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
- Console.log(Constants.DebugFlags.App.RecentsComponent,
+ Console.log(Constants.Log.App.RecentsComponent,
"[RecentsComponent|ServiceConnection|onServiceConnected]",
"toggleRecents: " + mToggleRecentsUponServiceBound);
mService = new Messenger(service);
mServiceIsBound = true;
- // Toggle recents if this service connection was triggered by hitting the recents button
- if (mToggleRecentsUponServiceBound) {
- startAlternateRecentsActivity();
+ if (hasValidTaskRects()) {
+ // Toggle recents if this new service connection was triggered by hitting recents
+ if (mToggleRecentsUponServiceBound) {
+ startAlternateRecentsActivity();
+ mToggleRecentsUponServiceBound = false;
+ }
+ } else {
+ // Otherwise, update the animation rects before starting the recents if requested
+ updateAnimationRects();
}
- mToggleRecentsUponServiceBound = false;
}
@Override
public void onServiceDisconnected(ComponentName className) {
- Console.log(Constants.DebugFlags.App.RecentsComponent,
+ Console.log(Constants.Log.App.RecentsComponent,
"[RecentsComponent|ServiceConnection|onServiceDisconnected]");
mService = null;
mServiceIsBound = false;
@@ -138,7 +154,7 @@
}
public void onStart() {
- Console.log(Constants.DebugFlags.App.RecentsComponent, "[RecentsComponent|start]");
+ Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|start]");
// Try to create a long-running connection to the recents service
bindToRecentsService(false);
@@ -146,11 +162,11 @@
/** Toggles the alternate recents activity */
public void onToggleRecents(Display display, int layoutDirection, View statusBarView) {
- Console.logStartTracingTime(Constants.DebugFlags.App.TimeRecentsStartup,
- Constants.DebugFlags.App.TimeRecentsStartupKey);
- Console.logStartTracingTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
- Constants.DebugFlags.App.TimeRecentsLaunchKey);
- Console.log(Constants.DebugFlags.App.RecentsComponent, "[RecentsComponent|toggleRecents]",
+ Console.logStartTracingTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey);
+ Console.logStartTracingTime(Constants.Log.App.TimeRecentsLaunchTask,
+ Constants.Log.App.TimeRecentsLaunchKey);
+ Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|toggleRecents]",
"serviceIsBound: " + mServiceIsBound);
mStatusBarView = statusBarView;
if (!mServiceIsBound) {
@@ -176,7 +192,7 @@
}
public void onCloseRecents() {
- Console.log(Constants.DebugFlags.App.RecentsComponent, "[RecentsComponent|closeRecents]");
+ Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|closeRecents]");
if (mServiceIsBound) {
// Try and update the recents configuration
try {
@@ -191,6 +207,26 @@
}
public void onConfigurationChanged(Configuration newConfig) {
+ updateAnimationRects();
+ }
+
+ /** Binds to the recents implementation */
+ private void bindToRecentsService(boolean toggleRecentsUponConnection) {
+ mToggleRecentsUponServiceBound = toggleRecentsUponConnection;
+ Intent intent = new Intent();
+ intent.setClassName(sRecentsPackage, sRecentsService);
+ mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ /** Returns whether we have valid task rects to animate to. */
+ boolean hasValidTaskRects() {
+ return mSingleCountFirstTaskRect != null && mSingleCountFirstTaskRect.width() > 0 &&
+ mSingleCountFirstTaskRect.height() > 0 && mMultipleCountFirstTaskRect != null &&
+ mMultipleCountFirstTaskRect.width() > 0 && mMultipleCountFirstTaskRect.height() > 0;
+ }
+
+ /** Updates each of the task animation rects. */
+ void updateAnimationRects() {
if (mServiceIsBound) {
Resources res = mContext.getResources();
int statusBarHeight = res.getDimensionPixelSize(
@@ -216,14 +252,6 @@
}
}
- /** Binds to the recents implementation */
- private void bindToRecentsService(boolean toggleRecentsUponConnection) {
- mToggleRecentsUponServiceBound = toggleRecentsUponConnection;
- Intent intent = new Intent();
- intent.setClassName(sRecentsPackage, sRecentsService);
- mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
- }
-
/** Loads the first task thumbnail */
Bitmap loadFirstTaskThumbnail() {
SystemServicesProxy ssp = mSystemServicesProxy;
@@ -300,6 +328,49 @@
return SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
}
+ /** Creates the activity options for a thumbnail transition. */
+ ActivityOptions getThumbnailTransitionActivityOptions(Rect taskRect) {
+ // Loading from thumbnail
+ Bitmap thumbnail;
+ Bitmap firstThumbnail = loadFirstTaskThumbnail();
+ if (firstThumbnail != null) {
+ // Create the thumbnail
+ thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
+ Bitmap.Config.ARGB_8888);
+ int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight());
+ Canvas c = new Canvas(thumbnail);
+ c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size),
+ new Rect(0, 0, taskRect.width(), taskRect.height()), null);
+ c.setBitmap(null);
+ // Recycle the old thumbnail
+ firstThumbnail.recycle();
+ } else {
+ // Load the thumbnail from the screenshot if can't get one from the system
+ WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ Display display = wm.getDefaultDisplay();
+ Bitmap screenshot = takeScreenshot(display);
+ if (screenshot != null) {
+ Resources res = mContext.getResources();
+ int size = Math.min(screenshot.getWidth(), screenshot.getHeight());
+ int statusBarHeight = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height);
+ thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
+ Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(thumbnail);
+ c.drawBitmap(screenshot, new Rect(0, statusBarHeight, size, statusBarHeight +
+ size), new Rect(0, 0, taskRect.width(), taskRect.height()), null);
+ c.setBitmap(null);
+ // Recycle the temporary screenshot
+ screenshot.recycle();
+ } else {
+ return null;
+ }
+ }
+
+ return ActivityOptions.makeThumbnailScaleDownAnimation(mStatusBarView, thumbnail,
+ taskRect.left, taskRect.top, null);
+ }
+
/** Starts the recents activity */
void startAlternateRecentsActivity() {
// If the user has toggled it too quickly, then just eat up the event here (it's better than
@@ -329,10 +400,10 @@
mService.send(msg);
// Time this path
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
- Constants.DebugFlags.App.TimeRecentsStartupKey, "sendToggleRecents");
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
- Constants.DebugFlags.App.TimeRecentsLaunchKey, "sendToggleRecents");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "sendToggleRecents");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+ Constants.Log.App.TimeRecentsLaunchKey, "sendToggleRecents");
} catch (RemoteException re) {
re.printStackTrace();
}
@@ -351,55 +422,36 @@
// number of items in the list.
List<ActivityManager.RecentTaskInfo> recentTasks =
ssp.getRecentTasks(4, UserHandle.CURRENT.getIdentifier());
- boolean hasMultipleTasks = hasMultipleRecentsTask(recentTasks);
+ Rect taskRect = hasMultipleRecentsTask(recentTasks) ? mMultipleCountFirstTaskRect :
+ mSingleCountFirstTaskRect;
boolean isTaskExcludedFromRecents = isTopTaskExcludeFromRecents(recentTasks);
- Rect taskRect = hasMultipleTasks ? mMultipleCountFirstTaskRect : mSingleCountFirstTaskRect;
- if (!isTopTaskHome && !isTaskExcludedFromRecents &&
- (taskRect != null) && (taskRect.width() > 0) && (taskRect.height() > 0)) {
- // Loading from thumbnail
- Bitmap thumbnail;
- Bitmap firstThumbnail = loadFirstTaskThumbnail();
- if (firstThumbnail != null) {// Create the thumbnail
- thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
- Bitmap.Config.ARGB_8888);
- int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight());
- Canvas c = new Canvas(thumbnail);
- c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size),
- new Rect(0, 0, taskRect.width(), taskRect.height()), null);
- c.setBitmap(null);
- // Recycle the old thumbnail
- firstThumbnail.recycle();
- } else {
- // Load the thumbnail from the screenshot if can't get one from the system
- WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- Display display = wm.getDefaultDisplay();
- Bitmap screenshot = takeScreenshot(display);
- Resources res = mContext.getResources();
- int size = Math.min(screenshot.getWidth(), screenshot.getHeight());
- int statusBarHeight = res.getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_height);
- thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
- Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(thumbnail);
- c.drawBitmap(screenshot, new Rect(0, statusBarHeight, size, statusBarHeight + size),
- new Rect(0, 0, taskRect.width(), taskRect.height()), null);
- c.setBitmap(null);
- // Recycle the temporary screenshot
- screenshot.recycle();
- }
+ boolean useThumbnailTransition = !isTopTaskHome && !isTaskExcludedFromRecents &&
+ hasValidTaskRects();
- ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(mStatusBarView,
- thumbnail, taskRect.left, taskRect.top, null);
- startAlternateRecentsActivity(opts, true);
- } else {
+ if (useThumbnailTransition) {
+ // Try starting with a thumbnail transition
+ ActivityOptions opts = getThumbnailTransitionActivityOptions(taskRect);
+ if (opts != null) {
+ startAlternateRecentsActivity(opts, true);
+ } else {
+ // Fall through below to the non-thumbnail transition
+ useThumbnailTransition = false;
+ }
+ }
+
+ // If there is no thumbnail transition, then just use a generic transition
+ // XXX: This should be different between home and from a recents-excluded app, perhaps the
+ // recents-excluded app should still show up in recents, when the app is in the
+ // foreground
+ if (!useThumbnailTransition) {
ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
R.anim.recents_from_launcher_enter,
R.anim.recents_from_launcher_exit);
startAlternateRecentsActivity(opts, false);
}
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
- Constants.DebugFlags.App.TimeRecentsStartupKey, "startRecentsActivity");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "startRecentsActivity");
mLastToggleTime = System.currentTimeMillis();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Console.java b/packages/SystemUI/src/com/android/systemui/recents/Console.java
index 4b75c99..c8d97cc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Console.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Console.java
@@ -37,7 +37,7 @@
public static final String AnsiRed = "\u001B[31m"; // SystemUIHandshake
public static final String AnsiGreen = "\u001B[32m"; // MeasureAndLayout
public static final String AnsiYellow = "\u001B[33m"; // SynchronizeViewsWithModel
- public static final String AnsiBlue = "\u001B[34m"; // TouchEvents
+ public static final String AnsiBlue = "\u001B[34m"; // TouchEvents, Search
public static final String AnsiPurple = "\u001B[35m"; // Draw
public static final String AnsiCyan = "\u001B[36m"; // ClickEvents
public static final String AnsiWhite = "\u001B[37m";
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index a996c1a..1d6a76c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -18,7 +18,6 @@
/**
* Constants
- * XXX: We are going to move almost all of these into a resource.
*/
public class Constants {
public static class DebugFlags {
@@ -26,11 +25,18 @@
public static final boolean Verbose = false;
public static class App {
+ // Enables the filtering of tasks according to their grouping
public static final boolean EnableTaskFiltering = false;
+ // Enables clipping of tasks against each other
public static final boolean EnableTaskStackClipping = false;
+ // 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 EnableSearchButton = false;
-
+ // Enables the search bar layout
+ public static final boolean EnableSearchLayout = true;
+ // Enables the dynamic shadows behind each task
+ public static final boolean EnableShadows = false;
// This disables the bitmap and icon caches
public static final boolean DisableBackgroundCache = false;
// For debugging, this enables us to create mock recents tasks
@@ -39,8 +45,11 @@
public static final int SystemServicesProxyMockPackageCount = 3;
// For debugging, this defines the number of mock recents tasks to create
public static final int SystemServicesProxyMockTaskCount = 75;
+ }
+ }
- // Timing certain paths
+ public static class Log {
+ public static class App {
public static final String TimeRecentsStartupKey = "startup";
public static final String TimeRecentsLaunchKey = "launchTask";
public static final boolean TimeRecentsStartup = false;
@@ -51,6 +60,7 @@
public static final boolean SystemUIHandshake = false;
public static final boolean TimeSystemCalls = false;
public static final boolean Memory = false;
+ public static final boolean Search = false;
}
public static class UI {
@@ -70,7 +80,12 @@
}
}
+ /** XXX: We are going to move almost all of these into a resource once they are nailed down. */
public static class Values {
+ public static class App {
+ public static int AppWidgetHostId = 1024;
+ public static String Key_SearchAppWidgetId = "searchAppWidgetId";
+ }
public static class Window {
// The dark background dim is set behind the empty recents view
public static final float DarkBackgroundDim = 0.5f;
@@ -85,11 +100,8 @@
public static final int TaskStackOverscrollRange = 150;
public static final int FilterStartDelay = 25;
- // The amount to inverse scale the movement if we are overscrolling
- public static final float TouchOverscrollScaleFactor = 3f;
-
// The padding will be applied to the smallest dimension, and then applied to all sides
- public static final float StackPaddingPct = 0.15f;
+ public static final float StackPaddingPct = 0.1f;
// The overlap height relative to the task height
public static final float StackOverlapPct = 0.65f;
// The height of the peek space relative to the stack height
@@ -99,10 +111,5 @@
// The number of cards we see in the peek space
public static final int StackPeekNumCards = 3;
}
-
- public static class TaskView {
- public static final boolean AnimateFrontTaskBarOnEnterRecents = true;
- public static final boolean AnimateFrontTaskBarOnLeavingRecents = true;
- }
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 71c45f2..3be6932 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -17,11 +17,16 @@
package com.android.systemui.recents;
import android.app.Activity;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
@@ -33,13 +38,37 @@
import java.util.ArrayList;
+/** Our special app widget host */
+class RecentsAppWidgetHost extends AppWidgetHost {
+ /* Callbacks to notify when an app package changes */
+ interface RecentsAppWidgetHostCallbacks {
+ public void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo);
+ }
+
+ RecentsAppWidgetHostCallbacks mCb;
+
+ public RecentsAppWidgetHost(Context context, int hostId, RecentsAppWidgetHostCallbacks cb) {
+ super(context, hostId);
+ mCb = cb;
+ }
+
+ @Override
+ protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) {
+ mCb.onProviderChanged(appWidgetId, appWidget);
+ }
+}
/* Activity */
-public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks {
+public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks,
+ RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks{
FrameLayout mContainerView;
RecentsView mRecentsView;
View mEmptyView;
+ AppWidgetHost mAppWidgetHost;
+ AppWidgetProviderInfo mSearchAppWidgetInfo;
+ AppWidgetHostView mSearchAppWidgetHostView;
+
boolean mVisible;
boolean mTaskLaunched;
@@ -48,7 +77,7 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+ Console.log(Constants.Log.App.SystemUIHandshake,
"[RecentsActivity|serviceBroadcast]", action, Console.AnsiRed);
if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
// Try and unfilter and filtered stacks
@@ -102,6 +131,75 @@
}
}
+ /** Attempts to allocate and bind the search bar app widget */
+ void bindSearchBarAppWidget() {
+ if (Constants.DebugFlags.App.EnableSearchLayout) {
+ RecentsConfiguration config = RecentsConfiguration.getInstance();
+ SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
+
+ // Reset the host view and widget info
+ mSearchAppWidgetHostView = null;
+ mSearchAppWidgetInfo = null;
+
+ // Try and load the app widget id from the settings
+ int appWidgetId = config.searchBarAppWidgetId;
+ if (appWidgetId >= 0) {
+ mSearchAppWidgetInfo = ssp.getAppWidgetInfo(appWidgetId);
+ if (mSearchAppWidgetInfo == null) {
+ // If there is no actual widget associated with that id, then delete it and
+ // prepare to bind another app widget in its place
+ ssp.unbindSearchAppWidget(mAppWidgetHost, appWidgetId);
+ appWidgetId = -1;
+ }
+ Console.log(Constants.Log.App.SystemUIHandshake,
+ "[RecentsActivity|onCreate|settings|appWidgetId]",
+ "Id: " + appWidgetId,
+ Console.AnsiBlue);
+ }
+
+ // If there is no id, then bind a new search app widget
+ if (appWidgetId < 0) {
+ Pair<Integer, AppWidgetProviderInfo> widgetInfo =
+ ssp.bindSearchAppWidget(mAppWidgetHost);
+ if (widgetInfo != null) {
+ Console.log(Constants.Log.App.SystemUIHandshake,
+ "[RecentsActivity|onCreate|searchWidget]",
+ "Id: " + widgetInfo.first + " Info: " + widgetInfo.second,
+ Console.AnsiBlue);
+
+ // Save the app widget id into the settings
+ config.updateSearchBarAppWidgetId(this, widgetInfo.first);
+ mSearchAppWidgetInfo = widgetInfo.second;
+ }
+ }
+ }
+ }
+
+ /** Creates the search bar app widget view */
+ void addSearchBarAppWidgetView() {
+ if (Constants.DebugFlags.App.EnableSearchLayout) {
+ RecentsConfiguration config = RecentsConfiguration.getInstance();
+ int appWidgetId = config.searchBarAppWidgetId;
+ if (appWidgetId >= 0) {
+ Console.log(Constants.Log.App.SystemUIHandshake,
+ "[RecentsActivity|onCreate|addSearchAppWidgetView]",
+ "Id: " + appWidgetId,
+ Console.AnsiBlue);
+ mSearchAppWidgetHostView = mAppWidgetHost.createView(this, appWidgetId,
+ mSearchAppWidgetInfo);
+ Bundle opts = new Bundle();
+ opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
+ AppWidgetProviderInfo.WIDGET_CATEGORY_RECENTS);
+ mSearchAppWidgetHostView.updateAppWidgetOptions(opts);
+ // Set the padding to 0 for this search widget
+ mSearchAppWidgetHostView.setPadding(0, 0, 0, 0);
+ mRecentsView.setSearchBar(mSearchAppWidgetHostView);
+ } else {
+ mRecentsView.setSearchBar(null);
+ }
+ }
+ }
+
/** Dismisses recents if we are already visible and the intent is to toggle the recents view */
boolean dismissRecentsIfVisible() {
if (mVisible) {
@@ -117,16 +215,19 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Console.logDivider(Constants.DebugFlags.App.SystemUIHandshake);
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onCreate]",
+ Console.logDivider(Constants.Log.App.SystemUIHandshake);
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onCreate]",
getIntent().getAction() + " visible: " + mVisible, Console.AnsiRed);
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
- Constants.DebugFlags.App.TimeRecentsStartupKey, "onCreate");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "onCreate");
// Initialize the loader and the configuration
RecentsTaskLoader.initialize(this);
RecentsConfiguration.reinitialize(this);
+ // Initialize the widget host (the host id is static and does not change)
+ mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId, this);
+
// Create the view hierarchy
mRecentsView = new RecentsView(this);
mRecentsView.setCallbacks(this);
@@ -145,6 +246,11 @@
// Update the recent tasks
updateRecentsTasks(getIntent());
+
+ // Bind the search app widget when we first start up
+ bindSearchBarAppWidget();
+ // Add the search bar layout
+ addSearchBarAppWidgetView();
}
@Override
@@ -153,11 +259,11 @@
// Reset the task launched flag if we encounter an onNewIntent() before onStop()
mTaskLaunched = false;
- Console.logDivider(Constants.DebugFlags.App.SystemUIHandshake);
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onNewIntent]",
+ Console.logDivider(Constants.Log.App.SystemUIHandshake);
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onNewIntent]",
intent.getAction() + " visible: " + mVisible, Console.AnsiRed);
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
- Constants.DebugFlags.App.TimeRecentsStartupKey, "onNewIntent");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "onNewIntent");
// Initialize the loader and the configuration
RecentsTaskLoader.initialize(this);
@@ -165,26 +271,30 @@
// Update the recent tasks
updateRecentsTasks(intent);
+
+ // Don't attempt to rebind the search bar widget, but just add the search bar layout
+ addSearchBarAppWidgetView();
}
@Override
protected void onStart() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onStart]", "",
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onStart]", "",
Console.AnsiRed);
super.onStart();
+ mAppWidgetHost.startListening();
mVisible = true;
}
@Override
protected void onResume() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onResume]", "",
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onResume]", "",
Console.AnsiRed);
super.onResume();
}
@Override
public void onAttachedToWindow() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+ Console.log(Constants.Log.App.SystemUIHandshake,
"[RecentsActivity|onAttachedToWindow]", "",
Console.AnsiRed);
super.onAttachedToWindow();
@@ -202,7 +312,7 @@
@Override
public void onDetachedFromWindow() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+ Console.log(Constants.Log.App.SystemUIHandshake,
"[RecentsActivity|onDetachedFromWindow]", "",
Console.AnsiRed);
super.onDetachedFromWindow();
@@ -214,24 +324,25 @@
@Override
protected void onPause() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onPause]", "",
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onPause]", "",
Console.AnsiRed);
super.onPause();
}
@Override
protected void onStop() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onStop]", "",
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onStop]", "",
Console.AnsiRed);
super.onStop();
+ mAppWidgetHost.stopListening();
mVisible = false;
mTaskLaunched = false;
}
@Override
protected void onDestroy() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onDestroy]", "",
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onDestroy]", "",
Console.AnsiRed);
super.onDestroy();
}
@@ -265,4 +376,18 @@
public void onTaskLaunching() {
mTaskLaunched = true;
}
+
+ @Override
+ public void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo) {
+ RecentsConfiguration config = RecentsConfiguration.getInstance();
+ SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
+ if (appWidgetId > -1 && appWidgetId == config.searchBarAppWidgetId) {
+ // The search provider may have changed, so just delete the old widget and bind it again
+ ssp.unbindSearchAppWidget(mAppWidgetHost, appWidgetId);
+ config.updateSearchBarAppWidgetId(this, -1);
+ // Load the widget again
+ bindSearchBarAppWidget();
+ addSearchBarAppWidgetView();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index d54df13..cb7e42a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
@@ -35,17 +36,28 @@
public Rect systemInsets = new Rect();
public Rect displayRect = new Rect();
+ boolean isLandscape;
+ boolean transposeSearchLayoutWithOrientation;
+ int searchBarAppWidgetId = -1;
+
public float animationPxMovementPerSecond;
public int filteringCurrentViewsMinAnimDuration;
public int filteringNewViewsMinAnimDuration;
public int taskBarEnterAnimDuration;
+ public int taskBarExitAnimDuration;
public int taskStackScrollDismissInfoPaneDistance;
public int taskStackMaxDim;
public int taskViewInfoPaneAnimDuration;
+ public int taskViewTranslationZMinPx;
+ public int taskViewTranslationZIncrementPx;
public int taskViewRoundedCornerRadiusPx;
public int searchBarSpaceHeightPx;
- public int searchBarSpaceEdgeMarginsPx;
+
+ public int taskBarViewDefaultBackgroundColor;
+ public int taskBarViewDefaultTextColor;
+ public int taskBarViewLightTextColor;
+ public int taskBarViewDarkTextColor;
public boolean launchedWithThumbnailAnimation;
@@ -72,9 +84,11 @@
DisplayMetrics dm = res.getDisplayMetrics();
mDisplayMetrics = dm;
- boolean isLandscape = res.getConfiguration().orientation ==
+ isLandscape = res.getConfiguration().orientation ==
Configuration.ORIENTATION_LANDSCAPE;
- Console.log(Constants.DebugFlags.UI.MeasureAndLayout,
+ transposeSearchLayoutWithOrientation =
+ res.getBoolean(R.bool.recents_transpose_search_layout_with_orientation);
+ Console.log(Constants.Log.UI.MeasureAndLayout,
"[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait",
Console.AnsiGreen);
@@ -87,6 +101,8 @@
res.getInteger(R.integer.recents_filter_animate_new_views_min_duration);
taskBarEnterAnimDuration =
res.getInteger(R.integer.recents_animate_task_bar_enter_duration);
+ taskBarExitAnimDuration =
+ res.getInteger(R.integer.recents_animate_task_bar_exit_duration);
taskStackScrollDismissInfoPaneDistance = res.getDimensionPixelSize(
R.dimen.recents_task_stack_scroll_dismiss_info_pane_distance);
taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim);
@@ -94,9 +110,24 @@
res.getInteger(R.integer.recents_animate_task_view_info_pane_duration);
taskViewRoundedCornerRadiusPx =
res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
+ taskViewTranslationZMinPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
+ taskViewTranslationZIncrementPx =
+ res.getDimensionPixelSize(R.dimen.recents_task_view_z_increment);
searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
- searchBarSpaceEdgeMarginsPx =
- res.getDimensionPixelSize(R.dimen.recents_search_bar_space_edge_margins);
+
+
+ taskBarViewDefaultBackgroundColor =
+ res.getColor(R.color.recents_task_bar_default_background_color);
+ taskBarViewDefaultTextColor =
+ res.getColor(R.color.recents_task_bar_default_text_color);
+ taskBarViewLightTextColor =
+ res.getColor(R.color.recents_task_bar_light_text_color);
+ taskBarViewDarkTextColor =
+ res.getColor(R.color.recents_task_bar_dark_text_color);
+
+ // Update the search widget id
+ SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0);
+ searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1);
}
/** Updates the system insets */
@@ -104,24 +135,57 @@
systemInsets.set(insets);
}
- /** Returns the search bar bounds in the specified orientation */
- public void getSearchBarBounds(int width, int height,
- Rect searchBarSpaceBounds, Rect searchBarBounds) {
+ /** Updates the search bar app widget */
+ public void updateSearchBarAppWidgetId(Context context, int appWidgetId) {
+ searchBarAppWidgetId = appWidgetId;
+ SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0);
+ settings.edit().putInt(Constants.Values.App.Key_SearchAppWidgetId,
+ appWidgetId).apply();
+ }
+
+ /** Returns whether the search bar app widget exists */
+ public boolean hasSearchBarAppWidget() {
+ return searchBarAppWidgetId >= 0;
+ }
+
+ /**
+ * Returns the task stack bounds in the current orientation. These bounds do not account for
+ * the system insets.
+ */
+ public void getTaskStackBounds(int width, int height, Rect taskStackBounds) {
+ if (hasSearchBarAppWidget()) {
+ Rect searchBarBounds = new Rect();
+ getSearchBarBounds(width, height, searchBarBounds);
+ if (isLandscape && transposeSearchLayoutWithOrientation) {
+ // In landscape, the search bar appears on the left, so shift the task rect right
+ taskStackBounds.set(searchBarBounds.width(), 0, width, height);
+ } else {
+ // In portrait, the search bar appears on the top, so shift the task rect below
+ taskStackBounds.set(0, searchBarBounds.height(), width, height);
+ }
+ } else {
+ taskStackBounds.set(0, 0, width, height);
+ }
+ }
+
+ /**
+ * Returns the search bar bounds in the current orientation. These bounds do not account for
+ * the system insets.
+ */
+ public void getSearchBarBounds(int width, int height, Rect searchBarSpaceBounds) {
// Return empty rects if search is not enabled
- if (!Constants.DebugFlags.App.EnableSearchButton) {
+ if (!Constants.DebugFlags.App.EnableSearchLayout) {
searchBarSpaceBounds.set(0, 0, 0, 0);
- searchBarBounds.set(0, 0, 0, 0);
return;
}
- // Calculate the search bar bounds, and account for the system insets
- int edgeMarginPx = searchBarSpaceEdgeMarginsPx;
- int availableWidth = width - systemInsets.left - systemInsets.right;
- searchBarSpaceBounds.set(0, 0, availableWidth, 2 * edgeMarginPx + searchBarSpaceHeightPx);
-
- // Inset from the search bar space to get the search bar bounds
- searchBarBounds.set(searchBarSpaceBounds);
- searchBarBounds.inset(edgeMarginPx, edgeMarginPx);
+ if (isLandscape && transposeSearchLayoutWithOrientation) {
+ // In landscape, the search bar appears on the left
+ searchBarSpaceBounds.set(0, 0, searchBarSpaceHeightPx, height);
+ } else {
+ // In portrait, the search bar appears on the top
+ searchBarSpaceBounds.set(0, 0, width, searchBarSpaceHeightPx);
+ }
}
/** Converts from DPs to PXs */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 36b761e..837cb34 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -45,7 +45,7 @@
@Override
public void handleMessage(Message msg) {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+ Console.log(Constants.Log.App.SystemUIHandshake,
"[RecentsService|handleMessage]", msg);
Context context = mContext.get();
@@ -60,39 +60,41 @@
Rect windowRect = data.getParcelable(AlternateRecentsComponent.KEY_WINDOW_RECT);
Rect systemInsets = data.getParcelable(AlternateRecentsComponent.KEY_SYSTEM_INSETS);
+ // NOTE: None of the rects computed below need to be offset for the status bar,
+ // since that is done when we compute the animation itself in the Recents component
+
// Create a dummy task stack & compute the rect for the thumbnail to animate to
TaskStack stack = new TaskStack(context);
TaskStackView tsv = new TaskStackView(context, stack);
Bundle replyData = new Bundle();
TaskViewTransform transform;
- // Get the search bar bounds so that we can account for its height in the children
- Rect searchBarSpaceBounds = new Rect();
- Rect searchBarBounds = new Rect();
+ // Get the task stack and search bar bounds
+ Rect taskStackBounds = new Rect();
RecentsConfiguration config = RecentsConfiguration.getInstance();
- config.getSearchBarBounds(windowRect.width(), windowRect.height(),
- searchBarSpaceBounds, searchBarBounds);
+ config.getTaskStackBounds(windowRect.width(), windowRect.height(), taskStackBounds);
- // Calculate the target task rect for when there is one task
+ // Calculate the target task rect for when there is one task.
+
// NOTE: Since the nav bar height is already accounted for in the windowRect, don't
- // pass in a bottom inset
+ // pass in a left or bottom inset
stack.addTask(new Task());
- tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top -
- systemInsets.bottom - searchBarSpaceBounds.height(), 0);
+ tsv.computeRects(taskStackBounds.width(), taskStackBounds.height() -
+ systemInsets.top - systemInsets.bottom, 0, 0);
tsv.boundScroll();
transform = tsv.getStackTransform(0, tsv.getStackScroll());
- transform.rect.offset(0, searchBarSpaceBounds.height());
+ transform.rect.offset(taskStackBounds.left, taskStackBounds.top);
replyData.putParcelable(AlternateRecentsComponent.KEY_SINGLE_TASK_STACK_RECT,
new Rect(transform.rect));
- // Also calculate the target task rect when there are multiple tasks
+ // Also calculate the target task rect when there are multiple tasks.
stack.addTask(new Task());
- tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top -
- systemInsets.bottom - searchBarSpaceBounds.height(), 0);
+ tsv.computeRects(taskStackBounds.width(), taskStackBounds.height() -
+ systemInsets.top - systemInsets.bottom, 0, 0);
tsv.setStackScrollRaw(Integer.MAX_VALUE);
tsv.boundScroll();
transform = tsv.getStackTransform(1, tsv.getStackScroll());
- transform.rect.offset(0, searchBarSpaceBounds.height());
+ transform.rect.offset(taskStackBounds.left, taskStackBounds.top);
replyData.putParcelable(AlternateRecentsComponent.KEY_MULTIPLE_TASK_STACK_RECT,
new Rect(transform.rect));
@@ -113,10 +115,10 @@
context.sendBroadcast(intent);
// Time this path
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
- Constants.DebugFlags.App.TimeRecentsStartupKey, "receivedToggleRecents");
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
- Constants.DebugFlags.App.TimeRecentsLaunchKey, "receivedToggleRecents");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "receivedToggleRecents");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+ Constants.Log.App.TimeRecentsLaunchKey, "receivedToggleRecents");
}
}
}
@@ -129,31 +131,31 @@
@Override
public void onCreate() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onCreate]");
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onCreate]");
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onBind]");
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onBind]");
return mSystemUIMessenger.getBinder();
}
@Override
public boolean onUnbind(Intent intent) {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onUnbind]");
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onUnbind]");
return super.onUnbind(intent);
}
@Override
public void onRebind(Intent intent) {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onRebind]");
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onRebind]");
super.onRebind(intent);
}
@Override
public void onDestroy() {
- Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onDestroy]");
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onDestroy]");
super.onDestroy();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index 52bba4a..c9038ee 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -51,7 +51,7 @@
/** Adds a new task to the load queue */
void addTask(Task t, boolean forceLoad) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, " [TaskResourceLoadQueue|addTask]");
+ Console.log(Constants.Log.App.TaskDataLoader, " [TaskResourceLoadQueue|addTask]");
if (!mQueue.contains(t)) {
mQueue.add(t);
}
@@ -68,7 +68,7 @@
* force reloaded.
*/
Pair<Task, Boolean> nextTask() {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, " [TaskResourceLoadQueue|nextTask]");
+ Console.log(Constants.Log.App.TaskDataLoader, " [TaskResourceLoadQueue|nextTask]");
Task task = mQueue.poll();
Boolean forceLoadTask = null;
if (task != null) {
@@ -82,14 +82,14 @@
/** Removes a task from the load queue */
void removeTask(Task t) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, " [TaskResourceLoadQueue|removeTask]");
+ Console.log(Constants.Log.App.TaskDataLoader, " [TaskResourceLoadQueue|removeTask]");
mQueue.remove(t);
mForceLoadSet.remove(t.key);
}
/** Clears all the tasks from the load queue */
void clearTasks() {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, " [TaskResourceLoadQueue|clearTasks]");
+ Console.log(Constants.Log.App.TaskDataLoader, " [TaskResourceLoadQueue|clearTasks]");
mQueue.clear();
mForceLoadSet.clear();
}
@@ -132,7 +132,7 @@
/** Restarts the loader thread */
void start(Context context) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|start]");
+ Console.log(Constants.Log.App.TaskDataLoader, "[TaskResourceLoader|start]");
mContext = context;
mCancelled = false;
mSystemServicesProxy = new SystemServicesProxy(context);
@@ -144,7 +144,7 @@
/** Requests the loader thread to stop after the current iteration */
void stop() {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|stop]");
+ Console.log(Constants.Log.App.TaskDataLoader, "[TaskResourceLoader|stop]");
// Mark as cancelled for the thread to pick up
mCancelled = true;
mSystemServicesProxy = null;
@@ -158,10 +158,10 @@
@Override
public void run() {
while (true) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[TaskResourceLoader|run|" + Thread.currentThread().getId() + "]");
if (mCancelled) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[TaskResourceLoader|cancel|" + Thread.currentThread().getId() + "]");
// We have to unset the context here, since the background thread may be using it
// when we call stop()
@@ -169,7 +169,7 @@
// If we are cancelled, then wait until we are started again
synchronized(mLoadThread) {
try {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[TaskResourceLoader|waitOnLoadThreadCancelled]");
mLoadThread.wait();
} catch (InterruptedException ie) {
@@ -186,7 +186,7 @@
if (t != null) {
Drawable loadIcon = mApplicationIconCache.get(t.key);
Bitmap loadThumbnail = mThumbnailCache.get(t.key);
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
" [TaskResourceLoader|load]",
t + " icon: " + loadIcon + " thumbnail: " + loadThumbnail +
" forceLoad: " + forceLoadTask);
@@ -197,7 +197,7 @@
Drawable icon = ssp.getActivityIcon(info, t.userId);
if (!mCancelled) {
if (icon != null) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
" [TaskResourceLoader|loadIcon]",
icon);
loadIcon = icon;
@@ -210,7 +210,7 @@
Bitmap thumbnail = ssp.getTaskThumbnail(t.key.id);
if (!mCancelled) {
if (thumbnail != null) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
" [TaskResourceLoader|loadThumbnail]",
thumbnail);
thumbnail.setHasAlpha(false);
@@ -240,7 +240,7 @@
if (!mCancelled && mLoadQueue.isEmpty()) {
synchronized(mLoadQueue) {
try {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[TaskResourceLoader|waitOnLoadQueue]");
mWaitingOnLoadQueue = true;
mLoadQueue.wait();
@@ -319,7 +319,7 @@
int thumbnailCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 :
mMaxThumbnailCacheSize;
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|init]", "thumbnailCache: " + thumbnailCacheSize +
" iconCache: " + iconCacheSize);
@@ -336,7 +336,7 @@
mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
mDefaultThumbnail.eraseColor(0x00000000);
mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|defaultBitmaps]",
"icon: " + mDefaultApplicationIcon + " thumbnail: " + mDefaultThumbnail, Console.AnsiRed);
}
@@ -366,10 +366,10 @@
List<ActivityManager.RecentTaskInfo> tasks =
ssp.getRecentTasks(25, UserHandle.CURRENT.getIdentifier());
Collections.reverse(tasks);
- Console.log(Constants.DebugFlags.App.TimeSystemCalls,
+ Console.log(Constants.Log.App.TimeSystemCalls,
"[RecentsTaskLoader|getRecentTasks]",
"" + (System.currentTimeMillis() - t1) + "ms");
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|tasks]", "" + tasks.size());
// Remove home/recents tasks
@@ -396,7 +396,7 @@
SpaceNode reload(Context context, int preloadCount) {
long t1 = System.currentTimeMillis();
- Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
+ Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
Resources res = context.getResources();
ArrayList<Task> tasksToForceLoad = new ArrayList<Task>();
TaskStack stack = new TaskStack(context);
@@ -415,21 +415,27 @@
ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent(), t.userId);
if (info == null) continue;
- String activityLabel = (t.activityLabel == null ? ssp.getActivityLabel(info) :
- t.activityLabel.toString());
+ ActivityManager.RecentsActivityValues av = t.activityValues;
+ String activityLabel = null;
BitmapDrawable activityIcon = null;
- if (t.activityIcon != null) {
- activityIcon = new BitmapDrawable(res, t.activityIcon);
+ int activityColor = 0;
+ if (av != null) {
+ activityLabel = (av.label != null ? av.label.toString() :
+ ssp.getActivityLabel(info));
+ activityIcon = (av.icon != null) ? new BitmapDrawable(res, av.icon) : null;
+ activityColor = av.colorPrimary;
+ } else {
+ activityLabel = ssp.getActivityLabel(info);
}
boolean isForemostTask = (i == (taskCount - 1));
// Create a new task
Task task = new Task(t.persistentId, (t.id > -1), t.baseIntent, activityLabel,
- activityIcon, t.userId);
+ activityIcon, activityColor, t.userId);
// Preload the specified number of apps
if (i >= (taskCount - preloadCount)) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|preloadTask]",
"i: " + i + " task: " + t.baseIntent.getComponent().getPackageName());
@@ -461,7 +467,7 @@
}
}
if (task.thumbnail == null) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|loadingTaskThumbnail]");
task.thumbnail = ssp.getTaskThumbnail(task.key.id);
if (task.thumbnail != null) {
@@ -474,11 +480,11 @@
}
// Add the task to the stack
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
" [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName());
stack.addTask(task);
}
- Console.log(Constants.DebugFlags.App.TimeSystemCalls,
+ Console.log(Constants.Log.App.TimeSystemCalls,
"[RecentsTaskLoader|getAllTaskTopThumbnail]",
"" + (System.currentTimeMillis() - t1) + "ms");
@@ -486,10 +492,10 @@
// Get all the stacks
t1 = System.currentTimeMillis();
List<ActivityManager.StackInfo> stackInfos = ams.getAllStackInfos();
- Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms");
- Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size());
+ Console.log(Constants.Log.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms");
+ Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size());
for (ActivityManager.StackInfo s : stackInfos) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, " [RecentsTaskLoader|stack]", s.toString());
+ Console.log(Constants.Log.App.TaskDataLoader, " [RecentsTaskLoader|stack]", s.toString());
if (stacks.containsKey(s.stackId)) {
stacks.get(s.stackId).setRect(s.bounds);
}
@@ -512,7 +518,7 @@
Drawable applicationIcon = mApplicationIconCache.get(t.key);
Bitmap thumbnail = mThumbnailCache.get(t.key);
- Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|loadTask]",
+ Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|loadTask]",
t + " applicationIcon: " + applicationIcon + " thumbnail: " + thumbnail +
" thumbnailCacheSize: " + mThumbnailCache.size());
@@ -533,7 +539,7 @@
/** Releases the task resource data back into the pool. */
public void unloadTaskData(Task t) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|unloadTask]", t +
" thumbnailCacheSize: " + mThumbnailCache.size());
@@ -543,7 +549,7 @@
/** Completely removes the resource data from the pool. */
public void deleteTaskData(Task t) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|deleteTask]", t);
mLoadQueue.removeTask(t);
@@ -554,13 +560,13 @@
/** Stops the task loader and clears all pending tasks */
void stopLoader() {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stopLoader]");
+ Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|stopLoader]");
mLoader.stop();
mLoadQueue.clearTasks();
}
void onTrimMemory(int level) {
- Console.log(Constants.DebugFlags.App.Memory, "[RecentsTaskLoader|onTrimMemory]",
+ Console.log(Constants.Log.App.Memory, "[RecentsTaskLoader|onTrimMemory]",
Console.trimMemoryLevelToString(level));
switch (level) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index 33ac0a8..b41555f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -20,7 +20,9 @@
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.SearchManager;
-import android.content.ActivityNotFoundException;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -35,8 +37,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
-import android.text.TextUtils;
-import android.util.Log;
+import android.util.Pair;
import java.util.ArrayList;
import java.util.List;
@@ -48,23 +49,32 @@
*/
public class SystemServicesProxy {
ActivityManager mAm;
+ AppWidgetManager mAwm;
PackageManager mPm;
IPackageManager mIpm;
UserManager mUm;
SearchManager mSm;
String mPackage;
+ ComponentName mAssistComponent;
Bitmap mDummyIcon;
/** Private constructor */
public SystemServicesProxy(Context context) {
mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ mAwm = AppWidgetManager.getInstance(context);
mPm = context.getPackageManager();
mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
mIpm = AppGlobals.getPackageManager();
mSm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
mPackage = context.getPackageName();
+ // Resolve the assist intent
+ Intent assist = mSm.getAssistIntent(context, false);
+ if (assist != null) {
+ mAssistComponent = assist.getComponent();
+ }
+
if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
// Create a dummy icon
mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
@@ -91,10 +101,13 @@
rti.id = rti.persistentId = i;
rti.baseIntent = new Intent();
rti.baseIntent.setComponent(cn);
- rti.description = rti.activityLabel = "" + i + " - " +
+ rti.activityValues = new ActivityManager.RecentsActivityValues();
+ rti.description = "" + i + " - " +
Long.toString(Math.abs(new Random().nextLong()), 36);
if (i % 2 == 0) {
- rti.activityIcon = Bitmap.createBitmap(mDummyIcon);
+ rti.activityValues.label = rti.description;
+ rti.activityValues.icon = Bitmap.createBitmap(mDummyIcon);
+ rti.activityValues.colorPrimary = new Random().nextInt();
}
tasks.add(rti);
}
@@ -103,7 +116,7 @@
return mAm.getRecentTasksForUser(numTasks,
ActivityManager.RECENT_IGNORE_UNAVAILABLE |
- ActivityManager.RECENT_INCLUDE_PROFILES, userId);
+ ActivityManager.RECENT_INCLUDE_PROFILES, userId);
}
/** Returns a list of the running tasks */
@@ -162,12 +175,12 @@
/**
* Returns the activity info for a given component name.
*
- * @param ComponentName The component name of the activity.
+ * @param cn The component name of the activity.
* @param userId The userId of the user that this is for.
*/
public ActivityInfo getActivityInfo(ComponentName cn, int userId) {
if (mIpm == null) return null;
- if (Constants.DebugFlags.App.EnableSystemServicesProxy) return null;
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) return new ActivityInfo();
try {
return mIpm.getActivityInfo(cn, PackageManager.GET_META_DATA, userId);
@@ -177,6 +190,23 @@
}
}
+ /**
+ * Returns the activity info for a given component name.
+ *
+ * @param cn The component name of the activity.
+ */
+ public ActivityInfo getActivityInfo(ComponentName cn) {
+ if (mPm == null) return null;
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) return new ActivityInfo();
+
+ try {
+ return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
/** Returns the activity label */
public String getActivityLabel(ActivityInfo info) {
if (mPm == null) return null;
@@ -208,27 +238,54 @@
return icon;
}
+ /**
+ * Resolves and binds the search app widget that is to appear in the recents.
+ */
+ public Pair<Integer, AppWidgetProviderInfo> bindSearchAppWidget(AppWidgetHost host) {
+ if (mAwm == null) return null;
+ if (mAssistComponent == null) return null;
+
+ // Find the first Recents widget from the same package as the global assist activity
+ List<AppWidgetProviderInfo> widgets = mAwm.getInstalledProviders(
+ AppWidgetProviderInfo.WIDGET_CATEGORY_RECENTS);
+ AppWidgetProviderInfo searchWidgetInfo = null;
+ for (AppWidgetProviderInfo info : widgets) {
+ if (info.provider.getPackageName().equals(mAssistComponent.getPackageName())) {
+ searchWidgetInfo = info;
+ break;
+ }
+ }
+
+ // Return early if there is no search widget
+ if (searchWidgetInfo == null) return null;
+
+ // Allocate a new widget id and try and bind the app widget (if that fails, then just skip)
+ int searchWidgetId = host.allocateAppWidgetId();
+ Bundle opts = new Bundle();
+ opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
+ AppWidgetProviderInfo.WIDGET_CATEGORY_RECENTS);
+ if (!mAwm.bindAppWidgetIdIfAllowed(searchWidgetId, searchWidgetInfo.provider, opts)) {
+ return null;
+ }
+ return new Pair<Integer, AppWidgetProviderInfo>(searchWidgetId, searchWidgetInfo);
+ }
/**
- * Composes an intent to launch the global search activity.
+ * Returns the app widget info for the specified app widget id.
*/
- public Intent getGlobalSearchIntent(Rect sourceBounds) {
- if (mSm == null) return null;
+ public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
+ if (mAwm == null) return null;
- // Try and get the global search activity
- ComponentName globalSearchActivity = mSm.getGlobalSearchActivity();
- if (globalSearchActivity == null) return null;
+ return mAwm.getAppWidgetInfo(appWidgetId);
+ }
- // Bundle the source of the search
- Bundle appSearchData = new Bundle();
- appSearchData.putString("source", mPackage);
+ /**
+ * Destroys the specified app widget.
+ */
+ public void unbindSearchAppWidget(AppWidgetHost host, int appWidgetId) {
+ if (mAwm == null) return;
- // Compose the intent and Start the search activity
- Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.setComponent(globalSearchActivity);
- intent.putExtra(SearchManager.APP_DATA, appSearchData);
- intent.setSourceBounds(sourceBounds);
- return intent;
+ // Delete the app widget
+ host.deleteAppWidgetId(appWidgetId);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
index 4a1b3b2..b602f84 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
@@ -16,6 +16,7 @@
package com.android.systemui.recents;
+import android.graphics.Color;
import android.graphics.Rect;
/* Common code */
@@ -46,4 +47,19 @@
r.offset(cx, cy);
}
}
+
+ /** Calculates the luminance-preserved greyscale of a given color. */
+ private static int colorToGreyscale(int color) {
+ return Math.round(0.2126f * Color.red(color) + 0.7152f * Color.green(color) +
+ 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();
+ int greyscale = colorToGreyscale(color);
+ return (greyscale < 128) ? configuration.taskBarViewLightTextColor :
+ configuration.taskBarViewDarkTextColor;
+
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 1566a49..47a506c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -72,6 +72,7 @@
public Drawable applicationIcon;
public Drawable activityIcon;
public String activityLabel;
+ public int colorPrimary;
public Bitmap thumbnail;
public boolean isActive;
public int userId;
@@ -83,10 +84,11 @@
}
public Task(int id, boolean isActive, Intent intent, String activityTitle,
- BitmapDrawable activityIcon, int userId) {
+ BitmapDrawable activityIcon, int colorPrimary, int userId) {
this.key = new TaskKey(id, intent, userId);
this.activityLabel = activityTitle;
this.activityIcon = activityIcon;
+ this.colorPrimary = colorPrimary;
this.isActive = isActive;
this.userId = userId;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index a04cd3e..eb7b5c6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -27,11 +27,9 @@
import android.net.Uri;
import android.os.UserHandle;
import android.provider.Settings;
-import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
-import android.widget.TextView;
import com.android.systemui.recents.Console;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
@@ -39,7 +37,6 @@
import com.android.systemui.recents.model.SpaceNode;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.R;
import java.util.ArrayList;
@@ -57,6 +54,8 @@
// The space partitioning root of this container
SpaceNode mBSP;
+ // Whether there are any tasks
+ boolean mHasTasks;
// Search bar view
View mSearchBar;
// Recents view callbacks
@@ -80,22 +79,14 @@
mBSP = n;
// Create and add all the stacks for this partition of space.
- boolean hasTasks = false;
+ mHasTasks = false;
removeAllViews();
ArrayList<TaskStack> stacks = mBSP.getStacks();
for (TaskStack stack : stacks) {
TaskStackView stackView = new TaskStackView(getContext(), stack);
stackView.setCallbacks(this);
addView(stackView);
- hasTasks |= (stack.getTaskCount() > 0);
- }
-
- // Create the search bar (and hide it if we have no recent tasks)
- if (Constants.DebugFlags.App.EnableSearchButton) {
- createSearchBar();
- if (!hasTasks) {
- mSearchBar.setVisibility(View.GONE);
- }
+ mHasTasks |= (stack.getTaskCount() > 0);
}
}
@@ -130,19 +121,30 @@
return false;
}
- /** Creates and adds the search bar */
- void createSearchBar() {
- // Create a temporary search bar
- mSearchBar = mInflater.inflate(R.layout.recents_search_bar, this, false);
- mSearchBar.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- onSearchTriggered();
+ /** Adds the search bar */
+ public void setSearchBar(View searchBar) {
+ // Create the search bar (and hide it if we have no recent tasks)
+ if (Constants.DebugFlags.App.EnableSearchLayout) {
+ // Remove the previous search bar if one exists
+ if (mSearchBar != null && indexOfChild(mSearchBar) > -1) {
+ removeView(mSearchBar);
}
- });
- addView(mSearchBar);
+ // Add the new search bar
+ if (searchBar != null) {
+ mSearchBar = searchBar;
+ mSearchBar.setVisibility(mHasTasks ? View.VISIBLE : View.GONE);
+ addView(mSearchBar);
+
+ Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsView|setSearchBar]",
+ "" + (mSearchBar.getVisibility() == View.VISIBLE),
+ Console.AnsiBlue);
+ }
+ }
}
+ /**
+ * This is called with the full size of the window since we are handling our own insets.
+ */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
@@ -150,27 +152,31 @@
int height = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|measure]",
+ Console.log(Constants.Log.UI.MeasureAndLayout, "[RecentsView|measure]",
"width: " + width + " height: " + height, Console.AnsiGreen);
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
- Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onMeasure");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "RecentsView.onMeasure");
- // Get the search bar bounds so that we can account for its height in the children
- Rect searchBarSpaceBounds = new Rect();
- Rect searchBarBounds = new Rect();
+ // Get the search bar bounds and measure the search bar layout
RecentsConfiguration config = RecentsConfiguration.getInstance();
- config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
- searchBarSpaceBounds, searchBarBounds);
if (mSearchBar != null) {
- mSearchBar.measure(MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), widthMode),
- MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), heightMode));
+ Rect searchBarSpaceBounds = new Rect();
+ config.getSearchBarBounds(width, height - config.systemInsets.top, searchBarSpaceBounds);
+ mSearchBar.measure(
+ MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), MeasureSpec.EXACTLY));
}
- // We measure our stack views sans the status bar. It will handle the nav bar itself.
+ // We give the full width of the space, not including the right nav bar insets in landscape,
+ // to the stack view, since we want the tasks to render under the search bar in landscape.
+ // In addition, we give it the full height, not including the top inset or search bar space,
+ // since we want the tasks to render under the navigation buttons in portrait.
+ Rect taskStackBounds = new Rect();
+ config.getTaskStackBounds(width, height, taskStackBounds);
int childWidth = width - config.systemInsets.right;
- int childHeight = height - config.systemInsets.top - searchBarSpaceBounds.height();
+ int childHeight = taskStackBounds.height() - config.systemInsets.top;
- // Measure each child
+ // Measure each TaskStackView
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
@@ -183,28 +189,34 @@
setMeasuredDimension(width, height);
}
+ /**
+ * This is called with the full size of the window since we are handling our own insets.
+ */
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|layout]",
+ Console.log(Constants.Log.UI.MeasureAndLayout, "[RecentsView|layout]",
new Rect(left, top, right, bottom) + " changed: " + changed, Console.AnsiGreen);
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
- Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onLayout");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "RecentsView.onLayout");
- // Get the search bar bounds so that we can account for its height in the children
- Rect searchBarSpaceBounds = new Rect();
- Rect searchBarBounds = new Rect();
+ // Get the search bar bounds so that we lay it out
RecentsConfiguration config = RecentsConfiguration.getInstance();
- config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
- searchBarSpaceBounds, searchBarBounds);
if (mSearchBar != null) {
+ Rect searchBarSpaceBounds = new Rect();
+ config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(), searchBarSpaceBounds);
mSearchBar.layout(config.systemInsets.left + searchBarSpaceBounds.left,
config.systemInsets.top + searchBarSpaceBounds.top,
config.systemInsets.left + mSearchBar.getMeasuredWidth(),
config.systemInsets.top + mSearchBar.getMeasuredHeight());
}
- // We offset our stack views by the status bar height. It will handle the nav bar itself.
- top += config.systemInsets.top + searchBarSpaceBounds.height();
+ // We offset the stack view by the left inset (if any), but lay it out under the search bar.
+ // In addition, we offset our stack views by the top inset and search bar height, but not
+ // the bottom insets because we want it to render under the navigation buttons.
+ Rect taskStackBounds = new Rect();
+ config.getTaskStackBounds(getMeasuredWidth(), getMeasuredHeight(), taskStackBounds);
+ left += config.systemInsets.left;
+ top += config.systemInsets.top + taskStackBounds.top;
// Layout each child
// XXX: Based on the space node for that task view
@@ -212,23 +224,22 @@
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child instanceof TaskStackView && child.getVisibility() != GONE) {
- int width = child.getMeasuredWidth();
- int height = child.getMeasuredHeight();
- child.layout(left, top, left + width, top + height);
+ TaskStackView tsv = (TaskStackView) child;
+ child.layout(left, top, left + tsv.getMeasuredWidth(), top + tsv.getMeasuredHeight());
}
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
- Console.log(Constants.DebugFlags.UI.Draw, "[RecentsView|dispatchDraw]", "",
+ Console.log(Constants.Log.UI.Draw, "[RecentsView|dispatchDraw]", "",
Console.AnsiPurple);
super.dispatchDraw(canvas);
}
@Override
protected boolean fitSystemWindows(Rect insets) {
- Console.log(Constants.DebugFlags.UI.MeasureAndLayout,
+ Console.log(Constants.Log.UI.MeasureAndLayout,
"[RecentsView|fitSystemWindows]", "insets: " + insets, Console.AnsiGreen);
// Update the configuration with the latest system insets and trigger a relayout
@@ -348,16 +359,16 @@
}
}
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
- Constants.DebugFlags.App.TimeRecentsLaunchKey, "startActivity");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+ Constants.Log.App.TimeRecentsLaunchKey, "startActivity");
}
};
- Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
- Constants.DebugFlags.App.TimeRecentsLaunchKey, "onTaskLaunched");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+ Constants.Log.App.TimeRecentsLaunchKey, "onTaskLaunched");
// Launch the app right away if there is no task view, otherwise, animate the icon out first
- if (tv == null || !Constants.Values.TaskView.AnimateFrontTaskBarOnLeavingRecents) {
+ if (tv == null) {
post(launchRunnable);
} else {
tv.animateOnLeavingRecents(launchRunnable);
@@ -374,24 +385,4 @@
TaskStackBuilder.create(getContext())
.addNextIntentWithParentStack(intent).startActivities();
}
-
- public void onSearchTriggered() {
- // Get the search bar source bounds
- Rect searchBarSpaceBounds = new Rect();
- Rect searchBarBounds = new Rect();
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
- searchBarSpaceBounds, searchBarBounds);
-
- // Get the search intent and start it
- Intent searchIntent = RecentsTaskLoader.getInstance().getSystemServicesProxy()
- .getGlobalSearchIntent(searchBarBounds);
- if (searchIntent != null) {
- try {
- getContext().startActivity(searchIntent);
- } catch (ActivityNotFoundException anfe) {
- Console.logError(getContext(), "Could not start Search activity");
- }
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
index 21ef9ff..c34300c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
@@ -178,7 +178,7 @@
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
- Console.log(Constants.DebugFlags.UI.TouchEvents,
+ Console.log(Constants.Log.UI.TouchEvents,
"[SwipeHelper|interceptTouchEvent]",
Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
final int action = ev.getAction();
@@ -291,7 +291,7 @@
}
public boolean onTouchEvent(MotionEvent ev) {
- Console.log(Constants.DebugFlags.UI.TouchEvents,
+ Console.log(Constants.Log.UI.TouchEvents,
"[SwipeHelper|touchEvent]",
Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
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 124f11e..c6cb812 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
@@ -18,11 +18,13 @@
import android.content.Context;
import android.util.AttributeSet;
-import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.systemui.R;
+import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.Utilities;
import com.android.systemui.recents.model.Task;
@@ -58,6 +60,7 @@
/** Binds the bar view to the task */
void rebindToTask(Task t, boolean animate) {
+ RecentsConfiguration configuration = RecentsConfiguration.getInstance();
mTask = t;
// If an activity icon is defined, then we use that as the primary icon to show in the bar,
// otherwise, we fall back to the application icon
@@ -67,6 +70,15 @@
mApplicationIcon.setImageDrawable(t.applicationIcon);
}
mActivityDescription.setText(t.activityLabel);
+ // Try and apply the system ui tint
+ int tint = t.colorPrimary;
+ if (Constants.DebugFlags.App.EnableTaskBarThemeColors && tint != 0) {
+ setBackgroundColor(tint);
+ mActivityDescription.setTextColor(Utilities.getIdealTextColorForBackgroundColor(tint));
+ } else {
+ setBackgroundColor(configuration.taskBarViewDefaultBackgroundColor);
+ mActivityDescription.setTextColor(configuration.taskBarViewDefaultTextColor);
+ }
if (animate) {
// XXX: Investigate how expensive it will be to create a second bitmap and crossfade
}
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 a81d01c..c6c29a6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
@@ -20,16 +20,21 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.drawable.TouchFeedbackDrawable;
import android.util.AttributeSet;
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;
+import com.android.systemui.recents.model.Task;
/* The task info view */
@@ -143,6 +148,25 @@
.start();
}
+ /** Binds the info view to the task */
+ void rebindToTask(Task t, boolean animate) {
+ RecentsConfiguration configuration = RecentsConfiguration.getInstance();
+ if (Constants.DebugFlags.App.EnableTaskBarThemeColors && t.colorPrimary != 0) {
+ setBackgroundColor(t.colorPrimary);
+ // Workaround: The button currently doesn't support setting a custom background tint
+ // not defined in the theme. Just lower the alpha on the button to make it blend more
+ // into the background.
+ if (mAppInfoButton.getBackground() instanceof TouchFeedbackDrawable) {
+ TouchFeedbackDrawable d = (TouchFeedbackDrawable) mAppInfoButton.getBackground();
+ if (d != null) {
+ d.setAlpha(96);
+ }
+ }
+ } else {
+ setBackgroundColor(configuration.taskBarViewDefaultBackgroundColor);
+ }
+ }
+
@Override
public void draw(Canvas canvas) {
int saveCount = 0;
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 0a8e76f..cfacd18 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -18,7 +18,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
@@ -110,7 +109,7 @@
requestSynchronizeStackViewsWithModel(0);
}
void requestSynchronizeStackViewsWithModel(int duration) {
- Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
+ Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
"[TaskStackView|requestSynchronize]", "" + duration + "ms", Console.AnsiYellow);
if (!mStackViewsDirty) {
invalidate();
@@ -215,7 +214,7 @@
/** Synchronizes the views with the model */
void synchronizeStackViewsWithModel() {
- Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
+ Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
"[TaskStackView|synchronizeViewsWithModel]",
"mStackViewsDirty: " + mStackViewsDirty, Console.AnsiYellow);
if (mStackViewsDirty) {
@@ -271,7 +270,7 @@
}
}
- Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
+ Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
" [TaskStackView|viewChildren]", "" + getChildCount());
mStackViewsAnimationDuration = 0;
@@ -395,12 +394,20 @@
return false;
}
- /** Returns whether the specified scroll is out of bounds */
- boolean isScrollOutOfBounds(int scroll) {
- return (scroll < mMinScroll) || (scroll > mMaxScroll);
+
+ /** Returns the amount that the scroll is out of bounds */
+ int getScrollAmountOutOfBounds(int scroll) {
+ if (scroll < mMinScroll) {
+ return mMinScroll - scroll;
+ } else if (scroll > mMaxScroll) {
+ return scroll - mMaxScroll;
+ }
+ return 0;
}
+
+ /** Returns whether the specified scroll is out of bounds */
boolean isScrollOutOfBounds() {
- return isScrollOutOfBounds(getStackScroll());
+ return getScrollAmountOutOfBounds(getStackScroll()) != 0;
}
/** Updates the min and max virtual scroll bounds */
@@ -421,7 +428,7 @@
}
// Debug logging
- if (Constants.DebugFlags.UI.MeasureAndLayout) {
+ if (Constants.Log.UI.MeasureAndLayout) {
Console.log(" [TaskStack|minScroll] " + mMinScroll);
Console.log(" [TaskStack|maxScroll] " + mMaxScroll);
}
@@ -448,7 +455,7 @@
/** Enables the hw layers and increments the hw layer requirement ref count */
void addHwLayersRefCount(String reason) {
- Console.log(Constants.DebugFlags.UI.HwLayers,
+ Console.log(Constants.Log.UI.HwLayers,
"[TaskStackView|addHwLayersRefCount] refCount: " +
mHwLayersRefCount + "->" + (mHwLayersRefCount + 1) + " " + reason);
if (mHwLayersRefCount == 0) {
@@ -465,7 +472,7 @@
/** Decrements the hw layer requirement ref count and disables the hw layers when we don't
need them anymore. */
void decHwLayersRefCount(String reason) {
- Console.log(Constants.DebugFlags.UI.HwLayers,
+ Console.log(Constants.Log.UI.HwLayers,
"[TaskStackView|decHwLayersRefCount] refCount: " +
mHwLayersRefCount + "->" + (mHwLayersRefCount - 1) + " " + reason);
mHwLayersRefCount--;
@@ -507,7 +514,7 @@
@Override
public void dispatchDraw(Canvas canvas) {
- Console.log(Constants.DebugFlags.UI.Draw, "[TaskStackView|dispatchDraw]", "",
+ Console.log(Constants.Log.UI.Draw, "[TaskStackView|dispatchDraw]", "",
Console.AnsiPurple);
synchronizeStackViewsWithModel();
super.dispatchDraw(canvas);
@@ -547,7 +554,7 @@
}
/** Computes the stack and task rects */
- public void computeRects(int width, int height, int insetBottom) {
+ public void computeRects(int width, int height, int insetLeft, int insetBottom) {
// Note: We let the stack view be the full height because we want the cards to go under the
// navigation bar if possible. However, the stack rects which we use to calculate
// max scroll, etc. need to take the nav bar into account
@@ -555,12 +562,13 @@
// Compute the stack rects
mRect.set(0, 0, width, height);
mStackRect.set(mRect);
+ mStackRect.left += insetLeft;
mStackRect.bottom -= insetBottom;
int smallestDimension = Math.min(width, height);
int padding = (int) (Constants.Values.TaskStackView.StackPaddingPct * smallestDimension / 2f);
- if (Constants.DebugFlags.App.EnableSearchButton) {
- // Don't need to pad the top since we have some padding on the search bar already
+ if (Constants.DebugFlags.App.EnableSearchLayout) {
+ mStackRect.top += padding;
mStackRect.left += padding;
mStackRect.right -= padding;
mStackRect.bottom -= padding;
@@ -582,20 +590,27 @@
updateMinMaxScroll(false);
}
+ /**
+ * This is called with the size of the space not including the top or right insets, or the
+ * search bar height in portrait (but including the search bar width in landscape, since we want
+ * to draw under it.
+ */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
- Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[TaskStackView|measure]",
+ Console.log(Constants.Log.UI.MeasureAndLayout, "[TaskStackView|measure]",
"width: " + width + " height: " + height +
" awaitingFirstLayout: " + mAwaitingFirstLayout, Console.AnsiGreen);
// Compute our stack/task rects
RecentsConfiguration config = RecentsConfiguration.getInstance();
- computeRects(width, height, config.systemInsets.bottom);
+ Rect taskStackBounds = new Rect();
+ config.getTaskStackBounds(width, height, taskStackBounds);
+ computeRects(width, height, taskStackBounds.left, config.systemInsets.bottom);
// Debug logging
- if (Constants.DebugFlags.UI.MeasureAndLayout) {
+ if (Constants.Log.UI.MeasureAndLayout) {
Console.log(" [TaskStack|fullRect] " + mRect);
Console.log(" [TaskStack|stackRect] " + mStackRect);
Console.log(" [TaskStack|stackRectSansPeek] " + mStackRectSansPeek);
@@ -610,8 +625,7 @@
synchronizeStackViewsWithModel();
// Animate the task bar of the first task view
- if (config.launchedWithThumbnailAnimation &&
- Constants.Values.TaskView.AnimateFrontTaskBarOnEnterRecents) {
+ if (config.launchedWithThumbnailAnimation) {
TaskView tv = (TaskView) getChildAt(getChildCount() - 1);
if (tv != null) {
tv.animateOnEnterRecents();
@@ -630,13 +644,18 @@
setMeasuredDimension(width, height);
}
+ /**
+ * This is called with the size of the space not including the top or right insets, or the
+ * search bar height in portrait (but including the search bar width in landscape, since we want
+ * to draw under it.
+ */
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[TaskStackView|layout]",
+ Console.log(Constants.Log.UI.MeasureAndLayout, "[TaskStackView|layout]",
"" + new Rect(left, top, right, bottom), Console.AnsiGreen);
// Debug logging
- if (Constants.DebugFlags.UI.MeasureAndLayout) {
+ if (Constants.Log.UI.MeasureAndLayout) {
Console.log(" [TaskStack|fullRect] " + mRect);
Console.log(" [TaskStack|stackRect] " + mStackRect);
Console.log(" [TaskStack|stackRectSansPeek] " + mStackRectSansPeek);
@@ -890,7 +909,7 @@
@Override
public TaskView createView(Context context) {
- Console.log(Constants.DebugFlags.ViewPool.PoolCallbacks, "[TaskStackView|createPoolView]");
+ Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|createPoolView]");
return (TaskView) mInflater.inflate(R.layout.recents_task_view, this, false);
}
@@ -898,7 +917,7 @@
public void prepareViewToEnterPool(TaskView tv) {
Task task = tv.getTask();
tv.resetViewProperties();
- Console.log(Constants.DebugFlags.ViewPool.PoolCallbacks, "[TaskStackView|returnToPool]",
+ Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|returnToPool]",
tv.getTask() + " tv: " + tv);
// Report that this tasks's data is no longer being used
@@ -914,7 +933,7 @@
@Override
public void prepareViewToLeavePool(TaskView tv, Task prepareData, boolean isNewView) {
- Console.log(Constants.DebugFlags.ViewPool.PoolCallbacks, "[TaskStackView|leavePool]",
+ Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|leavePool]",
"isNewView: " + isNewView);
// Setup and attach the view to the window
@@ -937,7 +956,7 @@
}
// Add/attach the view to the hierarchy
- Console.log(Constants.DebugFlags.ViewPool.PoolCallbacks, " [TaskStackView|insertIndex]",
+ Console.log(Constants.Log.ViewPool.PoolCallbacks, " [TaskStackView|insertIndex]",
"" + insertIndex);
if (isNewView) {
addView(tv, insertIndex);
@@ -967,7 +986,7 @@
@Override
public void onTaskIconClicked(TaskView tv) {
- Console.log(Constants.DebugFlags.UI.ClickEvents, "[TaskStack|Clicked|Icon]",
+ Console.log(Constants.Log.UI.ClickEvents, "[TaskStack|Clicked|Icon]",
tv.getTask() + " is currently filtered: " + mStack.hasFilteredTasks(),
Console.AnsiCyan);
if (Constants.DebugFlags.App.EnableTaskFiltering) {
@@ -1003,7 +1022,7 @@
public void onClick(View v) {
TaskView tv = (TaskView) v;
Task task = tv.getTask();
- Console.log(Constants.DebugFlags.UI.ClickEvents, "[TaskStack|Clicked|Thumbnail]",
+ Console.log(Constants.Log.UI.ClickEvents, "[TaskStack|Clicked|Thumbnail]",
task + " cb: " + mCb);
// Close any open info panes if the user taps on another task
@@ -1128,7 +1147,7 @@
/** Touch preprocessing for handling below */
public boolean onInterceptTouchEvent(MotionEvent ev) {
- Console.log(Constants.DebugFlags.UI.TouchEvents,
+ Console.log(Constants.Log.UI.TouchEvents,
"[TaskStackViewTouchHandler|interceptTouchEvent]",
Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
@@ -1212,7 +1231,7 @@
/** Handles touch events once we have intercepted them */
public boolean onTouchEvent(MotionEvent ev) {
- Console.log(Constants.DebugFlags.UI.TouchEvents,
+ Console.log(Constants.Log.UI.TouchEvents,
"[TaskStackViewTouchHandler|touchEvent]",
Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
@@ -1284,9 +1303,13 @@
}
if (mIsScrolling) {
int curStackScroll = mSv.getStackScroll();
- if (mSv.isScrollOutOfBounds(curStackScroll + deltaY)) {
- // Scale the touch if we are overscrolling
- deltaY /= Constants.Values.TaskStackView.TouchOverscrollScaleFactor;
+ int overScrollAmount = mSv.getScrollAmountOutOfBounds(curStackScroll + deltaY);
+ if (overScrollAmount != 0) {
+ // Bound the overscroll to a fixed amount, and inversely scale the y-movement
+ // relative to how close we are to the max overscroll
+ float maxOverScroll = mSv.mTaskRect.height() / 3f;
+ deltaY = Math.round(deltaY * (1f - (Math.min(maxOverScroll, overScrollAmount)
+ / maxOverScroll)));
}
mSv.setStackScroll(curStackScroll + deltaY);
if (mSv.isScrollOutOfBounds()) {
@@ -1306,11 +1329,12 @@
if (mIsScrolling && (Math.abs(velocity) > mMinimumVelocity)) {
// Enable HW layers on the stack
mSv.addHwLayersRefCount("flingScroll");
+ // XXX: Make this animation a function of the velocity AND distance
int overscrollRange = (int) (Math.min(1f,
Math.abs((float) velocity / mMaximumVelocity)) *
Constants.Values.TaskStackView.TaskStackOverscrollRange);
- Console.log(Constants.DebugFlags.UI.TouchEvents,
+ Console.log(Constants.Log.UI.TouchEvents,
"[TaskStackViewTouchHandler|fling]",
"scroll: " + mSv.getStackScroll() + " velocity: " + velocity +
" maxVelocity: " + mMaximumVelocity +
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 d3b79d6..45c2fae 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -20,6 +20,7 @@
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.Outline;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
@@ -33,7 +34,6 @@
import com.android.systemui.recents.BakedBezierInterpolator;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.Utilities;
import com.android.systemui.recents.model.Task;
@@ -108,6 +108,11 @@
mRoundedRectClipPath.reset();
mRoundedRectClipPath.addRoundRect(new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight()),
radius, radius, Path.Direction.CW);
+
+ // Update the outline
+ Outline o = new Outline();
+ o.setRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), radius);
+ setOutline(o);
}
@Override
@@ -134,13 +139,23 @@
/** Synchronizes this view's properties with the task's transform */
void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
TaskViewTransform toTransform, int duration) {
+ RecentsConfiguration config = RecentsConfiguration.getInstance();
+ int minZ = config.taskViewTranslationZMinPx;
+ int incZ = config.taskViewTranslationZIncrementPx;
+
if (duration > 0) {
if (animateFromTransform != null) {
setTranslationY(animateFromTransform.translationY);
+ if (Constants.DebugFlags.App.EnableShadows) {
+ setTranslationZ(Math.max(minZ, minZ + (animateFromTransform.t * incZ)));
+ }
setScaleX(animateFromTransform.scale);
setScaleY(animateFromTransform.scale);
setAlpha(animateFromTransform.alpha);
}
+ if (Constants.DebugFlags.App.EnableShadows) {
+ animate().translationZ(Math.max(minZ, minZ + (toTransform.t * incZ)));
+ }
animate().translationY(toTransform.translationY)
.scaleX(toTransform.scale)
.scaleY(toTransform.scale)
@@ -157,6 +172,9 @@
.start();
} else {
setTranslationY(toTransform.translationY);
+ if (Constants.DebugFlags.App.EnableShadows) {
+ setTranslationZ(Math.max(minZ, minZ + (toTransform.t * incZ)));
+ }
setScaleX(toTransform.scale);
setScaleY(toTransform.scale);
setAlpha(toTransform.alpha);
@@ -169,6 +187,9 @@
void resetViewProperties() {
setTranslationX(0f);
setTranslationY(0f);
+ if (Constants.DebugFlags.App.EnableShadows) {
+ setTranslationZ(0f);
+ }
setScaleX(1f);
setScaleY(1f);
setAlpha(1f);
@@ -197,18 +218,9 @@
/** Animates this task view as it enters recents */
public void animateOnEnterRecents() {
RecentsConfiguration config = RecentsConfiguration.getInstance();
- int translate = config.pxFromDp(10);
- mBarView.setScaleX(1.25f);
- mBarView.setScaleY(1.25f);
mBarView.setAlpha(0f);
- mBarView.setTranslationX(translate / 2);
- mBarView.setTranslationY(-translate);
mBarView.animate()
.alpha(1f)
- .scaleX(1f)
- .scaleY(1f)
- .translationX(0)
- .translationY(0)
.setStartDelay(235)
.setInterpolator(BakedBezierInterpolator.INSTANCE)
.setDuration(config.taskBarEnterAnimDuration)
@@ -219,16 +231,11 @@
/** Animates this task view as it exits recents */
public void animateOnLeavingRecents(final Runnable r) {
RecentsConfiguration config = RecentsConfiguration.getInstance();
- int translate = config.pxFromDp(10);
mBarView.animate()
.alpha(0f)
- .scaleX(1.1f)
- .scaleY(1.1f)
- .translationX(translate / 2)
- .translationY(-translate)
.setStartDelay(0)
.setInterpolator(BakedBezierInterpolator.INSTANCE)
- .setDuration(Utilities.calculateTranslationAnimationDuration(translate))
+ .setDuration(config.taskBarExitAnimDuration)
.withLayer()
.withEndAction(new Runnable() {
@Override
@@ -352,6 +359,7 @@
// Bind each of the views to the new task data
mThumbnailView.rebindToTask(mTask, reloadingTaskData);
mBarView.rebindToTask(mTask, reloadingTaskData);
+ mInfoView.rebindToTask(mTask, reloadingTaskData);
// Rebind any listeners
mBarView.mApplicationIcon.setOnClickListener(this);
mInfoView.mAppInfoButton.setOnClickListener(this);
@@ -376,7 +384,7 @@
@Override
public void onClick(View v) {
if (v == mInfoView) {
- // Do nothing
+ hideInfoPane();
} else if (v == mBarView.mApplicationIcon) {
mCb.onTaskIconClicked(this);
} else if (v == mInfoView.mAppInfoButton) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 0f32dc0..91df9ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -16,12 +16,18 @@
package com.android.systemui.statusbar;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
-import android.widget.FrameLayout;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import com.android.internal.R;
@@ -32,9 +38,9 @@
public abstract class ActivatableNotificationView extends ExpandableOutlineView {
private static final long DOUBLETAP_TIMEOUT_MS = 1000;
+ private static final int BACKGROUND_ANIMATION_LENGTH_MS = 220;
private boolean mDimmed;
- private boolean mLocked;
private int mBgResId = R.drawable.notification_quantum_bg;
private int mDimmedBgResId = R.drawable.notification_quantum_bg_dim;
@@ -51,13 +57,20 @@
private OnActivatedListener mOnActivatedListener;
+ protected Drawable mBackgroundNormal;
+ protected Drawable mBackgroundDimmed;
+ private ObjectAnimator mBackgroundAnimator;
+ private Interpolator mFastOutSlowInInterpolator;
+
public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
updateBackgroundResource();
+ setWillNotDraw(false);
+ mFastOutSlowInInterpolator =
+ AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
}
-
private final Runnable mTapTimeoutRunnable = new Runnable() {
@Override
public void run() {
@@ -66,20 +79,51 @@
};
@Override
+ protected void onDraw(Canvas canvas) {
+ draw(canvas, mBackgroundNormal);
+ draw(canvas, mBackgroundDimmed);
+ }
+
+ private void draw(Canvas canvas, Drawable drawable) {
+ if (drawable != null) {
+ drawable.setBounds(0, mClipTopAmount, getWidth(), mActualHeight);
+ drawable.draw(canvas);
+ }
+ }
+
+ @Override
+ protected boolean verifyDrawable(Drawable who) {
+ return super.verifyDrawable(who) || who == mBackgroundNormal
+ || who == mBackgroundDimmed;
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ drawableStateChanged(mBackgroundNormal);
+ drawableStateChanged(mBackgroundDimmed);
+ }
+
+ private void drawableStateChanged(Drawable d) {
+ if (d != null && d.isStateful()) {
+ d.setState(getDrawableState());
+ }
+ }
+
+ @Override
public void setOnClickListener(OnClickListener l) {
super.setOnClickListener(l);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
- if (mLocked) {
- return handleTouchEventLocked(event);
+ if (mDimmed) {
+ return handleTouchEventDimmed(event);
} else {
return super.onTouchEvent(event);
}
}
- private boolean handleTouchEventLocked(MotionEvent event) {
+ private boolean handleTouchEventDimmed(MotionEvent event) {
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
@@ -88,14 +132,6 @@
if (mDownY > getActualHeight()) {
return false;
}
-
- // Call the listener tentatively directly, even if we don't know whether the user
- // will stay within the touch slop, as the listener is implemented as a scale
- // animation, which is cancellable without jarring effects when swiping away
- // notifications.
- if (mOnActivatedListener != null) {
- mOnActivatedListener.onActivated(this);
- }
break;
case MotionEvent.ACTION_MOVE:
if (!isWithinTouchSlop(event)) {
@@ -109,8 +145,8 @@
makeActive(event.getX(), event.getY());
postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
} else {
- performClick();
makeInactive();
+ performClick();
}
} else {
makeInactive();
@@ -126,8 +162,11 @@
}
private void makeActive(float x, float y) {
- mCustomBackground.setHotspot(0, x, y);
+ mBackgroundDimmed.setHotspot(0, x, y);
mActivated = true;
+ if (mOnActivatedListener != null) {
+ mOnActivatedListener.onActivated(this);
+ }
}
/**
@@ -136,12 +175,14 @@
private void makeInactive() {
if (mActivated) {
// Make sure that we clear the hotspot from the center.
- mCustomBackground.setHotspot(0, getWidth() / 2, getActualHeight() / 2);
- mCustomBackground.removeHotspot(0);
+ if (mBackgroundDimmed != null) {
+ mBackgroundDimmed.setHotspot(0, getWidth() / 2, getActualHeight() / 2);
+ mBackgroundDimmed.removeHotspot(0);
+ }
mActivated = false;
}
if (mOnActivatedListener != null) {
- mOnActivatedListener.onReset(this);
+ mOnActivatedListener.onActivationReset(this);
}
removeCallbacks(mTapTimeoutRunnable);
}
@@ -151,25 +192,18 @@
&& Math.abs(event.getY() - mDownY) < mTouchSlop;
}
- /**
- * Sets the notification as dimmed, meaning that it will appear in a more gray variant.
- */
- public void setDimmed(boolean dimmed) {
+ public void setDimmed(boolean dimmed, boolean fade) {
if (mDimmed != dimmed) {
mDimmed = dimmed;
- updateBackgroundResource();
+ if (fade) {
+ fadeBackgroundResource();
+ } else {
+ updateBackgroundResource();
+ }
}
}
/**
- * Sets the notification as locked. In the locked state, the first tap will produce a quantum
- * ripple to make the notification brighter and only the second tap will cause a click.
- */
- public void setLocked(boolean locked) {
- mLocked = locked;
- }
-
- /**
* Sets the resource id for the background of this notification.
*
* @param bgResId The background resource to use in normal state.
@@ -181,20 +215,111 @@
updateBackgroundResource();
}
+ private void fadeBackgroundResource() {
+ if (mDimmed) {
+ setBackgroundDimmed(mDimmedBgResId);
+ } else {
+ setBackgroundNormal(mBgResId);
+ }
+ int startAlpha = mDimmed ? 255 : 0;
+ int endAlpha = mDimmed ? 0 : 255;
+ int duration = BACKGROUND_ANIMATION_LENGTH_MS;
+ // Check whether there is already a background animation running.
+ if (mBackgroundAnimator != null) {
+ startAlpha = (Integer) mBackgroundAnimator.getAnimatedValue();
+ duration = (int) mBackgroundAnimator.getCurrentPlayTime();
+ mBackgroundAnimator.removeAllListeners();
+ mBackgroundAnimator.cancel();
+ if (duration <= 0) {
+ updateBackgroundResource();
+ return;
+ }
+ }
+ mBackgroundNormal.setAlpha(startAlpha);
+ mBackgroundAnimator =
+ ObjectAnimator.ofInt(mBackgroundNormal, "alpha", startAlpha, endAlpha);
+ mBackgroundAnimator.setInterpolator(mFastOutSlowInInterpolator);
+ mBackgroundAnimator.setDuration(duration);
+ mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mDimmed) {
+ setBackgroundNormal(null);
+ } else {
+ setBackgroundDimmed(null);
+ }
+ mBackgroundAnimator = null;
+ }
+ });
+ mBackgroundAnimator.start();
+ }
+
private void updateBackgroundResource() {
- setCustomBackgroundResource(mDimmed ? mDimmedBgResId : mBgResId);
+ if (mDimmed) {
+ setBackgroundDimmed(mDimmedBgResId);
+ mBackgroundDimmed.setAlpha(255);
+ setBackgroundNormal(null);
+ } else {
+ setBackgroundDimmed(null);
+ setBackgroundNormal(mBgResId);
+ mBackgroundNormal.setAlpha(255);
+ }
+ }
+
+ /**
+ * Sets a background drawable for the normal state. As we need to change our bounds
+ * independently of layout, we need the notion of a background independently of the regular View
+ * background..
+ */
+ private void setBackgroundNormal(Drawable backgroundNormal) {
+ if (mBackgroundNormal != null) {
+ mBackgroundNormal.setCallback(null);
+ unscheduleDrawable(mBackgroundNormal);
+ }
+ mBackgroundNormal = backgroundNormal;
+ if (mBackgroundNormal != null) {
+ mBackgroundNormal.setCallback(this);
+ }
+ invalidate();
+ }
+
+ private void setBackgroundDimmed(Drawable overlay) {
+ if (mBackgroundDimmed != null) {
+ mBackgroundDimmed.setCallback(null);
+ unscheduleDrawable(mBackgroundDimmed);
+ }
+ mBackgroundDimmed = overlay;
+ if (mBackgroundDimmed != null) {
+ mBackgroundDimmed.setCallback(this);
+ }
+ invalidate();
+ }
+
+ private void setBackgroundNormal(int drawableResId) {
+ setBackgroundNormal(getResources().getDrawable(drawableResId));
+ }
+
+ private void setBackgroundDimmed(int drawableResId) {
+ setBackgroundDimmed(getResources().getDrawable(drawableResId));
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- setPivotX(getWidth()/2);
+ setPivotX(getWidth() / 2);
}
@Override
- public void setActualHeight(int actualHeight) {
- super.setActualHeight(actualHeight);
- setPivotY(actualHeight/2);
+ public void setActualHeight(int actualHeight, boolean notifyListeners) {
+ super.setActualHeight(actualHeight, notifyListeners);
+ invalidate();
+ setPivotY(actualHeight / 2);
+ }
+
+ @Override
+ public void setClipTopAmount(int clipTopAmount) {
+ super.setClipTopAmount(clipTopAmount);
+ invalidate();
}
public void setOnActivatedListener(OnActivatedListener onActivatedListener) {
@@ -203,6 +328,6 @@
public interface OnActivatedListener {
void onActivated(View view);
- void onReset(View view);
+ void onActivationReset(View view);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 9149e2d..ecefc39 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -70,7 +70,7 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList;
-import com.android.internal.util.LegacyNotificationUtil;
+import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SearchPanelView;
@@ -143,7 +143,7 @@
// public mode, private notifications, etc
private boolean mLockscreenPublicMode = false;
private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
- private LegacyNotificationUtil mLegacyNotificationUtil = LegacyNotificationUtil.getInstance();
+ private NotificationColorUtil mNotificationColorUtil = NotificationColorUtil.getInstance();
private UserManager mUserManager;
@@ -167,7 +167,12 @@
protected int mZenMode;
- protected boolean mOnKeyguard;
+ /**
+ * The {@link StatusBarState} of the status bar.
+ */
+ protected int mState;
+ protected boolean mBouncerShowing;
+
protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
public boolean isDeviceProvisioned() {
@@ -297,7 +302,7 @@
ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();
mCommandQueue = new CommandQueue(this, iconList);
- int[] switches = new int[7];
+ int[] switches = new int[8];
ArrayList<IBinder> binders = new ArrayList<IBinder>();
try {
mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,
@@ -312,7 +317,7 @@
setSystemUiVisibility(switches[1], 0xffffffff);
topAppWindowChanged(switches[2] != 0);
// StatusBarManagerService has a back up of IME token and it's restored here.
- setImeWindowStatus(binders.get(0), switches[3], switches[4]);
+ setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[7] != 0);
setHardKeyboardStatus(switches[5] != 0, switches[6] != 0);
// Set up the initial icon state
@@ -768,8 +773,8 @@
PendingIntent contentIntent = sbn.getNotification().contentIntent;
if (contentIntent != null) {
- final View.OnClickListener listener = makeClicker(contentIntent,
- sbn.getPackageName(), sbn.getTag(), sbn.getId(), isHeadsUp, sbn.getUserId());
+ final View.OnClickListener listener = makeClicker(contentIntent, sbn.getKey(),
+ isHeadsUp);
row.setOnClickListener(listener);
} else {
row.setOnClickListener(null);
@@ -847,7 +852,7 @@
Drawable iconDrawable = StatusBarIconView.getIcon(mContext, ic);
icon.setImageDrawable(iconDrawable);
- if (mLegacyNotificationUtil.isGrayscale(iconDrawable)) {
+ if (mNotificationColorUtil.isGrayscale(iconDrawable)) {
icon.setBackgroundResource(
com.android.internal.R.drawable.notification_icon_legacy_bg_inset);
}
@@ -879,27 +884,20 @@
return true;
}
- public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag,
- int id, boolean forHun, int userId) {
- return new NotificationClicker(intent, pkg, tag, id, forHun, userId);
+ public NotificationClicker makeClicker(PendingIntent intent, String notificationKey,
+ boolean forHun) {
+ return new NotificationClicker(intent, notificationKey, forHun);
}
protected class NotificationClicker implements View.OnClickListener {
private PendingIntent mIntent;
- private String mPkg;
- private String mTag;
- private int mId;
+ private final String mNotificationKey;
private boolean mIsHeadsUp;
- private int mUserId;
- public NotificationClicker(PendingIntent intent, String pkg, String tag, int id,
- boolean forHun, int userId) {
+ public NotificationClicker(PendingIntent intent, String notificationKey, boolean forHun) {
mIntent = intent;
- mPkg = pkg;
- mTag = tag;
- mId = id;
+ mNotificationKey = notificationKey;
mIsHeadsUp = forHun;
- mUserId = userId;
}
public void onClick(View v) {
@@ -935,7 +933,7 @@
if (mIsHeadsUp) {
mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
}
- mBarService.onNotificationClick(mPkg, mTag, mId, mUserId);
+ mBarService.onNotificationClick(mNotificationKey);
} catch (RemoteException ex) {
// system process is dead if we're here.
}
@@ -1057,9 +1055,10 @@
mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
int n = mNotificationData.size();
int visibleNotifications = 0;
+ boolean onKeyguard = mState == StatusBarState.KEYGUARD;
for (int i = n-1; i >= 0; i--) {
NotificationData.Entry entry = mNotificationData.get(i);
- if (mOnKeyguard) {
+ if (onKeyguard) {
entry.row.setExpansionDisabled(true);
} else {
entry.row.setExpansionDisabled(false);
@@ -1068,10 +1067,8 @@
entry.row.setSystemExpanded(top);
}
}
- entry.row.setDimmed(mOnKeyguard);
- entry.row.setLocked(mOnKeyguard);
boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
- if (mOnKeyguard && (visibleNotifications >= maxKeyguardNotifications
+ if (onKeyguard && (visibleNotifications >= maxKeyguardNotifications
|| !showOnKeyguard)) {
entry.row.setVisibility(View.GONE);
if (showOnKeyguard) {
@@ -1087,49 +1084,13 @@
}
}
- if (mOnKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
+ if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
mKeyguardIconOverflowContainer.setVisibility(View.VISIBLE);
} else {
mKeyguardIconOverflowContainer.setVisibility(View.GONE);
}
}
- @Override
- public void onActivated(View view) {
- int n = mNotificationData.size();
- for (int i = 0; i < n; i++) {
- NotificationData.Entry entry = mNotificationData.get(i);
- if (entry.row.getVisibility() != View.GONE) {
- if (view == entry.row) {
- entry.row.getActivator().activate();
- } else {
- entry.row.getActivator().activateInverse();
- }
- }
- }
- if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
- if (view == mKeyguardIconOverflowContainer) {
- mKeyguardIconOverflowContainer.getActivator().activate();
- } else {
- mKeyguardIconOverflowContainer.getActivator().activateInverse();
- }
- }
- }
-
- @Override
- public void onReset(View view) {
- int n = mNotificationData.size();
- for (int i = 0; i < n; i++) {
- NotificationData.Entry entry = mNotificationData.get(i);
- if (entry.row.getVisibility() != View.GONE) {
- entry.row.getActivator().reset();
- }
- }
- if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
- mKeyguardIconOverflowContainer.getActivator().reset();
- }
- }
-
private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
return sbn.getNotification().priority >= Notification.PRIORITY_LOW;
}
@@ -1145,7 +1106,6 @@
protected abstract void updateNotificationIcons();
protected abstract void tick(IBinder key, StatusBarNotification n, boolean firstTime);
protected abstract void updateExpandedViewPos(int expandedPosition);
- protected abstract int getExpandedViewMaxHeight();
protected abstract boolean shouldDisableNavbarGestures();
protected boolean isTopNotification(ViewGroup parent, NotificationData.Entry entry) {
@@ -1283,7 +1243,7 @@
if (userChangedExpansion) {
boolean userExpanded = oldEntry.row.isUserExpanded();
newEntry.row.setUserExpanded(userExpanded);
- newEntry.row.applyExpansionToLayout();
+ newEntry.row.notifyHeightChanged();
}
}
@@ -1338,9 +1298,8 @@
// update the contentIntent
final PendingIntent contentIntent = notification.getNotification().contentIntent;
if (contentIntent != null) {
- final View.OnClickListener listener = makeClicker(contentIntent,
- notification.getPackageName(), notification.getTag(), notification.getId(),
- isHeadsUp, notification.getUserId());
+ final View.OnClickListener listener = makeClicker(contentIntent, notification.getKey(),
+ isHeadsUp);
entry.row.setOnClickListener(listener);
} else {
entry.row.setOnClickListener(null);
@@ -1398,6 +1357,17 @@
// hook for subclasses
}
+ public void setBouncerShowing(boolean bouncerShowing) {
+ mBouncerShowing = bouncerShowing;
+ }
+
+ /**
+ * @return Whether the security bouncer from Keyguard is showing.
+ */
+ public boolean isBouncerShowing() {
+ return mBouncerShowing;
+ }
+
public void destroy() {
if (mSearchPanelView != null) {
mWindowManager.removeViewImmediate(mSearchPanelView);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index bbbe8fa..5362af5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -65,6 +65,8 @@
public static final int FLAG_EXCLUDE_INPUT_METHODS_PANEL = 1 << 3;
public static final int FLAG_EXCLUDE_COMPAT_MODE_PANEL = 1 << 4;
+ private static final String SHOW_IME_SWITCHER_KEY = "showImeSwitcherKey";
+
private StatusBarIconList mList;
private Callbacks mCallbacks;
private Handler mHandler = new H();
@@ -91,7 +93,8 @@
public void animateExpandSettingsPanel();
public void setSystemUiVisibility(int vis, int mask);
public void topAppWindowChanged(boolean visible);
- public void setImeWindowStatus(IBinder token, int vis, int backDisposition);
+ public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher);
public void setHardKeyboardStatus(boolean available, boolean enabled);
public void toggleRecentApps();
public void preloadRecentApps();
@@ -190,11 +193,13 @@
}
}
- public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
+ public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) {
synchronized (mList) {
mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
- mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, vis, backDisposition, token)
- .sendToTarget();
+ Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, vis, backDisposition, token);
+ m.getData().putBoolean(SHOW_IME_SWITCHER_KEY, showImeSwitcher);
+ m.sendToTarget();
}
}
@@ -298,7 +303,8 @@
mCallbacks.topAppWindowChanged(msg.arg1 != 0);
break;
case MSG_SHOW_IME_BUTTON:
- mCallbacks.setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2);
+ mCallbacks.setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2,
+ msg.getData().getBoolean(SHOW_IME_SWITCHER_KEY, false));
break;
case MSG_SET_HARD_KEYBOARD_STATUS:
mCallbacks.setHardKeyboardStatus(msg.arg1 != 0, msg.arg2 != 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
new file mode 100644
index 0000000..5b2ea0b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -0,0 +1,206 @@
+/*
+ * 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.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+import com.android.systemui.ExpandHelper;
+import com.android.systemui.Gefingerpoken;
+import com.android.systemui.R;
+
+/**
+ * A utility class to enable the downward swipe on the lockscreen to go to the full shade and expand
+ * the notification where the drag started.
+ */
+public class DragDownHelper implements Gefingerpoken {
+
+ private static final float RUBBERBAND_FACTOR_EXPANDABLE = 0.5f;
+ private static final float RUBBERBAND_FACTOR_STATIC = 0.15f;
+
+ private static final int SPRING_BACK_ANIMATION_LENGTH_MS = 375;
+
+ private int mMinDragDistance;
+ private ExpandHelper.Callback mCallback;
+ private float mInitialTouchX;
+ private float mInitialTouchY;
+ private boolean mDraggingDown;
+ private float mTouchSlop;
+ private OnDragDownListener mOnDragDownListener;
+ private View mHost;
+ private final int[] mTemp2 = new int[2];
+ private boolean mDraggedFarEnough;
+ private ExpandableView mStartingChild;
+ private Interpolator mInterpolator;
+
+ public DragDownHelper(Context context, View host, ExpandHelper.Callback callback,
+ OnDragDownListener onDragDownListener) {
+ mMinDragDistance = context.getResources().getDimensionPixelSize(
+ R.dimen.keyguard_drag_down_min_distance);
+ mInterpolator =
+ AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
+ mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+ mCallback = callback;
+ mOnDragDownListener = onDragDownListener;
+ mHost = host;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent event) {
+ final float x = event.getX();
+ final float y = event.getY();
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mDraggedFarEnough = false;
+ mDraggingDown = false;
+ mStartingChild = null;
+ mInitialTouchY = y;
+ mInitialTouchX = x;
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ final float h = y - mInitialTouchY;
+ if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) {
+ mDraggingDown = true;
+ captureStartingChild(mInitialTouchX, mInitialTouchY);
+ mInitialTouchY = y;
+ mInitialTouchX = x;
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (!mDraggingDown) {
+ return false;
+ }
+ final float x = event.getX();
+ final float y = event.getY();
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_MOVE:
+ final float h = y - mInitialTouchY;
+ captureStartingChild(mInitialTouchX, mInitialTouchY);
+ if (mStartingChild != null) {
+ handleExpansion(h, mStartingChild);
+ }
+ if (h > mMinDragDistance) {
+ if (!mDraggedFarEnough) {
+ mDraggedFarEnough = true;
+ mOnDragDownListener.onThresholdReached();
+ }
+ } else {
+ if (mDraggedFarEnough) {
+ mDraggedFarEnough = false;
+ mOnDragDownListener.onDragDownReset();
+ }
+ }
+ return true;
+ case MotionEvent.ACTION_UP:
+ if (mDraggedFarEnough) {
+ if (mStartingChild != null) {
+ mCallback.setUserLockedChild(mStartingChild, false);
+ }
+ mOnDragDownListener.onDraggedDown(mStartingChild);
+ mDraggingDown = false;
+ } else {
+ stopDragging();
+ return false;
+ }
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ stopDragging();
+ return false;
+ }
+ return false;
+ }
+
+ private void captureStartingChild(float x, float y) {
+ if (mStartingChild == null) {
+ mStartingChild = findView(x, y);
+ if (mStartingChild != null) {
+ mCallback.setUserLockedChild(mStartingChild, true);
+ }
+ }
+ }
+
+ private void handleExpansion(float heightDelta, ExpandableView child) {
+ if (heightDelta < 0) {
+ heightDelta = 0;
+ }
+ boolean expandable = child.isContentExpandable();
+ float rubberbandFactor = expandable
+ ? RUBBERBAND_FACTOR_EXPANDABLE
+ : RUBBERBAND_FACTOR_STATIC;
+ float rubberband = heightDelta * rubberbandFactor;
+ if (expandable && (rubberband + child.getMinHeight()) > child.getMaxHeight()) {
+ float overshoot = (rubberband + child.getMinHeight()) - child.getMaxHeight();
+ overshoot *= (1 - RUBBERBAND_FACTOR_STATIC);
+ rubberband -= overshoot;
+ }
+ child.setActualHeight((int) (child.getMinHeight() + rubberband));
+ }
+
+ private void cancelExpansion(final ExpandableView child) {
+ if (child.getActualHeight() == child.getMinHeight()) {
+ return;
+ }
+ ObjectAnimator anim = ObjectAnimator.ofInt(child, "actualHeight",
+ child.getActualHeight(), child.getMinHeight());
+ anim.setInterpolator(mInterpolator);
+ anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mCallback.setUserLockedChild(child, false);
+ }
+ });
+ anim.start();
+ }
+
+ private void stopDragging() {
+ if (mStartingChild != null) {
+ cancelExpansion(mStartingChild);
+ }
+ mDraggingDown = false;
+ mOnDragDownListener.onDragDownReset();
+ }
+
+ private ExpandableView findView(float x, float y) {
+ mHost.getLocationOnScreen(mTemp2);
+ x += mTemp2[0];
+ y += mTemp2[1];
+ return mCallback.getChildAtRawPosition(x, y);
+ }
+
+ public interface OnDragDownListener {
+ void onDraggedDown(View startingChild);
+ void onDragDownReset();
+ void onThresholdReached();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 61aad6f..39f2bb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -52,7 +52,6 @@
private NotificationContentView mPublicLayout;
private NotificationContentView mPrivateLayout;
private int mMaxExpandHeight;
- private NotificationActivator mActivator;
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -63,8 +62,6 @@
super.onFinishInflate();
mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
-
- mActivator = new NotificationActivator(this);
}
@Override
@@ -137,7 +134,7 @@
*/
public void setSystemExpanded(boolean expand) {
mIsSystemExpanded = expand;
- applyExpansionToLayout();
+ notifyHeightChanged();
}
/**
@@ -145,7 +142,7 @@
*/
public void setExpansionDisabled(boolean expansionDisabled) {
mExpansionDisabled = expansionDisabled;
- applyExpansionToLayout();
+ notifyHeightChanged();
}
/**
@@ -160,13 +157,8 @@
}
}
- /**
- * If {@link #isExpanded()} then this is the greatest possible height this view can
- * get and otherwise it is {@link #mRowMinHeight}.
- *
- * @return the maximum allowed expansion height of this view.
- */
- public int getMaximumAllowedExpandHeight() {
+ @Override
+ public int getIntrinsicHeight() {
if (isUserLocked()) {
return getActualHeight();
}
@@ -213,34 +205,27 @@
mPrivateLayout.setVisibility(show ? View.GONE : View.VISIBLE);
}
- /**
- * Sets the notification as dimmed, meaning that it will appear in a more gray variant.
- */
- public void setDimmed(boolean dimmed) {
- super.setDimmed(dimmed);
- mActivator.setDimmed(dimmed);
- }
-
public int getMaxExpandHeight() {
return mMaxExpandHeight;
}
- public NotificationActivator getActivator() {
- return mActivator;
- }
-
/**
* @return the potential height this view could expand in addition.
*/
public int getExpandPotential() {
- return getMaximumAllowedExpandHeight() - getActualHeight();
+ return getIntrinsicHeight() - getActualHeight();
}
@Override
- public void setActualHeight(int height) {
- mPrivateLayout.setActualHeight(height);
+ public boolean isContentExpandable() {
+ return mPrivateLayout.isContentExpandable();
+ }
+
+ @Override
+ public void setActualHeight(int height, boolean notifyListeners) {
+ mPrivateLayout.setActualHeight(height, notifyListeners);
invalidate();
- super.setActualHeight(height);
+ super.setActualHeight(height, notifyListeners);
}
@Override
@@ -249,6 +234,11 @@
}
@Override
+ public int getMinHeight() {
+ return mPrivateLayout.getMinHeight();
+ }
+
+ @Override
public void setClipTopAmount(int clipTopAmount) {
super.setClipTopAmount(clipTopAmount);
mPrivateLayout.setClipTopAmount(clipTopAmount);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 43eb5b5..a42c194 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -33,8 +33,8 @@
}
@Override
- public void setActualHeight(int actualHeight) {
- super.setActualHeight(actualHeight);
+ public void setActualHeight(int actualHeight, boolean notifyListeners) {
+ super.setActualHeight(actualHeight, notifyListeners);
updateOutline();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 35913fa..281bd2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -17,12 +17,8 @@
package com.android.systemui.statusbar;
import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Outline;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
@@ -34,7 +30,6 @@
private OnHeightChangedListener mOnHeightChangedListener;
protected int mActualHeight;
protected int mClipTopAmount;
- protected Drawable mCustomBackground;
private boolean mActualHeightInitialized;
public ExpandableView(Context context, AttributeSet attrs) {
@@ -42,27 +37,6 @@
}
@Override
- protected void onDraw(Canvas canvas) {
- if (mCustomBackground != null) {
- mCustomBackground.setBounds(0, mClipTopAmount, getWidth(), mActualHeight);
- mCustomBackground.draw(canvas);
- }
- }
-
- @Override
- protected boolean verifyDrawable(Drawable who) {
- return super.verifyDrawable(who) || who == mCustomBackground;
- }
-
- @Override
- protected void drawableStateChanged() {
- final Drawable d = mCustomBackground;
- if (d != null && d.isStateful()) {
- d.setState(getDrawableState());
- }
- }
-
- @Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (!mActualHeightInitialized && mActualHeight == 0) {
@@ -71,22 +45,41 @@
mActualHeightInitialized = true;
}
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (filterMotionEvent(ev)) {
+ return super.dispatchTouchEvent(ev);
+ }
+ return false;
+ }
+
+ private boolean filterMotionEvent(MotionEvent event) {
+ return event.getActionMasked() != MotionEvent.ACTION_DOWN
+ || event.getY() > mClipTopAmount && event.getY() < mActualHeight;
+ }
+
/**
* Sets the actual height of this notification. This is different than the laid out
* {@link View#getHeight()}, as we want to avoid layouting during scrolling and expanding.
+ *
+ * @param actualHeight The height of this notification.
+ * @param notifyListeners Whether the listener should be informed about the change.
*/
- public void setActualHeight(int actualHeight) {
+ public void setActualHeight(int actualHeight, boolean notifyListeners) {
mActualHeight = actualHeight;
- invalidate();
- if (mOnHeightChangedListener != null) {
- mOnHeightChangedListener.onHeightChanged(this);
+ if (notifyListeners) {
+ notifyHeightChanged();
}
}
+ public void setActualHeight(int actualHeight) {
+ setActualHeight(actualHeight, true);
+ }
+
/**
* See {@link #setActualHeight}.
*
- * @return The actual height of this notification.
+ * @return The current actual height of this notification.
*/
public int getActualHeight() {
return mActualHeight;
@@ -95,7 +88,32 @@
/**
* @return The maximum height of this notification.
*/
- public abstract int getMaxHeight();
+ public int getMaxHeight() {
+ return getHeight();
+ }
+
+ /**
+ * @return The minimum height of this notification.
+ */
+ public int getMinHeight() {
+ return getHeight();
+ }
+
+ /**
+ * Sets the notification as dimmed. The default implementation does nothing.
+ *
+ * @param dimmed Whether the notification should be dimmed.
+ * @param fade Whether an animation should be played to change the state.
+ */
+ public void setDimmed(boolean dimmed, boolean fade) {
+ }
+
+ /**
+ * @return The desired notification height.
+ */
+ public int getIntrinsicHeight() {
+ return mActualHeight;
+ }
/**
* Sets the amount this view should be clipped from the top. This is used when an expanded
@@ -105,7 +123,10 @@
*/
public void setClipTopAmount(int clipTopAmount) {
mClipTopAmount = clipTopAmount;
- invalidate();
+ }
+
+ public int getClipTopAmount() {
+ return mClipTopAmount;
}
public void setOnHeightChangedListener(OnHeightChangedListener listener) {
@@ -113,22 +134,16 @@
}
/**
- * Sets a custom background drawable. As we need to change our bounds independently of layout,
- * we need the notition of a custom background.
+ * @return Whether we can expand this views content.
*/
- public void setCustomBackground(Drawable customBackground) {
- if (mCustomBackground != null) {
- mCustomBackground.setCallback(null);
- unscheduleDrawable(mCustomBackground);
- }
- mCustomBackground = customBackground;
- mCustomBackground.setCallback(this);
- setWillNotDraw(customBackground == null);
- invalidate();
+ public boolean isContentExpandable() {
+ return false;
}
- public void setCustomBackgroundResource(int drawableResId) {
- setCustomBackground(getResources().getDrawable(drawableResId));
+ public void notifyHeightChanged() {
+ if (mOnHeightChangedListener != null) {
+ mOnHeightChangedListener.onHeightChanged(this);
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java
deleted file mode 100644
index 620e457..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java
+++ /dev/null
@@ -1,87 +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;
-
-import android.content.Context;
-import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import com.android.systemui.R;
-
-/**
- * A helper class used by both {@link com.android.systemui.statusbar.ExpandableNotificationRow} and
- * {@link com.android.systemui.statusbar.NotificationOverflowIconsView} to make a notification look
- * active after tapping it once on the Keyguard.
- */
-public class NotificationActivator {
-
- private static final int ANIMATION_LENGTH_MS = 220;
- private static final float INVERSE_ALPHA = 0.9f;
- private static final float DIMMED_SCALE = 0.95f;
-
- private final View mTargetView;
-
- private final Interpolator mFastOutSlowInInterpolator;
- private final Interpolator mLinearOutSlowInInterpolator;
- private final int mTranslationZ;
-
- public NotificationActivator(View targetView) {
- mTargetView = targetView;
- Context ctx = targetView.getContext();
- mFastOutSlowInInterpolator =
- AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_slow_in);
- mLinearOutSlowInInterpolator =
- AnimationUtils.loadInterpolator(ctx, android.R.interpolator.linear_out_slow_in);
- mTranslationZ =
- ctx.getResources().getDimensionPixelSize(R.dimen.z_distance_between_notifications);
- mTargetView.animate().setDuration(ANIMATION_LENGTH_MS);
- }
-
- public void activateInverse() {
- mTargetView.animate().withLayer().alpha(INVERSE_ALPHA);
- }
-
- public void activate() {
- mTargetView.animate()
- .setInterpolator(mLinearOutSlowInInterpolator)
- .scaleX(1)
- .scaleY(1)
- .translationZBy(mTranslationZ);
- }
-
- public void reset() {
- mTargetView.animate()
- .setInterpolator(mFastOutSlowInInterpolator)
- .scaleX(DIMMED_SCALE)
- .scaleY(DIMMED_SCALE)
- .translationZBy(-mTranslationZ);
- if (mTargetView.getAlpha() != 1.0f) {
- mTargetView.animate().withLayer().alpha(1);
- }
- }
-
- public void setDimmed(boolean dimmed) {
- if (dimmed) {
- mTargetView.setScaleX(DIMMED_SCALE);
- mTargetView.setScaleY(DIMMED_SCALE);
- } else {
- mTargetView.setScaleX(1);
- mTargetView.setScaleY(1);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index fd0cb08..9df2701 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -70,8 +70,8 @@
}
@Override
- public void setActualHeight(int actualHeight) {
- super.setActualHeight(actualHeight);
+ public void setActualHeight(int actualHeight, boolean notifyListeners) {
+ super.setActualHeight(actualHeight, notifyListeners);
selectLayout();
updateClipping();
}
@@ -84,15 +84,16 @@
}
@Override
+ public int getMinHeight() {
+ return mSmallHeight;
+ }
+
+ @Override
public void setClipTopAmount(int clipTopAmount) {
super.setClipTopAmount(clipTopAmount);
updateClipping();
}
- public int getClipTopAmount() {
- return mClipTopAmount;
- }
-
private void updateClipping() {
mClipBounds.set(0, mClipTopAmount, getWidth(), mActualHeight);
setClipBounds(mClipBounds);
@@ -125,4 +126,9 @@
public void notifyContentUpdated() {
selectLayout();
}
+
+ @Override
+ public boolean isContentExpandable() {
+ return mExpandedChild != null;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
index 8ebd50d..864c597 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
@@ -28,14 +28,13 @@
public class NotificationOverflowContainer extends ActivatableNotificationView {
private NotificationOverflowIconsView mIconsView;
- private NotificationActivator mActivator;
public NotificationOverflowContainer(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
- public void setActualHeight(int currentHeight) {
+ public void setActualHeight(int currentHeight, boolean notifyListeners) {
// noop
}
@@ -45,11 +44,6 @@
}
@Override
- public int getMaxHeight() {
- return getHeight();
- }
-
- @Override
public void setClipTopAmount(int clipTopAmount) {
// noop
}
@@ -59,18 +53,9 @@
super.onFinishInflate();
mIconsView = (NotificationOverflowIconsView) findViewById(R.id.overflow_icons_view);
mIconsView.setMoreText((TextView) findViewById(R.id.more_text));
-
- mActivator = new NotificationActivator(this);
- mActivator.setDimmed(true);
- setLocked(true);
- setDimmed(true);
}
public NotificationOverflowIconsView getIconsView() {
return mIconsView;
}
-
- public NotificationActivator getActivator() {
- return mActivator;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
new file mode 100644
index 0000000..9d75228
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.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.systemui.statusbar;
+
+/**
+ * Class to encapsulate all possible status bar states regarding Keyguard.
+ */
+public class StatusBarState {
+
+ /**
+ * The status bar is in the "normal" shade mode.
+ */
+ public static final int SHADE = 0;
+
+ /**
+ * Status bar is currently the Keyguard.
+ */
+ public static final int KEYGUARD = 1;
+
+ /**
+ * Status bar is in the special mode, where it is fully interactive but still locked. So
+ * dismissing the shade will still show the bouncer.
+ */
+ public static final int SHADE_LOCKED = 2;
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java
new file mode 100644
index 0000000..5bc7e5a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.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.phone;
+
+import android.content.Intent;
+
+/**
+ * An interface to start activities. This is used to as a callback from the views to
+ * {@link PhoneStatusBar} to allow custom handling for starting the activity, i.e. dismissing the
+ * Keyguard.
+ */
+public interface ActivityStarter {
+ public void startActivity(Intent intent);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 3cc22ef..58b3f2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -42,14 +43,18 @@
* Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
* text.
*/
-public class KeyguardBottomAreaView extends FrameLayout {
+public class KeyguardBottomAreaView extends FrameLayout
+ implements SwipeAffordanceView.AffordanceListener {
final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView";
- private View mCameraButton;
- private float mCameraDragDistance;
+ private static final Intent PHONE_INTENT = new Intent(Intent.ACTION_DIAL);
+
+ private SwipeAffordanceView mCameraButton;
+ private SwipeAffordanceView mPhoneButton;
+
private PowerManager mPowerManager;
- private int mScaledTouchSlop;
+ private ActivityStarter mActivityStarter;
public KeyguardBottomAreaView(Context context) {
super(context);
@@ -71,20 +76,37 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mCameraButton = findViewById(R.id.camera_button);
+ mCameraButton = (SwipeAffordanceView) findViewById(R.id.camera_button);
+ mPhoneButton = (SwipeAffordanceView) findViewById(R.id.phone_button);
+ mCameraButton.setAffordanceListener(this);
+ mPhoneButton.setAffordanceListener(this);
watchForDevicePolicyChanges();
watchForAccessibilityChanges();
updateCameraVisibility();
- mCameraDragDistance = getResources().getDimension(R.dimen.camera_drag_distance);
- mScaledTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ updatePhoneVisibility();
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
}
+ public void setActivityStarter(ActivityStarter activityStarter) {
+ mActivityStarter = activityStarter;
+ }
+
private void updateCameraVisibility() {
boolean visible = !isCameraDisabledByDpm();
mCameraButton.setVisibility(visible ? View.VISIBLE : View.GONE);
}
+ private void updatePhoneVisibility() {
+ boolean visible = isPhoneVisible();
+ mPhoneButton.setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+
+ private boolean isPhoneVisible() {
+ PackageManager pm = mContext.getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
+ && pm.resolveActivity(PHONE_INTENT, 0) != null;
+ }
+
private boolean isCameraDisabledByDpm() {
final DevicePolicyManager dpm =
(DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
@@ -136,15 +158,8 @@
}
private void enableAccessibility(boolean touchExplorationEnabled) {
-
- // Add a touch handler or accessibility click listener for camera button.
- if (touchExplorationEnabled) {
- mCameraButton.setOnTouchListener(null);
- mCameraButton.setOnClickListener(mCameraClickListener);
- } else {
- mCameraButton.setOnTouchListener(mCameraTouchListener);
- mCameraButton.setOnClickListener(null);
- }
+ mCameraButton.enableAccessibility(touchExplorationEnabled);
+ mPhoneButton.enableAccessibility(touchExplorationEnabled);
}
private void launchCamera() {
@@ -153,80 +168,21 @@
UserHandle.CURRENT);
}
- private final OnClickListener mCameraClickListener = new OnClickListener() {
- @Override
- public void onClick(View v) {
+ private void launchPhone() {
+ mActivityStarter.startActivity(PHONE_INTENT);
+ }
+
+ @Override
+ public void onUserActivity(long when) {
+ mPowerManager.userActivity(when, false);
+ }
+
+ @Override
+ public void onActionPerformed(SwipeAffordanceView view) {
+ if (view == mCameraButton) {
launchCamera();
+ } else if (view == mPhoneButton) {
+ launchPhone();
}
- };
-
- private final OnTouchListener mCameraTouchListener = new OnTouchListener() {
- private float mStartX;
- private boolean mTouchSlopReached;
- private boolean mSkipCancelAnimation;
-
- @Override
- public boolean onTouch(final View cameraButtonView, MotionEvent event) {
- float realX = event.getRawX();
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- mStartX = realX;
- mTouchSlopReached = false;
- mSkipCancelAnimation = false;
- break;
- case MotionEvent.ACTION_MOVE:
- if (realX > mStartX) {
- realX = mStartX;
- }
- if (realX < mStartX - mCameraDragDistance) {
- cameraButtonView.setPressed(true);
- mPowerManager.userActivity(event.getEventTime(), false);
- } else {
- cameraButtonView.setPressed(false);
- }
- if (realX < mStartX - mScaledTouchSlop) {
- mTouchSlopReached = true;
- }
- cameraButtonView.setTranslationX(Math.max(realX - mStartX,
- -mCameraDragDistance));
- break;
- case MotionEvent.ACTION_UP:
- if (realX < mStartX - mCameraDragDistance) {
- launchCamera();
- cameraButtonView.animate().x(-cameraButtonView.getWidth())
- .setInterpolator(new AccelerateInterpolator(2f)).withEndAction(
- new Runnable() {
- @Override
- public void run() {
- cameraButtonView.setTranslationX(0);
- }
- });
- mSkipCancelAnimation = true;
- }
- if (realX < mStartX - mScaledTouchSlop) {
- mTouchSlopReached = true;
- }
- if (!mTouchSlopReached) {
- mSkipCancelAnimation = true;
- cameraButtonView.animate().translationX(-mCameraDragDistance / 2).
- setInterpolator(new DecelerateInterpolator()).withEndAction(
- new Runnable() {
- @Override
- public void run() {
- cameraButtonView.animate().translationX(0).
- setInterpolator(new AccelerateInterpolator());
- }
- });
- }
- case MotionEvent.ACTION_CANCEL:
- cameraButtonView.setPressed(false);
- if (!mSkipCancelAnimation) {
- cameraButtonView.animate().translationX(0)
- .setInterpolator(new AccelerateInterpolator(2f));
- }
- break;
- }
- return true;
- }
- };
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 3fae3f0..089757a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -39,6 +39,7 @@
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
+import android.view.inputmethod.InputMethodManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -142,6 +143,14 @@
}
};
+ private final OnClickListener mImeSwitcherClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ ((InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE))
+ .showInputMethodPicker();
+ }
+ };
+
private class H extends Handler {
public void handleMessage(Message m) {
switch (m.what) {
@@ -233,6 +242,10 @@
return mCurrentView.findViewById(R.id.home);
}
+ public View getImeSwitchButton() {
+ return mCurrentView.findViewById(R.id.ime_switcher);
+ }
+
// for when home is disabled, but search isn't
public View getSearchLight() {
return mCurrentView.findViewById(R.id.search_light);
@@ -283,6 +296,12 @@
((ImageView)getRecentsButton()).setImageDrawable(mVertical ? mRecentLandIcon : mRecentIcon);
+ final boolean showImeButton = ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
+ getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE);
+ // Update menu button in case the IME state has changed.
+ setMenuVisibility(mShowMenu, true);
+
+
setDisabledFlags(mDisabledFlags, true);
}
@@ -363,7 +382,10 @@
mShowMenu = show;
- getMenuButton().setVisibility(mShowMenu ? View.VISIBLE : View.INVISIBLE);
+ // Only show Menu if IME switcher not shown.
+ final boolean shouldShow = mShowMenu &&
+ ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0);
+ getMenuButton().setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
}
@Override
@@ -379,6 +401,8 @@
mCurrentView = mRotatedViews[Surface.ROTATION_0];
+ getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
+
watchForAccessibilityChanges();
}
@@ -424,6 +448,8 @@
mCurrentView = mRotatedViews[rot];
mCurrentView.setVisibility(View.VISIBLE);
+ getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
+
mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
// force the low profile & disabled states into compliance
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 712eec8..f63ba9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -16,28 +16,58 @@
package com.android.systemui.statusbar.phone;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
+import android.view.VelocityTracker;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
public class NotificationPanelView extends PanelView implements
- ExpandableView.OnHeightChangedListener {
+ ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
+ View.OnClickListener {
public static final boolean DEBUG_GESTURES = true;
+ private static final int EXPANSION_ANIMATION_LENGTH = 375;
PhoneStatusBar mStatusBar;
- private View mHeader;
+ private StatusBarHeaderView mHeader;
+ private QuickSettingsContainerView mQsContainer;
private View mKeyguardStatusView;
+ private ObservableScrollView mScrollView;
+ private View mStackScrollerContainer;
private NotificationStackScrollLayout mNotificationStackScroller;
- private boolean mTrackingSettings;
private int mNotificationTopPadding;
+ private boolean mAnimateNextTopPaddingChange;
+
+ private Interpolator mExpansionInterpolator;
+
+ private int mTrackingPointer;
+ private VelocityTracker mVelocityTracker;
+ private boolean mTracking;
+ private boolean mQsExpanded;
+ private float mInitialHeightOnTouch;
+ private float mInitialTouchX;
+ private float mInitialTouchY;
+ private float mQsExpansionHeight;
+ private int mQsMinExpansionHeight;
+ private int mQsMaxExpansionHeight;
+ private int mMinStackHeight;
+ private float mNotificationTranslation;
+ private int mStackScrollerIntrinsicPadding;
+ private boolean mQsExpansionEnabled = true;
+ private ValueAnimator mQsExpansionAnimator;
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -61,14 +91,21 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
-
- mHeader = findViewById(R.id.header);
+ mHeader = (StatusBarHeaderView) findViewById(R.id.header);
+ mHeader.getBackgroundView().setOnClickListener(this);
mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
+ mStackScrollerContainer = findViewById(R.id.notification_container_parent);
+ mQsContainer = (QuickSettingsContainerView) findViewById(R.id.quick_settings_container);
+ mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
+ mScrollView.setListener(this);
mNotificationStackScroller = (NotificationStackScrollLayout)
findViewById(R.id.notification_stack_scroller);
mNotificationStackScroller.setOnHeightChangedListener(this);
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);
}
@Override
@@ -76,9 +113,50 @@
super.onLayout(changed, left, top, right, bottom);
int keyguardBottomMargin =
((MarginLayoutParams) mKeyguardStatusView.getLayoutParams()).bottomMargin;
- mNotificationStackScroller.setTopPadding(mStatusBar.isOnKeyguard()
- ? mKeyguardStatusView.getBottom() + keyguardBottomMargin
- : mHeader.getBottom() + mNotificationTopPadding);
+ if (!mQsExpanded) {
+ mStackScrollerIntrinsicPadding = mStatusBar.getBarState() == StatusBarState.KEYGUARD
+ ? mKeyguardStatusView.getBottom() + keyguardBottomMargin
+ : mHeader.getBottom() + mNotificationTopPadding;
+ mNotificationStackScroller.setTopPadding(mStackScrollerIntrinsicPadding,
+ mAnimateNextTopPaddingChange);
+ mAnimateNextTopPaddingChange = false;
+ }
+
+ // Calculate quick setting heights.
+ mQsMinExpansionHeight = mHeader.getCollapsedHeight();
+ mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getHeight();
+ if (mQsExpansionHeight == 0) {
+ mQsExpansionHeight = mQsMinExpansionHeight;
+ }
+ }
+
+ public void animateNextTopPaddingChange() {
+ mAnimateNextTopPaddingChange = true;
+ requestLayout();
+ }
+
+ /**
+ * @return Whether Quick Settings are currently expanded.
+ */
+ public boolean isQsExpanded() {
+ return mQsExpanded;
+ }
+
+ public void setQsExpansionEnabled(boolean qsExpansionEnabled) {
+ mQsExpansionEnabled = qsExpansionEnabled;
+ mHeader.setExpansionEnabled(qsExpansionEnabled);
+ }
+
+ public void closeQs() {
+ cancelAnimation();
+ setQsExpansion(mQsMinExpansionHeight);
+ }
+
+ public void openQs() {
+ cancelAnimation();
+ if (mQsExpansionEnabled) {
+ setQsExpansion(mQsMaxExpansionHeight);
+ }
}
@Override
@@ -105,38 +183,245 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- // intercept for quick settings
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- final View target = mStatusBar.isOnKeyguard() ? mKeyguardStatusView : mHeader;
- final boolean inTarget = PhoneStatusBar.inBounds(target, event, true);
- if (inTarget && !isInSettings()) {
- mTrackingSettings = true;
- return true;
- }
- if (!inTarget && isInSettings()) {
- mTrackingSettings = true;
- return true;
- }
+ int pointerIndex = event.findPointerIndex(mTrackingPointer);
+ if (pointerIndex < 0) {
+ pointerIndex = 0;
+ mTrackingPointer = event.getPointerId(pointerIndex);
}
- return super.onInterceptTouchEvent(event);
+ final float x = event.getX(pointerIndex);
+ final float y = event.getY(pointerIndex);
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mInitialTouchY = y;
+ mInitialTouchX = x;
+ initVelocityTracker();
+ trackMovement(event);
+ if (shouldIntercept(mInitialTouchX, mInitialTouchY, 0)) {
+ getParent().requestDisallowInterceptTouchEvent(true);
+ }
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ final int upPointer = event.getPointerId(event.getActionIndex());
+ if (mTrackingPointer == upPointer) {
+ // gesture is ongoing, find a new pointer to track
+ final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+ mTrackingPointer = event.getPointerId(newIndex);
+ mInitialTouchX = event.getX(newIndex);
+ mInitialTouchY = event.getY(newIndex);
+ }
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ final float h = y - mInitialTouchY;
+ trackMovement(event);
+ if (Math.abs(h) > mTouchSlop && Math.abs(h) > Math.abs(x - mInitialTouchX)
+ && shouldIntercept(mInitialTouchX, mInitialTouchY, h)) {
+ onQsExpansionStarted();
+ mInitialHeightOnTouch = mQsExpansionHeight;
+ mInitialTouchY = y;
+ mInitialTouchX = x;
+ mTracking = true;
+ return true;
+ }
+ break;
+ }
+ return !mQsExpanded && super.onInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO: Handle doublefinger swipe to notifications again. Look at history for a reference
// implementation.
- if (mTrackingSettings) {
- mStatusBar.onSettingsEvent(event);
- if (event.getAction() == MotionEvent.ACTION_UP
- || event.getAction() == MotionEvent.ACTION_CANCEL) {
- mTrackingSettings = false;
+ if (mTracking) {
+ int pointerIndex = event.findPointerIndex(mTrackingPointer);
+ if (pointerIndex < 0) {
+ pointerIndex = 0;
+ mTrackingPointer = event.getPointerId(pointerIndex);
+ }
+ final float y = event.getY(pointerIndex);
+ final float x = event.getX(pointerIndex);
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mTracking = true;
+ mInitialTouchY = y;
+ mInitialTouchX = x;
+ onQsExpansionStarted();
+ mInitialHeightOnTouch = mQsExpansionHeight;
+ initVelocityTracker();
+ trackMovement(event);
+ break;
+
+ case MotionEvent.ACTION_POINTER_UP:
+ final int upPointer = event.getPointerId(event.getActionIndex());
+ if (mTrackingPointer == upPointer) {
+ // gesture is ongoing, find a new pointer to track
+ final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+ final float newY = event.getY(newIndex);
+ final float newX = event.getX(newIndex);
+ mTrackingPointer = event.getPointerId(newIndex);
+ mInitialHeightOnTouch = mQsExpansionHeight;
+ mInitialTouchY = newY;
+ mInitialTouchX = newX;
+ }
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ final float h = y - mInitialTouchY;
+ setQsExpansion(h + mInitialHeightOnTouch);
+ trackMovement(event);
+ break;
+
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mTracking = false;
+ mTrackingPointer = -1;
+ trackMovement(event);
+
+ float vel = getCurrentVelocity();
+
+ // TODO: Better logic whether we should expand or not.
+ flingSettings(vel, vel > 0);
+
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ break;
}
return true;
}
- if (isInSettings()) {
- return true;
+
+ // Consume touch events when QS are expanded.
+ return mQsExpanded || super.onTouchEvent(event);
+ }
+
+ private void onQsExpansionStarted() {
+ cancelAnimation();
+
+ // Reset scroll position and apply that position to the expanded height.
+ float height = mQsExpansionHeight - mScrollView.getScrollY();
+ mScrollView.scrollTo(0, 0);
+ setQsExpansion(height);
+ }
+
+ private void expandQs() {
+ mHeader.setExpanded(true);
+ mNotificationStackScroller.setEnabled(false);
+ mScrollView.setVisibility(View.VISIBLE);
+ mQsExpanded = true;
+ }
+
+ private void collapseQs() {
+ mHeader.setExpanded(false);
+ mNotificationStackScroller.setEnabled(true);
+ mScrollView.setVisibility(View.INVISIBLE);
+ mQsExpanded = false;
+ }
+
+ private void setQsExpansion(float height) {
+ height = Math.min(Math.max(height, mQsMinExpansionHeight), mQsMaxExpansionHeight);
+ if (height > mQsMinExpansionHeight && !mQsExpanded) {
+ expandQs();
+ } else if (height <= mQsMinExpansionHeight && mQsExpanded) {
+ collapseQs();
}
- return super.onTouchEvent(event);
+ mQsExpansionHeight = height;
+ mHeader.setExpansion(height);
+ setQsTranslation(height);
+ setQsStackScrollerPadding(height);
+ }
+
+ private void setQsTranslation(float height) {
+ mQsContainer.setY(height - mQsContainer.getHeight());
+ }
+
+ private void setQsStackScrollerPadding(float height) {
+ float start = height - mScrollView.getScrollY() + mNotificationTopPadding;
+ float stackHeight = mNotificationStackScroller.getHeight() - start;
+ if (stackHeight <= mMinStackHeight) {
+ float overflow = mMinStackHeight - stackHeight;
+ stackHeight = mMinStackHeight;
+ start = mNotificationStackScroller.getHeight() - stackHeight;
+ mNotificationStackScroller.setTranslationY(overflow);
+ mNotificationTranslation = overflow + mScrollView.getScrollY();
+ } else {
+ mNotificationStackScroller.setTranslationY(0);
+ mNotificationTranslation = mScrollView.getScrollY();
+ }
+ mNotificationStackScroller.setTopPadding(clampQsStackScrollerPadding((int) start), false);
+ }
+
+ private int clampQsStackScrollerPadding(int desiredPadding) {
+ return Math.max(desiredPadding, mStackScrollerIntrinsicPadding);
+ }
+
+ private void trackMovement(MotionEvent event) {
+ if (mVelocityTracker != null) mVelocityTracker.addMovement(event);
+ }
+
+ private void initVelocityTracker() {
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ }
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+
+ private float getCurrentVelocity() {
+ if (mVelocityTracker == null) {
+ return 0;
+ }
+ mVelocityTracker.computeCurrentVelocity(1000);
+ return mVelocityTracker.getYVelocity();
+ }
+
+ private void cancelAnimation() {
+ if (mQsExpansionAnimator != null) {
+ mQsExpansionAnimator.cancel();
+ }
+ }
+ 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);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ setQsExpansion((Float) animation.getAnimatedValue());
+ }
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mQsExpansionAnimator = null;
+ }
+ });
+ animator.start();
+ mQsExpansionAnimator = animator;
+ }
+
+ /**
+ * @return Whether we should intercept a gesture to open Quick Settings.
+ */
+ private boolean shouldIntercept(float x, float y, float yDiff) {
+ 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();
+ if (mQsExpanded) {
+ return onHeader || (mScrollView.isScrolledToBottom() && yDiff < 0);
+ } else {
+ return onHeader;
+ }
}
@Override
@@ -151,14 +436,16 @@
protected int getMaxPanelHeight() {
if (!isInSettings()) {
int maxPanelHeight = super.getMaxPanelHeight();
- int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin();
+ int notificationMarginBottom = mStackScrollerContainer.getPaddingBottom();
+ int emptyBottomMargin = notificationMarginBottom
+ + mNotificationStackScroller.getEmptyBottomMargin();
return maxPanelHeight - emptyBottomMargin;
}
return super.getMaxPanelHeight();
}
private boolean isInSettings() {
- return mStatusBar != null && mStatusBar.isFlippedToSettings();
+ return mQsExpanded;
}
@Override
@@ -187,4 +474,24 @@
public void onHeightChanged(ExpandableView view) {
requestPanelHeightUpdate();
}
+
+ @Override
+ public void onScrollChanged() {
+ if (mQsExpanded) {
+ mNotificationStackScroller.setTranslationY(
+ mNotificationTranslation - mScrollView.getScrollY());
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == mHeader.getBackgroundView()) {
+ onQsExpansionStarted();
+ if (mQsExpanded) {
+ flingSettings(0 /* vel */, false /* expand */);
+ } else if (mQsExpansionEnabled) {
+ flingSettings(0 /* vel */, true /* expand */);
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
new file mode 100644
index 0000000..f41e78d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -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
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+/**
+ * The container with notification stack scroller and quick settings inside.
+ */
+public class NotificationsQuickSettingsContainer extends FrameLayout {
+
+ public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected boolean fitSystemWindows(Rect insets) {
+ setPadding(0, 0, 0, insets.bottom);
+ insets.bottom = 0;
+ return true;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
new file mode 100644
index 0000000..46484f3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.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.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ScrollView;
+
+/**
+ * A scroll view which can be observed for scroll change events.
+ */
+public class ObservableScrollView extends ScrollView {
+
+ private Listener mListener;
+
+ public ObservableScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+
+ public boolean isScrolledToBottom() {
+ return getScrollY() == getMaxScrollY();
+ }
+
+ private int getMaxScrollY() {
+ int scrollRange = 0;
+ if (getChildCount() > 0) {
+ View child = getChildAt(0);
+ scrollRange = Math.max(0,
+ child.getHeight() - (getHeight() - mPaddingBottom - mPaddingTop));
+ }
+ return scrollRange;
+ }
+
+ @Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ if (mListener != null) {
+ mListener.onScrollChanged();
+ }
+ }
+
+ public interface Listener {
+ void onScrollChanged();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 328a1728..8c70517 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -75,7 +75,7 @@
private boolean mClosing;
private boolean mTracking;
private int mTrackingPointer;
- private int mTouchSlop;
+ protected int mTouchSlop;
private TimeAnimator mTimeAnimator;
private ObjectAnimator mPeekAnimator;
@@ -220,9 +220,9 @@
private float mVel, mAccel;
protected int mMaxPanelHeight = 0;
private String mViewName;
- protected float mInitialTouchY;
- protected float mInitialTouchX;
- protected float mFinalTouchY;
+ private float mInitialTouchY;
+ private float mInitialTouchX;
+ private float mFinalTouchY;
protected void onExpandingFinished() {
}
@@ -526,11 +526,14 @@
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
+ if (mTimeAnimator.isRunning()) {
+ mTimeAnimator.cancel(); // end any outstanding animations
+ return true;
+ }
mInitialTouchY = y;
mInitialTouchX = x;
initVelocityTracker();
trackMovement(event);
- mTimeAnimator.cancel(); // end any outstanding animations
break;
case MotionEvent.ACTION_POINTER_UP:
final int upPointer = event.getPointerId(event.getActionIndex());
@@ -569,7 +572,7 @@
}
protected boolean isScrolledToBottom() {
- return false;
+ return true;
}
protected float getContentHeight() {
@@ -623,9 +626,7 @@
mExpandedHeight = mMaxPanelHeight;
}
}
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(
- getDesiredMeasureHeight(), MeasureSpec.AT_MOST);
- setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
+ setMeasuredDimension(getMeasuredWidth(), getDesiredMeasureHeight());
}
protected int getDesiredMeasureHeight() {
@@ -705,11 +706,6 @@
* @return the default implementation simply returns the maximum height.
*/
protected int getMaxPanelHeight() {
- if (mMaxPanelHeight <= 0) {
- if (DEBUG) logf("Forcing measure() since mMaxPanelHeight=" + mMaxPanelHeight);
- measure(MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY));
- }
return mMaxPanelHeight;
}
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 545352c..92eee4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -18,6 +18,7 @@
import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
+import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
@@ -72,7 +73,6 @@
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewPropertyAnimator;
@@ -95,6 +95,8 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.DragDownHelper;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.InterceptedNotifications;
import com.android.systemui.statusbar.NotificationData;
@@ -102,6 +104,7 @@
import com.android.systemui.statusbar.NotificationOverflowContainer;
import com.android.systemui.statusbar.SignalClusterView;
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.DateView;
@@ -119,7 +122,8 @@
import java.util.Collection;
import java.util.Collections;
-public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
+public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
+ DragDownHelper.OnDragDownListener, ActivityStarter {
static final String TAG = "PhoneStatusBar";
public static final boolean DEBUG = BaseStatusBar.DEBUG;
public static final boolean SPEW = false;
@@ -187,8 +191,6 @@
int mIconHPadding = -1;
Display mDisplay;
Point mCurrentDisplaySize = new Point();
- private float mHeadsUpVerticalOffset;
- private int[] mStackScrollerPosition = new int[2];
StatusBarWindowView mStatusBarWindow;
PhoneStatusBarView mStatusBarView;
@@ -217,21 +219,21 @@
NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
View mExpandedContents;
int mNotificationPanelGravity;
- int mNotificationPanelMarginBottomPx, mNotificationPanelMarginPx;
+ int mNotificationPanelMarginBottomPx;
float mNotificationPanelMinHeightFrac;
boolean mNotificationPanelIsFullScreenWidth;
TextView mNotificationPanelDebugText;
// settings
QuickSettings mQS;
- boolean mHasQuickSettings;
View mFlipSettingsView;
QuickSettingsContainerView mSettingsContainer;
// top bar
View mNotificationPanelHeader;
View mKeyguardStatusView;
- View mKeyguardBottomArea;
+ KeyguardBottomAreaView mKeyguardBottomArea;
+ boolean mLeaveOpenOnKeyguardHide;
KeyguardIndicationTextView mKeyguardIndicationTextView;
// TODO: Fetch phrase from search/hotword provider.
@@ -239,14 +241,14 @@
int mKeyguardMaxNotificationCount;
View mDateTimeView;
View mClearButton;
- FlipperButton mHeaderFlipper, mKeyguardFlipper;
+ ImageView mHeaderFlipper;
// carrier/wifi label
private TextView mCarrierLabel;
private boolean mCarrierLabelVisible = false;
private int mCarrierLabelHeight;
private TextView mEmergencyCallLabel;
- private int mNotificationHeaderHeight;
+ private int mStatusBarHeaderHeight;
private View mKeyguardCarrierLabel;
private boolean mShowCarrierInPanel = false;
@@ -320,11 +322,12 @@
if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " +
"selfChange=%s userSetup=%s mUserSetup=%s",
selfChange, userSetup, mUserSetup));
- mHeaderFlipper.userSetup(userSetup);
- mKeyguardFlipper.userSetup(userSetup);
if (userSetup != mUserSetup) {
mUserSetup = userSetup;
+ if (mNotificationPanel != null) {
+ mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned() && userSetup);
+ }
if (!mUserSetup && mStatusBarView != null)
animateCollapseQuickSettings();
}
@@ -379,7 +382,7 @@
private boolean mSettingsStarted;
private boolean mSettingsCancelled;
private boolean mSettingsClosing;
- private int mNotificationPadding;
+ private boolean mVisible;
private final OnChildLocationsChangedListener mOnChildLocationsChangedListener =
new OnChildLocationsChangedListener() {
@@ -469,6 +472,13 @@
}
};
+ private final View.OnClickListener mOverflowClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ goToLockedShade(null);
+ }
+ };
+
@Override
public void setZenMode(int mode) {
super.setZenMode(mode);
@@ -618,13 +628,16 @@
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);
mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
- mKeyguardBottomArea = mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
+ 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);
@@ -634,16 +647,13 @@
mClearButton.setEnabled(false);
mDateView = (DateView)mStatusBarWindow.findViewById(R.id.date);
- mHasQuickSettings = res.getBoolean(R.bool.config_hasQuickSettings);
-
mDateTimeView = mNotificationPanelHeader.findViewById(R.id.datetime);
if (mDateTimeView != null) {
mDateTimeView.setOnClickListener(mClockClickListener);
mDateTimeView.setEnabled(true);
}
- mHeaderFlipper = new FlipperButton(mStatusBarWindow.findViewById(R.id.header_flipper));
- mKeyguardFlipper =new FlipperButton(mStatusBarWindow.findViewById(R.id.keyguard_flipper));
+ mHeaderFlipper = (ImageView) mStatusBarWindow.findViewById(R.id.header_flipper);
if (!mNotificationPanelIsFullScreenWidth) {
mNotificationPanel.setSystemUiVisibility(
@@ -718,28 +728,23 @@
// updateCarrierLabelVisibility(false);
}
- // Quick Settings (where available, some restrictions apply)
- mNotificationPadding = mContext.getResources()
- .getDimensionPixelSize(R.dimen.notification_side_padding);
- if (mHasQuickSettings) {
- // 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);
- }
- mQS.setService(this);
- mQS.setBar(mStatusBarView);
- mQS.setup(mNetworkController, mBluetoothController, mBatteryController,
- mLocationController, mRotationLockController);
- } else {
- mQS = null; // fly away, be free
+ // 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);
}
+ mQS.setService(this);
+ mQS.setBar(mStatusBarView);
+ mQS.setup(mNetworkController, mBluetoothController, mBatteryController,
+ mLocationController, mRotationLockController);
+ } else {
+ mQS = null; // fly away, be free
}
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -760,99 +765,6 @@
return mStatusBarView;
}
- public boolean onSettingsEvent(MotionEvent event) {
- userActivity();
- if (mSettingsClosing
- && mFlipSettingsViewAnim != null && mFlipSettingsViewAnim.isRunning()) {
- return true;
- }
- if (mSettingsTracker != null) {
- mSettingsTracker.addMovement(event);
- }
- final int slop = ViewConfiguration.get(mContext).getScaledTouchSlop();
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- mSettingsTracker = VelocityTracker.obtain();
- mSettingsDownY = event.getY();
- mSettingsCancelled = false;
- mSettingsStarted = false;
- mSettingsClosing = mFlipSettingsView.getVisibility() == View.VISIBLE;
- if (mSettingsClosing) {
- mStackScroller.setVisibility(View.VISIBLE);
- } else {
- mFlipSettingsView.setTranslationY(-mNotificationPanel.getMeasuredHeight());
- }
- dispatchSettingsEvent(event);
- } else if (mSettingsTracker != null && (event.getAction() == MotionEvent.ACTION_UP
- || event.getAction() == MotionEvent.ACTION_CANCEL)) {
- final float dy = event.getY() - mSettingsDownY;
- final FlipperButton flipper = mOnKeyguard ? mKeyguardFlipper : mHeaderFlipper;
- final boolean inButton = flipper.inHolderBounds(event);
- final boolean qsTap = mSettingsClosing && Math.abs(dy) < slop;
- if (!qsTap && !inButton) {
- mSettingsTracker.computeCurrentVelocity(1000);
- final float vy = mSettingsTracker.getYVelocity();
- final boolean animate = true;
- if (dy <= slop || vy <= 0) {
- flipToNotifications(animate);
- } else {
- flipToSettings(animate);
- }
- }
- mSettingsTracker.recycle();
- mSettingsTracker = null;
- dispatchSettingsEvent(event);
- } else if (mSettingsTracker != null && event.getAction() == MotionEvent.ACTION_MOVE) {
- final float dy = event.getY() - mSettingsDownY;
- if (mSettingsClosing) {
- positionSettings(dy);
- final boolean qsTap = Math.abs(dy) < slop;
- if (!mSettingsCancelled && !qsTap) {
- MotionEvent cancelEvent = MotionEvent.obtainNoHistory(event);
- cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
- dispatchSettingsEvent(cancelEvent);
- mSettingsCancelled = true;
- }
- } else {
- if (!mSettingsStarted && dy > slop) {
- mSettingsStarted = true;
- mFlipSettingsView.setVisibility(View.VISIBLE);
- mStackScroller.setVisibility(View.VISIBLE);
- }
- if (mSettingsStarted) {
- positionSettings(dy);
- }
- dispatchSettingsEvent(event);
- }
- }
- return true;
- }
-
- private void dispatchSettingsEvent(MotionEvent event) {
- final View target = mSettingsClosing ? mFlipSettingsView : mNotificationPanelHeader;
- final int[] targetLoc = new int[2];
- target.getLocationInWindow(targetLoc);
- final int[] panelLoc = new int[2];
- mNotificationPanel.getLocationInWindow(panelLoc);
- final int dx = targetLoc[0] - panelLoc[0];
- final int dy = targetLoc[1] - panelLoc[1];
- event.offsetLocation(-dx, -dy);
- target.dispatchTouchEvent(event);
- }
-
- private void positionSettings(float dy) {
- if (mSettingsClosing) {
- final int ph = mNotificationPanel.getMeasuredHeight();
- dy = Math.min(Math.max(-ph, dy), 0);
- mFlipSettingsView.setTranslationY(dy);
- mStackScroller.setTranslationY(ph + dy);
- } else {
- final int h = mFlipSettingsView.getBottom();
- dy = Math.min(Math.max(0, dy), h);
- mFlipSettingsView.setTranslationY(-h + dy);
- mStackScroller.setTranslationY(dy);
- }
- }
-
private void startKeyguard() {
KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
@@ -1193,7 +1105,7 @@
}
if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0
- && !mNotificationPanel.isTracking() && !mOnKeyguard) {
+ && !mNotificationPanel.isTracking() && mState != StatusBarState.KEYGUARD) {
animateCollapsePanels();
}
}
@@ -1213,8 +1125,11 @@
((ImageView)mClearButton).setImageResource(R.drawable.ic_notify_clear);
}
- mHeaderFlipper.refreshLayout();
- mKeyguardFlipper.refreshLayout();
+ if (mHeaderFlipper != null) {
+ // Force asset reloading
+ mHeaderFlipper.setImageDrawable(null);
+ mHeaderFlipper.setImageResource(R.drawable.ic_notify_quicksettings);
+ }
refreshAllStatusBarIcons();
}
@@ -1269,8 +1184,7 @@
}
}
- mHeaderFlipper.provisionCheck(provisioned);
- mKeyguardFlipper.provisionCheck(provisioned);
+ mNotificationPanel.setQsExpansionEnabled(provisioned && mUserSetup);
}
@Override
@@ -1345,9 +1259,9 @@
final boolean makeVisible =
!(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
&& mStackScroller.getHeight() < (mNotificationPanel.getHeight()
- - mCarrierLabelHeight - mNotificationHeaderHeight)
+ - mCarrierLabelHeight - mStatusBarHeaderHeight)
&& mStackScroller.getVisibility() == View.VISIBLE
- && !mOnKeyguard;
+ && mState != StatusBarState.KEYGUARD;
if (force || mCarrierLabelVisible != makeVisible) {
mCarrierLabelVisible = makeVisible;
@@ -1563,6 +1477,11 @@
return new PhoneStatusBar.H();
}
+ @Override
+ public void startActivity(Intent intent) {
+ startActivityDismissingKeyguard(intent, false);
+ }
+
/**
* All changes to the status bar and notifications funnel through here and are batched.
*/
@@ -1653,6 +1572,9 @@
}
public void animateCollapsePanels(int flags) {
+ if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
+ return;
+ }
if (SPEW) {
Log.d(TAG, "animateCollapse():"
+ " mExpandedVisible=" + mExpandedVisible
@@ -1750,47 +1672,8 @@
}
public void flipToNotifications(boolean animate) {
- cancelAnim(mFlipSettingsViewAnim);
- cancelAnim(mScrollViewAnim);
- cancelAnim(mClearButtonAnim);
- mHeaderFlipper.cancel();
- mKeyguardFlipper.cancel();
- mStackScroller.setVisibility(View.VISIBLE);
- final int h = mNotificationPanel.getMeasuredHeight();
- if (animate) {
- final float settingsY =
- mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : 0;
- final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : h;
- mScrollViewAnim = start(
- interpolator(mDecelerateInterpolator,
- ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, 0)
- .setDuration(FLIP_DURATION)
- ));
- mFlipSettingsViewAnim = start(
- setVisibilityWhenDone(
- interpolator(mDecelerateInterpolator,
- ObjectAnimator.ofFloat(
- mFlipSettingsView, View.TRANSLATION_Y, settingsY, -h))
- .setDuration(FLIP_DURATION),
- mFlipSettingsView, View.INVISIBLE));
- } else {
- mStackScroller.setTranslationY(0);
- mFlipSettingsView.setTranslationY(-h);
- mFlipSettingsView.setVisibility(View.INVISIBLE);
- }
- mHeaderFlipper.flipToNotifications(animate);
- mKeyguardFlipper.flipToNotifications(animate);
- mClearButton.setVisibility(View.VISIBLE);
- mClearButton.setAlpha(0f);
- setAreThereNotifications(); // this will show/hide the button as necessary
- mNotificationPanel.postDelayed(new Runnable() {
- public void run() {
- updateCarrierLabelVisibility(false);
- }
- }, animate ? FLIP_DURATION - 150 : 0);
- if (mOnFlipRunnable != null) {
- mOnFlipRunnable.run();
- }
+ // TODO: Animation
+ mNotificationPanel.closeQs();
}
@Override
@@ -1804,78 +1687,18 @@
if (!mUserSetup) return;
mNotificationPanel.expand();
- if (mFlipSettingsView.getVisibility() != View.VISIBLE
- || mFlipSettingsView.getTranslationY() < 0) {
- flipToSettings(true /*animate*/);
- }
+ mNotificationPanel.openQs();
if (false) postStartTracing();
}
public boolean isFlippedToSettings() {
- if (mFlipSettingsView != null) {
- return mFlipSettingsView.getVisibility() == View.VISIBLE;
+ if (mNotificationPanel != null) {
+ return mNotificationPanel.isQsExpanded();
}
return false;
}
- public void flipToSettings(boolean animate) {
- // Settings are not available in setup
- if (!mUserSetup) return;
-
- cancelAnim(mFlipSettingsViewAnim);
- cancelAnim(mScrollViewAnim);
- mHeaderFlipper.cancel();
- mKeyguardFlipper.cancel();
- cancelAnim(mClearButtonAnim);
-
- mFlipSettingsView.setVisibility(View.VISIBLE);
- final int h = mNotificationPanel.getMeasuredHeight();
- if (animate) {
- final float settingsY
- = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : -h;
- final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : 0;
- mFlipSettingsViewAnim = start(
- startDelay(0,
- interpolator(mDecelerateInterpolator,
- ObjectAnimator.ofFloat(mFlipSettingsView, View.TRANSLATION_Y,
- settingsY, 0f)
- .setDuration(FLIP_DURATION)
- )));
- mScrollViewAnim = start(
- setVisibilityWhenDone(
- interpolator(mDecelerateInterpolator,
- ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, h)
- )
- .setDuration(FLIP_DURATION),
- mStackScroller, View.INVISIBLE));
- } else {
- mFlipSettingsView.setTranslationY(0);
- mStackScroller.setTranslationY(h);
- mStackScroller.setVisibility(View.INVISIBLE);
- }
- mHeaderFlipper.flipToSettings(animate);
- mKeyguardFlipper.flipToSettings(animate);
- if (animate) {
- mClearButtonAnim = start(
- setVisibilityWhenDone(
- ObjectAnimator.ofFloat(mClearButton, View.ALPHA, 0f)
- .setDuration(FLIP_DURATION),
- mClearButton, View.INVISIBLE));
- } else {
- mClearButton.setAlpha(0);
- mClearButton.setVisibility(View.INVISIBLE);
- }
- mNotificationPanel.postDelayed(new Runnable() {
- public void run() {
- updateCarrierLabelVisibility(false);
- }
- }, animate ? FLIP_DURATION - 150 : 0);
- if (mOnFlipRunnable != null) {
- mOnFlipRunnable.run();
- }
- }
-
public void animateCollapseQuickSettings() {
mStatusBarView.collapseAllPanels(true);
}
@@ -1902,12 +1725,10 @@
mStackScroller.setVisibility(View.VISIBLE);
mNotificationPanel.setVisibility(View.GONE);
- mFlipSettingsView.setVisibility(View.GONE);
setAreThereNotifications(); // show the clear button
- mHeaderFlipper.reset();
- mKeyguardFlipper.reset();
+ mNotificationPanel.closeQs();
mExpandedVisible = false;
if (mNavigationBarView != null)
@@ -2098,7 +1919,7 @@
if (mDemoMode) return;
int sbMode = mStatusBarMode;
if (panelsEnabled() && (mInteractingWindows & StatusBarManager.WINDOW_STATUS_BAR) != 0
- && !mOnKeyguard) {
+ && mState != StatusBarState.KEYGUARD) {
// if panels are expandable, force the status bar opaque on any interaction
sbMode = MODE_OPAQUE;
}
@@ -2210,13 +2031,22 @@
}
@Override
- public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
- boolean altBack = (backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS)
- || ((vis & InputMethodService.IME_VISIBLE) != 0);
+ public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) {
+ boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
+ int flags = mNavigationIconHints;
+ if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) {
+ flags |= NAVIGATION_HINT_BACK_ALT;
+ } else {
+ flags &= ~NAVIGATION_HINT_BACK_ALT;
+ }
+ if (showImeSwitcher) {
+ flags |= NAVIGATION_HINT_IME_SHOWN;
+ } else {
+ flags &= ~NAVIGATION_HINT_IME_SHOWN;
+ }
- setNavigationIconHints(
- altBack ? (mNavigationIconHints | NAVIGATION_HINT_BACK_ALT)
- : (mNavigationIconHints & ~NAVIGATION_HINT_BACK_ALT));
+ setNavigationIconHints(flags);
if (mQS != null) mQS.setImeWindowStatus(vis > 0);
}
@@ -2429,20 +2259,11 @@
}
}
- void updateExpandedInvisiblePosition() {
- mTrackingPosition = -mDisplayMetrics.heightPixels;
- }
-
static final float saturate(float a) {
return a < 0f ? 0f : (a > 1f ? 1f : a);
}
@Override
- protected int getExpandedViewMaxHeight() {
- return mDisplayMetrics.heightPixels - mNotificationPanelMarginBottomPx;
- }
-
- @Override
public void updateExpandedViewPos(int thingy) {
if (SPEW) Log.v(TAG, "updateExpandedViewPos");
@@ -2452,15 +2273,8 @@
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mNotificationPanel.getLayoutParams();
lp.gravity = mNotificationPanelGravity;
- lp.setMarginStart(mNotificationPanelMarginPx);
mNotificationPanel.setLayoutParams(lp);
- if (ENABLE_HEADS_UP && mHeadsUpNotificationView != null) {
- mHeadsUpNotificationView.setMargin(mNotificationPanelMarginPx);
- mStackScroller.getLocationOnScreen(mStackScrollerPosition);
- mHeadsUpVerticalOffset = mStackScrollerPosition[1] - mNaturalBarHeight;
- }
-
updateCarrierLabelVisibility(false);
}
@@ -2508,17 +2322,6 @@
animateCollapsePanels();
}
- private View.OnClickListener mSettingsButtonListener = new View.OnClickListener() {
- public void onClick(View v) {
- if (mHasQuickSettings) {
- animateExpandSettingsPanel();
- } else {
- startActivityDismissingKeyguard(
- new Intent(android.provider.Settings.ACTION_SETTINGS), true);
- }
- }
- };
-
private View.OnClickListener mClockClickListener = new View.OnClickListener() {
public void onClick(View v) {
startActivityDismissingKeyguard(
@@ -2551,12 +2354,14 @@
notifyNavigationBarScreenOn(false);
notifyHeadsUpScreenOn(false);
finishBarAnimations();
+ stopNotificationLogging();
}
else if (Intent.ACTION_SCREEN_ON.equals(action)) {
mScreenOn = true;
// work around problem where mDisplay.getRotation() is not stable while screen is off (bug 7086018)
repositionNavigationBar();
notifyNavigationBarScreenOn(true);
+ startNotificationLoggingIfScreenOnAndVisible();
}
else if (ACTION_DEMO.equals(action)) {
Bundle bundle = intent.getExtras();
@@ -2617,17 +2422,6 @@
}
}
- public void animateHeadsUp(boolean animateInto, float frac) {
- if (!ENABLE_HEADS_UP || mHeadsUpNotificationView == null) return;
- frac = frac / 0.4f;
- frac = frac < 1.0f ? frac : 1.0f;
- float alpha = 1.0f - frac;
- float offset = mHeadsUpVerticalOffset * frac;
- offset = animateInto ? offset : 0f;
- mHeadsUpNotificationView.setAlpha(alpha);
- mHeadsUpNotificationView.setY(offset);
- }
-
public void onHeadsUpDismissed() {
if (mInterruptingNotificationEntry == null) return;
mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
@@ -2700,17 +2494,13 @@
mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity);
- mNotificationPanelMarginBottomPx
- = (int) res.getDimension(R.dimen.notification_panel_margin_bottom);
- mNotificationPanelMarginPx
- = (int) res.getDimension(R.dimen.notification_panel_margin_left);
mNotificationPanelGravity = res.getInteger(R.integer.notification_panel_layout_gravity);
if (mNotificationPanelGravity <= 0) {
mNotificationPanelGravity = Gravity.START | Gravity.TOP;
}
mCarrierLabelHeight = res.getDimensionPixelSize(R.dimen.carrier_label_height);
- mNotificationHeaderHeight = res.getDimensionPixelSize(R.dimen.notification_panel_header_height);
+ mStatusBarHeaderHeight = res.getDimensionPixelSize(R.dimen.status_bar_header_height);
mNotificationPanelMinHeightFrac = res.getFraction(R.dimen.notification_panel_min_height_frac, 1, 1);
if (mNotificationPanelMinHeightFrac < 0f || mNotificationPanelMinHeightFrac > 1f) {
@@ -2730,22 +2520,40 @@
@Override
protected void visibilityChanged(boolean visible) {
+ mVisible = visible;
if (visible) {
- mStackScroller.setChildLocationsChangedListener(mNotificationLocationsChangedListener);
+ startNotificationLoggingIfScreenOnAndVisible();
} else {
- // Report all notifications as invisible and turn down the
- // reporter.
- if (!mCurrentlyVisibleNotifications.isEmpty()) {
- logNotificationVisibilityChanges(
- Collections.<String>emptyList(), mCurrentlyVisibleNotifications);
- mCurrentlyVisibleNotifications.clear();
- }
- mHandler.removeCallbacks(mVisibilityReporter);
- mStackScroller.setChildLocationsChangedListener(null);
+ stopNotificationLogging();
}
super.visibilityChanged(visible);
}
+ private void stopNotificationLogging() {
+ // Report all notifications as invisible and turn down the
+ // reporter.
+ if (!mCurrentlyVisibleNotifications.isEmpty()) {
+ logNotificationVisibilityChanges(
+ Collections.<String>emptyList(), mCurrentlyVisibleNotifications);
+ mCurrentlyVisibleNotifications.clear();
+ }
+ mHandler.removeCallbacks(mVisibilityReporter);
+ mStackScroller.setChildLocationsChangedListener(null);
+ }
+
+ private void startNotificationLoggingIfScreenOnAndVisible() {
+ if (mVisible && mScreenOn) {
+ mStackScroller.setChildLocationsChangedListener(mNotificationLocationsChangedListener);
+ // Some transitions like mScreenOn=false -> mScreenOn=true don't
+ // cause the scroller to emit child location events. Hence generate
+ // one ourselves to guarantee that we're reporting visible
+ // notifications.
+ // (Note that in cases where the scroller does emit events, this
+ // additional event doesn't break anything.)
+ mNotificationLocationsChangedListener.onChildLocationsChanged(mStackScroller);
+ }
+ }
+
private void logNotificationVisibilityChanges(
Collection<String> newlyVisible, Collection<String> noLongerVisible) {
if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) {
@@ -2930,31 +2738,38 @@
}
}
- public boolean isOnKeyguard() {
- return mOnKeyguard;
+ /**
+ * @return The {@link StatusBarState} the status bar is in.
+ */
+ public int getBarState() {
+ return mState;
}
public void showKeyguard() {
- mOnKeyguard = true;
+ setBarState(StatusBarState.KEYGUARD);
updateKeyguardState();
instantExpandNotificationsPanel();
+ mLeaveOpenOnKeyguardHide = false;
}
public void hideKeyguard() {
- mOnKeyguard = false;
+ setBarState(StatusBarState.SHADE);
+ if (mLeaveOpenOnKeyguardHide) {
+ mLeaveOpenOnKeyguardHide = false;
+ mNotificationPanel.animateNextTopPaddingChange();
+ } else {
+ instantCollapseNotificationPanel();
+ }
updateKeyguardState();
- instantCollapseNotificationPanel();
}
private void updatePublicMode() {
- setLockscreenPublicMode(mOnKeyguard && mStatusBarKeyguardViewManager.isSecure());
+ setLockscreenPublicMode(mState == StatusBarState.KEYGUARD
+ && mStatusBarKeyguardViewManager.isSecure());
}
private void updateKeyguardState() {
- if (mOnKeyguard) {
- if (isFlippedToSettings()) {
- flipToNotifications(false /*animate*/);
- }
+ if (mState == StatusBarState.KEYGUARD) {
mKeyguardStatusView.setVisibility(View.VISIBLE);
mKeyguardBottomArea.setVisibility(View.VISIBLE);
mKeyguardIndicationTextView.setVisibility(View.VISIBLE);
@@ -2962,7 +2777,7 @@
mKeyguardCarrierLabel.setVisibility(View.VISIBLE);
mNotificationPanelHeader.setVisibility(View.GONE);
- mKeyguardFlipper.setVisibility(View.VISIBLE);
+ mNotificationPanel.closeQs();
mSettingsContainer.setKeyguardShowing(true);
} else {
mKeyguardStatusView.setVisibility(View.GONE);
@@ -2971,10 +2786,10 @@
mKeyguardCarrierLabel.setVisibility(View.GONE);
mNotificationPanelHeader.setVisibility(View.VISIBLE);
- mKeyguardFlipper.setVisibility(View.GONE);
mSettingsContainer.setKeyguardShowing(false);
}
+ updateStackScrollerState();
updatePublicMode();
updateRowStates();
checkBarModes();
@@ -2982,18 +2797,22 @@
updateCarrierLabelVisibility(false);
}
+ public void updateStackScrollerState() {
+ mStackScroller.setDimmed(mState == StatusBarState.KEYGUARD, false /* animate */);
+ }
+
public void userActivity() {
- if (mOnKeyguard) {
+ if (mState == StatusBarState.KEYGUARD) {
mKeyguardViewMediatorCallback.userActivity();
}
}
public boolean onMenuPressed() {
- return mOnKeyguard && mStatusBarKeyguardViewManager.onMenuPressed();
+ return mState == StatusBarState.KEYGUARD && mStatusBarKeyguardViewManager.onMenuPressed();
}
public boolean onBackPressed() {
- if (mOnKeyguard) {
+ if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
return mStatusBarKeyguardViewManager.onBackPressed();
} else {
animateCollapsePanels();
@@ -3002,7 +2821,7 @@
}
private void showBouncer() {
- if (mOnKeyguard) {
+ if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
mStatusBarKeyguardViewManager.dismiss();
}
}
@@ -3035,23 +2854,33 @@
public void onActivated(View view) {
userActivity();
mKeyguardIndicationTextView.switchIndication(R.string.notification_tap_again);
- super.onActivated(view);
+ mStackScroller.setActivatedChild(view);
+ }
+
+ /**
+ * @param state The {@link StatusBarState} to set.
+ */
+ public void setBarState(int state) {
+ mState = state;
+ mStatusBarWindowManager.setStatusBarState(state);
}
@Override
- public void onReset(View view) {
- super.onReset(view);
- mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+ public void onActivationReset(View view) {
+ if (view == mStackScroller.getActivatedChild()) {
+ mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+ mStackScroller.setActivatedChild(null);
+ }
}
public void onTrackingStarted() {
- if (mOnKeyguard) {
+ if (mState == StatusBarState.KEYGUARD) {
mKeyguardIndicationTextView.switchIndication(R.string.keyguard_unlock);
}
}
public void onTrackingStopped() {
- if (mOnKeyguard) {
+ if (mState == StatusBarState.KEYGUARD) {
mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
}
}
@@ -3065,135 +2894,53 @@
return mNavigationBarView;
}
+ // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
+
+ @Override
+ public void onDraggedDown(View startingChild) {
+ goToLockedShade(startingChild);
+ }
+
+ @Override
+ public void onDragDownReset() {
+ mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
+ }
+
+ public void onThresholdReached() {
+ mStackScroller.setDimmed(false /* dimmed */, true /* animate */);
+ }
+
+ /**
+ * 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>
+ *
+ * @param expandView The view to expand after going to the shade.
+ */
+ public void goToLockedShade(View expandView) {
+ if (expandView instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) expandView;
+ row.setUserExpanded(true);
+ }
+ if (isLockscreenPublicMode() && !userAllowsPrivateNotificationsInPublic(mCurrentUserId)) {
+ mLeaveOpenOnKeyguardHide = true;
+ showBouncer();
+ } else if (mStatusBarKeyguardViewManager.isSecure()) {
+ mNotificationPanel.animateNextTopPaddingChange();
+ setBarState(StatusBarState.SHADE_LOCKED);
+ updateKeyguardState();
+ } else {
+ mLeaveOpenOnKeyguardHide = true;
+ mStatusBarKeyguardViewManager.dismiss();
+ }
+ }
+
/**
* @return a ViewGroup that spans the entire panel which contains the quick settings
*/
public ViewGroup getQuickSettingsOverlayParent() {
- if (mHasQuickSettings) {
- return mNotificationPanel;
- } else {
- return null;
- }
- }
-
- public static boolean inBounds(View view, MotionEvent event, boolean orAbove) {
- final int[] location = new int[2];
- view.getLocationInWindow(location);
- final int rx = (int) event.getRawX();
- final int ry = (int) event.getRawY();
- return rx >= location[0] && rx <= location[0] + view.getMeasuredWidth()
- && (orAbove || ry >= location[1]) && ry <= location[1] + view.getMeasuredHeight();
- }
-
- private final class FlipperButton {
- private final View mHolder;
-
- private ImageView mSettingsButton, mNotificationButton;
- private Animator mSettingsButtonAnim, mNotificationButtonAnim;
-
- public FlipperButton(View holder) {
- mHolder = holder;
- mSettingsButton = (ImageView) holder.findViewById(R.id.settings_button);
- if (mSettingsButton != null) {
- mSettingsButton.setOnClickListener(mSettingsButtonListener);
- if (mHasQuickSettings) {
- // the settings panel is hiding behind this button
- mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
- mSettingsButton.setVisibility(View.VISIBLE);
- } else {
- // no settings panel, go straight to settings
- mSettingsButton.setVisibility(View.VISIBLE);
- mSettingsButton.setImageResource(R.drawable.ic_notify_settings);
- }
- }
- mNotificationButton = (ImageView) holder.findViewById(R.id.notification_button);
- if (mNotificationButton != null) {
- mNotificationButton.setOnClickListener(mNotificationButtonListener);
- }
- }
-
- public boolean inHolderBounds(MotionEvent event) {
- return inBounds(mHolder, event, false);
- }
-
- public void provisionCheck(boolean provisioned) {
- if (mSettingsButton != null) {
- mSettingsButton.setEnabled(provisioned);
- }
- }
-
- public void userSetup(boolean userSetup) {
- if (mSettingsButton != null) {
- mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE);
- }
- }
-
- public void reset() {
- cancel();
- mSettingsButton.setVisibility(View.VISIBLE);
- mNotificationButton.setVisibility(View.GONE);
- }
-
- public void refreshLayout() {
- if (mSettingsButton != null) {
- // Force asset reloading
- mSettingsButton.setImageDrawable(null);
- mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
- }
-
- if (mNotificationButton != null) {
- // Force asset reloading
- mNotificationButton.setImageDrawable(null);
- mNotificationButton.setImageResource(R.drawable.ic_notifications);
- }
- }
-
- public void flipToSettings(boolean animate) {
- mNotificationButton.setVisibility(View.VISIBLE);
- if (animate) {
- mSettingsButtonAnim = start(
- setVisibilityWhenDone(
- ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
- .setDuration(FLIP_DURATION_OUT),
- mStackScroller, View.INVISIBLE));
- mNotificationButtonAnim = start(
- startDelay(FLIP_DURATION_OUT,
- ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
- .setDuration(FLIP_DURATION_IN)));
- } else {
- mSettingsButton.setAlpha(0f);
- mSettingsButton.setVisibility(View.INVISIBLE);
- mNotificationButton.setAlpha(1f);
- }
- }
-
- public void flipToNotifications(boolean animate) {
- mSettingsButton.setVisibility(View.VISIBLE);
- if (animate) {
- mNotificationButtonAnim = start(
- setVisibilityWhenDone(
- ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f)
- .setDuration(FLIP_DURATION_OUT),
- mNotificationButton, View.INVISIBLE));
-
- mSettingsButtonAnim = start(
- startDelay(FLIP_DURATION_OUT,
- ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f)
- .setDuration(FLIP_DURATION_IN)));
- } else {
- mNotificationButton.setVisibility(View.INVISIBLE);
- mNotificationButton.setAlpha(0f);
- mSettingsButton.setAlpha(1f);
- }
- }
-
- public void cancel() {
- cancelAnim(mSettingsButtonAnim);
- cancelAnim(mNotificationButtonAnim);
- }
-
- public void setVisibility(int vis) {
- mHolder.setVisibility(vis);
- }
+ return mNotificationPanel;
}
}
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 79c63f7..e6de057 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -19,7 +19,6 @@
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Log;
@@ -29,6 +28,7 @@
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBarState;
public class PhoneStatusBarView extends PanelBar {
private static final String TAG = "PhoneStatusBarView";
@@ -187,7 +187,10 @@
if (panel == mFadingPanel && mScrimColor != 0 && ActivityManager.isHighEndGfx()
&& mBar.mStatusBarWindow != null) {
if (mShouldFade) {
- int scrimColor = mBar.isOnKeyguard() ? mScrimColorKeyguard : mScrimColor;
+ int scrimColor = (mBar.getBarState() == StatusBarState.KEYGUARD
+ || mBar.getBarState() == StatusBarState.SHADE_LOCKED)
+ ? mScrimColorKeyguard
+ : mScrimColor;
frac = mPanelExpandedFractionSum; // don't judge me
// let's start this 20% of the way down the screen
frac = frac * 1.2f - 0.2f;
@@ -217,8 +220,6 @@
panel.setAlpha(alpha);
}
- mBar.animateHeadsUp(mNotificationPanel == panel, mPanelExpandedFractionSum);
-
mBar.updateCarrierLabelVisibility(false);
mBar.userActivity();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
new file mode 100644
index 0000000..9d33930
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.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 com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+
+import com.android.systemui.R;
+
+/**
+ * The view to manage the header area in the expanded status bar.
+ */
+public class StatusBarHeaderView extends RelativeLayout {
+
+ private boolean mExpanded;
+ private View mBackground;
+ private View mFlipper;
+
+ private int mCollapsedHeight;
+ private int mExpandedHeight;
+
+ public StatusBarHeaderView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mBackground = findViewById(R.id.background);
+ mFlipper = findViewById(R.id.header_flipper);
+ loadDimens();
+ }
+
+ private void loadDimens() {
+ mCollapsedHeight = getResources().getDimensionPixelSize(
+ R.dimen.status_bar_header_height);
+ mExpandedHeight = getResources().getDimensionPixelSize(
+ R.dimen.status_bar_header_height_expanded);
+ }
+
+ public int getCollapsedHeight() {
+ return mCollapsedHeight;
+ }
+
+ public int getExpandedHeight() {
+ return mExpandedHeight;
+ }
+
+ public void setExpanded(boolean expanded) {
+ if (expanded != mExpanded) {
+ ViewGroup.LayoutParams lp = getLayoutParams();
+ lp.height = expanded ? mExpandedHeight : mCollapsedHeight;
+ setLayoutParams(lp);
+ mExpanded = expanded;
+ }
+ }
+
+ public void setExpansionEnabled(boolean enabled) {
+ mFlipper.setVisibility(enabled ? View.VISIBLE : View.GONE);
+ }
+
+ public void setExpansion(float height) {
+ if (height < mCollapsedHeight) {
+ height = mCollapsedHeight;
+ }
+ if (height > mExpandedHeight) {
+ height = mExpandedHeight;
+ }
+ if (mExpanded) {
+ mBackground.setTranslationY(-(mExpandedHeight - height));
+ } else {
+ mBackground.setTranslationY(0);
+ }
+ }
+
+ public View getBackgroundView() {
+ return mBackground;
+ }
+}
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 c2595cf..e24ddd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -18,22 +18,14 @@
import android.content.Context;
import android.os.Bundle;
-import android.os.IBinder;
import android.os.RemoteException;
-import android.util.Log;
import android.util.Slog;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
import com.android.internal.policy.IKeyguardShowCallback;
import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardHostView;
-import com.android.keyguard.KeyguardSimpleHostView;
-import com.android.keyguard.R;
import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.keyguard.KeyguardViewMediator;
/**
* Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
@@ -82,7 +74,7 @@
mShowing = true;
mStatusBarWindowManager.setKeyguardShowing(true);
showBouncerOrKeyguard();
- updateBackButtonState();
+ updateStates();
}
/**
@@ -102,9 +94,9 @@
}
}
- public void showBouncer() {
+ private void showBouncer() {
mBouncer.show();
- updateBackButtonState();
+ updateStates();
}
/**
@@ -112,7 +104,7 @@
*/
public void reset() {
showBouncerOrKeyguard();
- updateBackButtonState();
+ updateStates();
}
public void onScreenTurnedOff() {
@@ -155,7 +147,7 @@
public void setOccluded(boolean occluded) {
mOccluded = occluded;
mStatusBarWindowManager.setKeyguardOccluded(occluded);
- updateBackButtonState();
+ updateStates();
}
/**
@@ -167,7 +159,7 @@
mStatusBarWindowManager.setKeyguardShowing(false);
mBouncer.hide();
mViewMediatorCallback.keyguardGone();
- updateBackButtonState();
+ updateStates();
}
/**
@@ -199,13 +191,13 @@
if (mBouncer.isShowing()) {
mBouncer.hide();
mPhoneStatusBar.showKeyguard();
- updateBackButtonState();
+ updateStates();
return true;
}
return false;
}
- private void updateBackButtonState() {
+ private void updateStates() {
int vis = mContainer.getSystemUiVisibility();
boolean bouncerDismissable = mBouncer.isShowing() && !mBouncer.needsFullscreenBouncer();
if (bouncerDismissable || !mShowing) {
@@ -213,11 +205,14 @@
} else {
mContainer.setSystemUiVisibility(vis | View.STATUS_BAR_DISABLE_BACK);
}
- if (!(mShowing && !mOccluded) || mBouncer.isShowing()) {
- mPhoneStatusBar.getNavigationBarView().setVisibility(View.VISIBLE);
- } else {
- mPhoneStatusBar.getNavigationBarView().setVisibility(View.GONE);
+ if (mPhoneStatusBar.getNavigationBarView() != null) {
+ if (!(mShowing && !mOccluded) || mBouncer.isShowing()) {
+ mPhoneStatusBar.getNavigationBarView().setVisibility(View.VISIBLE);
+ } else {
+ mPhoneStatusBar.getNavigationBarView().setVisibility(View.GONE);
+ }
}
+ mPhoneStatusBar.setBouncerShowing(mBouncer.isShowing());
}
public boolean onMenuPressed() {
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 d175d7a..a4c9df5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.phone;
-import android.app.ActionBar;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
@@ -28,6 +27,8 @@
import android.view.WindowManager;
import com.android.keyguard.R;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.StatusBarState;
/**
* Encapsulates all logic for the status bar window state management.
@@ -137,7 +138,8 @@
}
private void applyUserActivityTimeout(State state) {
- if (state.isKeyguardShowingAndNotOccluded()) {
+ if (state.isKeyguardShowingAndNotOccluded()
+ && state.statusBarState == StatusBarState.KEYGUARD) {
mLp.userActivityTimeout = state.keyguardUserActivityTimeout;
} else {
mLp.userActivityTimeout = -1;
@@ -145,7 +147,8 @@
}
private void applyInputFeatures(State state) {
- if (state.isKeyguardShowingAndNotOccluded()) {
+ if (state.isKeyguardShowingAndNotOccluded()
+ && state.statusBarState == StatusBarState.KEYGUARD) {
mLp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
} else {
mLp.inputFeatures &= ~WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
@@ -194,6 +197,14 @@
apply(mCurrentState);
}
+ /**
+ * @param state The {@link StatusBarState} of the status bar.
+ */
+ public void setStatusBarState(int state) {
+ mCurrentState.statusBarState = state;
+ apply(mCurrentState);
+ }
+
private static class State {
boolean keyguardShowing;
boolean keyguardOccluded;
@@ -202,6 +213,11 @@
boolean statusBarFocusable;
long keyguardUserActivityTimeout;
+ /**
+ * The {@link BaseStatusBar} state from the status bar.
+ */
+ int statusBarState;
+
private boolean isKeyguardShowingAndNotOccluded() {
return keyguardShowing && !keyguardOccluded;
}
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 6b5ef5a..e802d185 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -31,16 +31,17 @@
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.statusbar.BaseStatusBar;
-import com.android.systemui.statusbar.policy.ScrollAdapter;
+import com.android.systemui.statusbar.DragDownHelper;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
-public class StatusBarWindowView extends FrameLayout
-{
+public class StatusBarWindowView extends FrameLayout {
public static final String TAG = "StatusBarWindowView";
public static final boolean DEBUG = BaseStatusBar.DEBUG;
private ExpandHelper mExpandHelper;
+ private DragDownHelper mDragDownHelper;
private NotificationStackScrollLayout mStackScrollLayout;
private NotificationPanelView mNotificationPanel;
@@ -55,11 +56,14 @@
@Override
protected boolean fitSystemWindows(Rect insets) {
if (getFitsSystemWindows()) {
- setPadding(insets.left, insets.top, insets.right, insets.bottom);
+ setPadding(insets.left, insets.top, insets.right, 0);
+ insets.left = 0;
+ insets.top = 0;
+ insets.right = 0;
} else {
setPadding(0, 0, 0, 0);
}
- return true;
+ return false;
}
@Override
@@ -75,6 +79,7 @@
minHeight, maxHeight);
mExpandHelper.setEventSource(this);
mExpandHelper.setScrollAdapter(mStackScrollLayout);
+ mDragDownHelper = new DragDownHelper(getContext(), this, mStackScrollLayout, mService);
// We really need to be able to animate while window animations are going on
// so that activities may be started asynchronously from panel animations
@@ -106,8 +111,15 @@
boolean intercept = false;
if (mNotificationPanel.isFullyExpanded()
&& mStackScrollLayout.getVisibility() == View.VISIBLE
- && !mService.isOnKeyguard()) {
+ && (mService.getBarState() == StatusBarState.SHADE
+ || (mService.getBarState() == StatusBarState.SHADE_LOCKED
+ && !mService.isBouncerShowing()))) {
intercept = mExpandHelper.onInterceptTouchEvent(ev);
+ } else if (mNotificationPanel.isFullyExpanded()
+ && mStackScrollLayout.getVisibility() == View.VISIBLE
+ && mService.getBarState() == StatusBarState.KEYGUARD
+ && !mService.isBouncerShowing()) {
+ intercept = mDragDownHelper.onInterceptTouchEvent(ev);
}
if (!intercept) {
super.onInterceptTouchEvent(ev);
@@ -124,8 +136,11 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean handled = false;
- if (mNotificationPanel.isFullyExpanded()) {
+ if (mNotificationPanel.isFullyExpanded()
+ && mService.getBarState() != StatusBarState.KEYGUARD) {
handled = mExpandHelper.onTouchEvent(ev);
+ } else if (mService.getBarState() == StatusBarState.KEYGUARD) {
+ handled = mDragDownHelper.onTouchEvent(ev);
}
if (!handled) {
handled = super.onTouchEvent(ev);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SwipeAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SwipeAffordanceView.java
new file mode 100644
index 0000000..049c5fc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SwipeAffordanceView.java
@@ -0,0 +1,222 @@
+/*
+ * 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.res.TypedArray;
+import android.os.SystemClock;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.Button;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.KeyButtonView;
+
+/**
+ * A swipeable button for affordances on the lockscreen. This is used for the camera and phone
+ * affordance.
+ */
+public class SwipeAffordanceView extends KeyButtonView {
+
+ private static final int SWIPE_DIRECTION_START = 0;
+ private static final int SWIPE_DIRECTION_END = 1;
+
+ private static final int SWIPE_DIRECTION_LEFT = 0;
+ private static final int SWIPE_DIRECTION_RIGHT = 1;
+
+ private AffordanceListener mListener;
+ private int mScaledTouchSlop;
+ private float mDragDistance;
+ private int mResolvedSwipeDirection;
+ private int mSwipeDirection;
+
+ public SwipeAffordanceView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SwipeAffordanceView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ TypedArray a = context.getTheme().obtainStyledAttributes(
+ attrs,
+ R.styleable.SwipeAffordanceView,
+ 0, 0);
+ try {
+ mSwipeDirection = a.getInt(R.styleable.SwipeAffordanceView_swipeDirection, 0);
+ } finally {
+ a.recycle();
+ }
+ }
+
+ @Override
+ public void onRtlPropertiesChanged(int layoutDirection) {
+ super.onRtlPropertiesChanged(layoutDirection);
+ if (!isLayoutRtl()) {
+ mResolvedSwipeDirection = mSwipeDirection;
+ } else {
+ mResolvedSwipeDirection = mSwipeDirection == SWIPE_DIRECTION_START
+ ? SWIPE_DIRECTION_RIGHT
+ : SWIPE_DIRECTION_LEFT;
+ }
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mDragDistance = getResources().getDimension(R.dimen.affordance_drag_distance);
+ mScaledTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ }
+
+ public void enableAccessibility(boolean touchExplorationEnabled) {
+
+ // Add a touch handler or accessibility click listener for camera button.
+ if (touchExplorationEnabled) {
+ setOnTouchListener(null);
+ setOnClickListener(mClickListener);
+ } else {
+ setOnTouchListener(mTouchListener);
+ setOnClickListener(null);
+ }
+ }
+
+ public void setAffordanceListener(AffordanceListener listener) {
+ mListener = listener;
+ }
+
+ private void onActionPerformed() {
+ if (mListener != null) {
+ mListener.onActionPerformed(this);
+ }
+ }
+
+ private void onUserActivity(long when) {
+ if (mListener != null) {
+ mListener.onUserActivity(when);
+ }
+ }
+
+ private final OnClickListener mClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onActionPerformed();
+ }
+ };
+
+ private final OnTouchListener mTouchListener = new OnTouchListener() {
+ private float mStartX;
+ private boolean mTouchSlopReached;
+ private boolean mSkipCancelAnimation;
+
+ @Override
+ public boolean onTouch(final View view, MotionEvent event) {
+ float realX = event.getRawX();
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mStartX = realX;
+ mTouchSlopReached = false;
+ mSkipCancelAnimation = false;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
+ ? realX > mStartX
+ : realX < mStartX) {
+ realX = mStartX;
+ }
+ if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
+ ? realX < mStartX - mDragDistance
+ : realX > mStartX + mDragDistance) {
+ view.setPressed(true);
+ onUserActivity(event.getEventTime());
+ } else {
+ view.setPressed(false);
+ }
+ if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
+ ? realX < mStartX - mScaledTouchSlop
+ : realX > mStartX + mScaledTouchSlop) {
+ mTouchSlopReached = true;
+ }
+ view.setTranslationX(mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
+ ? Math.max(realX - mStartX, -mDragDistance)
+ : Math.min(realX - mStartX, mDragDistance));
+ break;
+ case MotionEvent.ACTION_UP:
+ if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
+ ? realX < mStartX - mDragDistance
+ : realX > mStartX + mDragDistance) {
+ onActionPerformed();
+ view.animate().x(mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
+ ? -view.getWidth()
+ : ((View) view.getParent()).getWidth() + view.getWidth())
+ .setInterpolator(new AccelerateInterpolator(2f)).withEndAction(
+ new Runnable() {
+ @Override
+ public void run() {
+ view.setTranslationX(0);
+ }
+ });
+ mSkipCancelAnimation = true;
+ }
+ if (mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
+ ? realX < mStartX - mScaledTouchSlop
+ : realX > mStartX + mScaledTouchSlop) {
+ mTouchSlopReached = true;
+ }
+ if (!mTouchSlopReached) {
+ mSkipCancelAnimation = true;
+ view.animate().translationX(mResolvedSwipeDirection == SWIPE_DIRECTION_LEFT
+ ? -mDragDistance / 2
+ : mDragDistance / 2).
+ setInterpolator(new DecelerateInterpolator()).withEndAction(
+ new Runnable() {
+ @Override
+ public void run() {
+ view.animate().translationX(0).
+ setInterpolator(new AccelerateInterpolator());
+ }
+ });
+ }
+ case MotionEvent.ACTION_CANCEL:
+ view.setPressed(false);
+ if (!mSkipCancelAnimation) {
+ view.animate().translationX(0)
+ .setInterpolator(new AccelerateInterpolator(2f));
+ }
+ break;
+ }
+ return true;
+ }
+ };
+
+ public interface AffordanceListener {
+
+ /**
+ * Called when the view would like to report user activity.
+ *
+ * @param when The timestamp of the user activity in {@link SystemClock#uptimeMillis} time
+ * base.
+ */
+ void onUserActivity(long when);
+
+ /**
+ * Called when the action of the affordance has been performed.
+ */
+ void onActionPerformed(SwipeAffordanceView view);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
index 20011ff..ff921cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
@@ -356,7 +356,7 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
- log("onTouchEvent " + MotionEvent.actionToString(event.getAction()));
+ if (DEBUG) log("onTouchEvent " + MotionEvent.actionToString(event.getAction()));
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mDownX = event.getX();
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
index 1bc97a0..8748888 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
@@ -58,7 +58,7 @@
mNoMan = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
try {
- mNoMan.requestZenModeConditions(mListener, true /*requested*/);
+ mNoMan.requestZenModeConditions(mListener, Condition.FLAG_RELEVANT_NOW);
} catch (RemoteException e) {
// noop
}
@@ -98,7 +98,7 @@
@Override
public void dispose() {
try {
- mNoMan.requestZenModeConditions(mListener, false /*requested*/);
+ mNoMan.requestZenModeConditions(mListener, 0 /*none*/);
} catch (RemoteException e) {
// noop
}
@@ -222,7 +222,7 @@
mExits.remove(i);
}
for (Condition c : mConditions.values()) {
- mExits.add(newExit(c.caption, "", "", c.id));
+ mExits.add(newExit(c.summary, c.line1, c.line2, c.id));
}
dispatchChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index c94c65f..81e2cb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -32,6 +32,7 @@
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.NotificationData;
public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.Callback, ExpandHelper.Callback {
@@ -185,12 +186,12 @@
// ExpandHelper.Callback methods
@Override
- public View getChildAtRawPosition(float x, float y) {
+ public ExpandableView getChildAtRawPosition(float x, float y) {
return getChildAtPosition(x, y);
}
@Override
- public View getChildAtPosition(float x, float y) {
+ public ExpandableView getChildAtPosition(float x, float y) {
return mHeadsUp == null ? null : mHeadsUp.row;
}
@@ -236,6 +237,10 @@
}
@Override
+ public void onChildSnappedBack(View animView) {
+ }
+
+ @Override
public View getChildAtPosition(MotionEvent ev) {
return mContentHolder;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
new file mode 100644
index 0000000..4121a40
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.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 com.android.systemui.statusbar.stack;
+
+import android.view.View;
+
+import java.util.ArrayList;
+
+/**
+ * A global state to track all input states for the algorithm.
+ */
+public class AmbientState {
+ private ArrayList<View> mDraggedViews = new ArrayList<View>();
+ private int mScrollY;
+ private boolean mDimmed;
+ private View mActivatedChild;
+
+ public int getScrollY() {
+ return mScrollY;
+ }
+
+ public void setScrollY(int scrollY) {
+ this.mScrollY = scrollY;
+ }
+
+ public void onBeginDrag(View view) {
+ mDraggedViews.add(view);
+ }
+
+ public void onDragFinished(View view) {
+ mDraggedViews.remove(view);
+ }
+
+ public ArrayList<View> getDraggedViews() {
+ return mDraggedViews;
+ }
+
+ /**
+ * @param dimmed Whether we are in a dimmed state (on the lockscreen), where the backgrounds are
+ * translucent and everything is scaled back a bit.
+ */
+ public void setDimmed(boolean dimmed) {
+ mDimmed = dimmed;
+ }
+
+ /**
+ * In dimmed mode, a child can be activated, which happens on the first tap of the double-tap
+ * interaction. This child is then scaled normally and its background is fully opaque.
+ */
+ public void setActivatedChild(View activatedChild) {
+ mActivatedChild = activatedChild;
+ }
+
+ public boolean isDimmed() {
+ return mDimmed;
+ }
+
+ public View getActivatedChild() {
+ return mActivatedChild;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
new file mode 100644
index 0000000..41914ed
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -0,0 +1,92 @@
+/*
+ * 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.stack;
+
+import java.util.ArrayList;
+
+/**
+ * Filters the animations for only a certain type of properties.
+ */
+public class AnimationFilter {
+ boolean animateAlpha;
+ boolean animateY;
+ boolean animateZ;
+ boolean animateScale;
+ boolean animateHeight;
+ boolean animateDimmed;
+
+ public AnimationFilter animateAlpha() {
+ animateAlpha = true;
+ return this;
+ }
+
+ public AnimationFilter animateY() {
+ animateY = true;
+ return this;
+ }
+
+ public AnimationFilter animateZ() {
+ animateZ = true;
+ return this;
+ }
+
+ public AnimationFilter animateScale() {
+ animateScale = true;
+ return this;
+ }
+
+ public AnimationFilter animateHeight() {
+ animateHeight = true;
+ return this;
+ }
+
+ public AnimationFilter animateDimmed() {
+ animateDimmed = true;
+ return this;
+ }
+
+ /**
+ * Combines multiple filters into {@code this} filter, using or as the operand .
+ *
+ * @param events The animation events from the filters to combine.
+ */
+ public void applyCombination(ArrayList<NotificationStackScrollLayout.AnimationEvent> events) {
+ reset();
+ int size = events.size();
+ for (int i = 0; i < size; i++) {
+ combineFilter(events.get(i).filter);
+ }
+ }
+
+ private void combineFilter(AnimationFilter filter) {
+ animateAlpha |= filter.animateAlpha;
+ animateY |= filter.animateY;
+ animateZ |= filter.animateZ;
+ animateScale |= filter.animateScale;
+ animateHeight |= filter.animateHeight;
+ animateDimmed |= filter.animateDimmed;
+ }
+
+ private void reset() {
+ animateAlpha = false;
+ animateY = false;
+ animateZ = false;
+ animateScale = false;
+ animateHeight = false;
+ animateDimmed = false;
+ }
+}
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 9a43e37..afd5068 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -84,7 +84,6 @@
private int mEmptyMarginBottom;
private int mPaddingBetweenElements;
private int mTopPadding;
- private boolean mListenForHeightChanges = true;
/**
* The algorithm which calculates the properties for our children
@@ -95,23 +94,30 @@
* The current State this Layout is in
*/
private StackScrollState mCurrentStackScrollState = new StackScrollState(this);
+ private AmbientState mAmbientState = new AmbientState();
private ArrayList<View> mChildrenToAddAnimated = new ArrayList<View>();
private ArrayList<View> mChildrenToRemoveAnimated = new ArrayList<View>();
- private ArrayList<ChildHierarchyChangeEvent> mAnimationEvents
- = new ArrayList<ChildHierarchyChangeEvent>();
+ private ArrayList<View> mSnappedBackChildren = new ArrayList<View>();
+ private ArrayList<View> mDragAnimPendingChildren = new ArrayList<View>();
+ private ArrayList<AnimationEvent> mAnimationEvents
+ = new ArrayList<AnimationEvent>();
private ArrayList<View> mSwipedOutViews = new ArrayList<View>();
private final StackStateAnimator mStateAnimator = new StackStateAnimator(this);
private OnChildLocationsChangedListener mListener;
private ExpandableView.OnHeightChangedListener mOnHeightChangedListener;
- private boolean mChildHierarchyDirty;
+ private boolean mNeedsAnimation;
+ private boolean mTopPaddingNeedsAnimation;
+ private boolean mDimmedNeedsAnimation;
+ private boolean mActivateNeedsAnimation;
private boolean mIsExpanded = true;
- private ViewTreeObserver.OnPreDrawListener mAfterLayoutPreDrawListener
+ private boolean mChildrenUpdateRequested;
+ private ViewTreeObserver.OnPreDrawListener mChildrenUpdater
= new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
- updateScrollPositionIfNecessary();
updateChildren();
+ mChildrenUpdateRequested = false;
getViewTreeObserver().removeOnPreDrawListener(this);
return true;
}
@@ -158,6 +164,7 @@
mScroller = new OverScroller(getContext());
setFocusable(true);
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
+ setClipChildren(false);
final ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = configuration.getScaledTouchSlop();
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
@@ -206,7 +213,8 @@
}
setMaxLayoutHeight(getHeight() - mEmptyMarginBottom);
updateContentHeight();
- getViewTreeObserver().addOnPreDrawListener(mAfterLayoutPreDrawListener);
+ updateScrollPositionIfNecessary();
+ requestChildrenUpdate();
}
public void setChildLocationsChangedListener(OnChildLocationsChangedListener listener) {
@@ -238,19 +246,43 @@
}
/**
+ * @return whether the height of the layout needs to be adapted, in order to ensure that the
+ * last child is not in the bottom stack.
+ */
+ private boolean needsHeightAdaption() {
+ View lastChild = getLastChildNotGone();
+ View firstChild = getFirstChildNotGone();
+ boolean isLastChildExpanded = isViewExpanded(lastChild);
+ return isLastChildExpanded && lastChild != firstChild;
+ }
+
+ private boolean isViewExpanded(View view) {
+ if (view != null) {
+ ExpandableView expandView = (ExpandableView) view;
+ return expandView.getActualHeight() > mCollapsedSize;
+ }
+ return false;
+ }
+
+ /**
* Updates the children views according to the stack scroll algorithm. Call this whenever
* modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout.
*/
private void updateChildren() {
- mCurrentStackScrollState.setScrollY(mOwnScrollY);
- mStackScrollAlgorithm.getStackScrollState(mCurrentStackScrollState);
- if (!isCurrentlyAnimating() && !mChildHierarchyDirty) {
+ mAmbientState.setScrollY(mOwnScrollY);
+ mStackScrollAlgorithm.getStackScrollState(mAmbientState, mCurrentStackScrollState);
+ if (!isCurrentlyAnimating() && !mNeedsAnimation) {
applyCurrentState();
- if (mListener != null) {
- mListener.onChildLocationsChanged(this);
- }
} else {
- startAnimationToState(mCurrentStackScrollState);
+ startAnimationToState();
+ }
+ }
+
+ private void requestChildrenUpdate() {
+ if (!mChildrenUpdateRequested) {
+ getViewTreeObserver().addOnPreDrawListener(mChildrenUpdater);
+ mChildrenUpdateRequested = true;
+ invalidate();
}
}
@@ -269,12 +301,19 @@
return mTopPadding;
}
- public void setTopPadding(int topPadding) {
+ public void setTopPadding(int topPadding, boolean animate) {
if (mTopPadding != topPadding) {
mTopPadding = topPadding;
updateAlgorithmHeightAndPadding();
updateContentHeight();
- updateChildren();
+ if (animate) {
+ mTopPaddingNeedsAnimation = true;
+ mNeedsAnimation = true;
+ }
+ requestChildrenUpdate();
+ if (mOnHeightChangedListener != null) {
+ mOnHeightChangedListener.onHeightChanged(null);
+ }
}
}
@@ -309,7 +348,7 @@
if (stackHeight != mCurrentStackHeight) {
mCurrentStackHeight = stackHeight;
updateAlgorithmHeightAndPadding();
- updateChildren();
+ requestChildrenUpdate();
}
}
@@ -342,11 +381,34 @@
veto.performClick();
}
setSwipingInProgress(false);
+ if (mDragAnimPendingChildren.contains(v)) {
+ // We start the swipe and finish it in the same frame, we don't want any animation
+ // for the drag
+ mDragAnimPendingChildren.remove(v);
+ }
mSwipedOutViews.add(v);
+ mAmbientState.onDragFinished(v);
+ }
+
+ @Override
+ public void onChildSnappedBack(View animView) {
+ mAmbientState.onDragFinished(animView);
+ if (!mDragAnimPendingChildren.contains(animView)) {
+ mSnappedBackChildren.add(animView);
+ requestChildrenUpdate();
+ mNeedsAnimation = true;
+ } else {
+ // We start the swipe and snap back in the same frame, we don't want any animation
+ mDragAnimPendingChildren.remove(animView);
+ }
}
public void onBeginDrag(View v) {
setSwipingInProgress(true);
+ mDragAnimPendingChildren.add(v);
+ mAmbientState.onBeginDrag(v);
+ requestChildrenUpdate();
+ mNeedsAnimation = true;
}
public void onDragCancelled(View v) {
@@ -357,13 +419,13 @@
return getChildAtPosition(ev.getX(), ev.getY());
}
- public View getChildAtRawPosition(float touchX, float touchY) {
+ public ExpandableView getChildAtRawPosition(float touchX, float touchY) {
int[] location = new int[2];
getLocationOnScreen(location);
- return getChildAtPosition(touchX - location[0],touchY - location[1]);
+ return getChildAtPosition(touchX - location[0], touchY - location[1]);
}
- public View getChildAtPosition(float touchX, float touchY) {
+ public ExpandableView getChildAtPosition(float touchX, float touchY) {
// find the view under the pointer, accounting for GONE views
final int count = getChildCount();
for (int childIdx = 0; childIdx < count; childIdx++) {
@@ -432,6 +494,9 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
+ if (!isEnabled()) {
+ return false;
+ }
boolean scrollerWantsIt = false;
if (!mSwipingInProgress) {
scrollerWantsIt = onScrollTouch(ev);
@@ -451,7 +516,7 @@
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
- if (getChildCount() == 0) {
+ if (getChildCount() == 0 || !isInContentBounds(ev)) {
return false;
}
boolean isBeingDragged = !mScroller.isFinished();
@@ -643,19 +708,13 @@
}
}
- public void customScrollBy(int y) {
- mOwnScrollY += y;
- updateChildren();
- }
-
- public void customScrollTo(int y) {
+ private void customScrollTo(int y) {
mOwnScrollY = y;
updateChildren();
}
@Override
- protected void onOverScrolled(int scrollX, int scrollY,
- boolean clampedX, boolean clampedY) {
+ protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
// Treat animating scrolls differently; see #computeScroll() for why.
if (!mScroller.isFinished()) {
final int oldX = mScrollX;
@@ -682,7 +741,13 @@
int firstChildMaxExpandHeight = getMaxExpandHeight(firstChild);
scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight + mBottomStackPeekSize);
- if (scrollRange > 0 && getChildCount() > 0) {
+ 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);
@@ -705,10 +770,24 @@
return null;
}
+ /**
+ * @return the last child which has visibility unequal to GONE
+ */
+ private View getLastChildNotGone() {
+ int childCount = getChildCount();
+ for (int i = childCount - 1; i >= 0; i--) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != View.GONE) {
+ return child;
+ }
+ }
+ return null;
+ }
+
private int getMaxExpandHeight(View view) {
if (view instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- return row.getMaximumAllowedExpandHeight();
+ return row.getIntrinsicHeight();
}
return view.getHeight();
}
@@ -728,7 +807,7 @@
}
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- height += row.getMaximumAllowedExpandHeight();
+ height += row.getIntrinsicHeight();
} else if (child instanceof ExpandableView) {
ExpandableView expandableView = (ExpandableView) child;
height += expandableView.getActualHeight();
@@ -792,9 +871,13 @@
updateScrollStateForRemovedChild(child);
if (mIsExpanded) {
- // Generate Animations
- mChildrenToRemoveAnimated.add(child);
- mChildHierarchyDirty = true;
+ if (!mChildrenToAddAnimated.contains(child)) {
+ // Generate Animations
+ mChildrenToRemoveAnimated.add(child);
+ mNeedsAnimation = true;
+ } else {
+ mChildrenToAddAnimated.remove(child);
+ }
}
}
@@ -850,7 +933,7 @@
// Generate Animations
mChildrenToAddAnimated.add(child);
- mChildHierarchyDirty = true;
+ mNeedsAnimation = true;
}
}
@@ -866,40 +949,89 @@
}
}
- private void startAnimationToState(StackScrollState finalState) {
- if (mChildHierarchyDirty) {
+ private void startAnimationToState() {
+ if (mNeedsAnimation) {
generateChildHierarchyEvents();
- mChildHierarchyDirty = false;
+ mNeedsAnimation = false;
}
- mStateAnimator.startAnimationForEvents(mAnimationEvents, finalState);
+ if (!mAnimationEvents.isEmpty()) {
+ mStateAnimator.startAnimationForEvents(mAnimationEvents, mCurrentStackScrollState);
+ } else {
+ applyCurrentState();
+ }
}
private void generateChildHierarchyEvents() {
generateChildAdditionEvents();
generateChildRemovalEvents();
- mChildHierarchyDirty = false;
+ generateSnapBackEvents();
+ generateDragEvents();
+ generateTopPaddingEvent();
+ generateActivateEvent();
+ generateDimmedEvent();
+ mNeedsAnimation = false;
+ }
+
+ private void generateSnapBackEvents() {
+ for (View child : mSnappedBackChildren) {
+ mAnimationEvents.add(new AnimationEvent(child,
+ AnimationEvent.ANIMATION_TYPE_SNAP_BACK));
+ }
+ mSnappedBackChildren.clear();
+ }
+
+ private void generateDragEvents() {
+ for (View child : mDragAnimPendingChildren) {
+ mAnimationEvents.add(new AnimationEvent(child,
+ AnimationEvent.ANIMATION_TYPE_START_DRAG));
+ }
+ mDragAnimPendingChildren.clear();
}
private void generateChildRemovalEvents() {
- for (View child : mChildrenToRemoveAnimated) {
+ for (View child : mChildrenToRemoveAnimated) {
boolean childWasSwipedOut = mSwipedOutViews.contains(child);
int animationType = childWasSwipedOut
- ? ChildHierarchyChangeEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT
- : ChildHierarchyChangeEvent.ANIMATION_TYPE_REMOVE;
- mAnimationEvents.add(new ChildHierarchyChangeEvent(child, animationType));
+ ? AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT
+ : AnimationEvent.ANIMATION_TYPE_REMOVE;
+ mAnimationEvents.add(new AnimationEvent(child, animationType));
}
mSwipedOutViews.clear();
mChildrenToRemoveAnimated.clear();
}
private void generateChildAdditionEvents() {
- for (View child : mChildrenToAddAnimated) {
- mAnimationEvents.add(new ChildHierarchyChangeEvent(child,
- ChildHierarchyChangeEvent.ANIMATION_TYPE_ADD));
+ for (View child : mChildrenToAddAnimated) {
+ mAnimationEvents.add(new AnimationEvent(child,
+ AnimationEvent.ANIMATION_TYPE_ADD));
}
mChildrenToAddAnimated.clear();
}
+ private void generateTopPaddingEvent() {
+ if (mTopPaddingNeedsAnimation) {
+ mAnimationEvents.add(
+ new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_TOP_PADDING_CHANGED));
+ }
+ mTopPaddingNeedsAnimation = false;
+ }
+
+ private void generateActivateEvent() {
+ if (mActivateNeedsAnimation) {
+ mAnimationEvents.add(
+ new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_ACTIVATED_CHILD));
+ }
+ mActivateNeedsAnimation = false;
+ }
+
+ private void generateDimmedEvent() {
+ if (mDimmedNeedsAnimation) {
+ mAnimationEvents.add(
+ new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_DIMMED));
+ }
+ mDimmedNeedsAnimation = false;
+ }
+
private boolean onInterceptTouchEventScroll(MotionEvent ev) {
/*
* This method JUST determines whether we want to intercept the motion.
@@ -1008,6 +1140,13 @@
return mIsBeingDragged;
}
+ /**
+ * @return Whether the specified motion event is actually happening over the content.
+ */
+ private boolean isInContentBounds(MotionEvent event) {
+ return event.getY() < getHeight() - getEmptyBottomMargin();
+ }
+
private void setIsBeingDragged(boolean isDragged) {
mIsBeingDragged = isDragged;
if (isDragged) {
@@ -1040,7 +1179,11 @@
}
public int getEmptyBottomMargin() {
- return Math.max(getHeight() - mContentHeight, 0);
+ int emptyMargin = mMaxLayoutHeight - mContentHeight;
+ if (needsHeightAdaption()) {
+ emptyMargin = emptyMargin - mCollapsedSize - mBottomStackPeekSize;
+ }
+ return Math.max(emptyMargin, 0);
}
public void onExpansionStarted() {
@@ -1061,14 +1204,12 @@
@Override
public void onHeightChanged(ExpandableView view) {
- if (mListenForHeightChanges && !isCurrentlyAnimating()) {
- updateContentHeight();
- updateScrollPositionIfNecessary();
- if (mOnHeightChangedListener != null) {
- mOnHeightChangedListener.onHeightChanged(view);
- }
- updateChildren();
+ updateContentHeight();
+ updateScrollPositionIfNecessary();
+ if (mOnHeightChangedListener != null) {
+ mOnHeightChangedListener.onHeightChanged(view);
}
+ requestChildrenUpdate();
}
public void setOnHeightChangedListener(
@@ -1077,14 +1218,41 @@
}
public void onChildAnimationFinished() {
- applyCurrentState();
+ requestChildrenUpdate();
mAnimationEvents.clear();
}
+ /**
+ * See {@link AmbientState#setDimmed}.
+ */
+ public void setDimmed(boolean dimmed, boolean animate) {
+ mAmbientState.setDimmed(dimmed);
+ if (animate) {
+ mDimmedNeedsAnimation = true;
+ mNeedsAnimation = true;
+ }
+ requestChildrenUpdate();
+ }
+
+ /**
+ * See {@link AmbientState#setActivatedChild}.
+ */
+ public void setActivatedChild(View activatedChild) {
+ mAmbientState.setActivatedChild(activatedChild);
+ mActivateNeedsAnimation = true;
+ mNeedsAnimation = true;
+ requestChildrenUpdate();
+ }
+
+ public View getActivatedChild() {
+ return mAmbientState.getActivatedChild();
+ }
+
private void applyCurrentState() {
- mListenForHeightChanges = false;
mCurrentStackScrollState.apply();
- mListenForHeightChanges = true;
+ if (mListener != null) {
+ mListener.onChildLocationsChanged(this);
+ }
}
/**
@@ -1094,19 +1262,122 @@
public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout);
}
- static class ChildHierarchyChangeEvent {
+ static class AnimationEvent {
- static int ANIMATION_TYPE_ADD = 1;
- static int ANIMATION_TYPE_REMOVE = 2;
- static int ANIMATION_TYPE_REMOVE_SWIPED_OUT = 3;
+ static AnimationFilter[] FILTERS = new AnimationFilter[] {
+
+ // ANIMATION_TYPE_ADD
+ new AnimationFilter()
+ .animateAlpha()
+ .animateHeight()
+ .animateY()
+ .animateZ(),
+
+ // ANIMATION_TYPE_REMOVE
+ new AnimationFilter()
+ .animateAlpha()
+ .animateHeight()
+ .animateY()
+ .animateZ(),
+
+ // ANIMATION_TYPE_REMOVE_SWIPED_OUT
+ new AnimationFilter()
+ .animateAlpha()
+ .animateHeight()
+ .animateY()
+ .animateZ(),
+
+ // ANIMATION_TYPE_TOP_PADDING_CHANGED
+ new AnimationFilter()
+ .animateAlpha()
+ .animateHeight()
+ .animateY()
+ .animateDimmed()
+ .animateScale()
+ .animateZ(),
+
+ // ANIMATION_TYPE_START_DRAG
+ new AnimationFilter()
+ .animateAlpha(),
+
+ // ANIMATION_TYPE_SNAP_BACK
+ new AnimationFilter()
+ .animateAlpha(),
+
+ // ANIMATION_TYPE_ACTIVATED_CHILD
+ new AnimationFilter()
+ .animateScale()
+ .animateAlpha(),
+
+ // ANIMATION_TYPE_DIMMED
+ new AnimationFilter()
+ .animateScale()
+ .animateDimmed()
+ };
+
+ static int[] LENGTHS = new int[] {
+
+ // ANIMATION_TYPE_ADD
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+ // ANIMATION_TYPE_REMOVE
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+ // ANIMATION_TYPE_REMOVE_SWIPED_OUT
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+ // ANIMATION_TYPE_TOP_PADDING_CHANGED
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+ // ANIMATION_TYPE_START_DRAG
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+ // ANIMATION_TYPE_SNAP_BACK
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+ // ANIMATION_TYPE_ACTIVATED_CHILD
+ StackStateAnimator.ANIMATION_DURATION_DIMMED_ACTIVATED,
+
+ // ANIMATION_TYPE_DIMMED
+ StackStateAnimator.ANIMATION_DURATION_DIMMED_ACTIVATED,
+ };
+
+ static int ANIMATION_TYPE_ADD = 0;
+ static int ANIMATION_TYPE_REMOVE = 1;
+ static int ANIMATION_TYPE_REMOVE_SWIPED_OUT = 2;
+ static int ANIMATION_TYPE_TOP_PADDING_CHANGED = 3;
+ static int ANIMATION_TYPE_START_DRAG = 4;
+ static int ANIMATION_TYPE_SNAP_BACK = 5;
+ static int ANIMATION_TYPE_ACTIVATED_CHILD = 6;
+ static int ANIMATION_TYPE_DIMMED = 7;
+
final long eventStartTime;
final View changingView;
final int animationType;
+ final AnimationFilter filter;
+ final long length;
- ChildHierarchyChangeEvent(View view, int type) {
+ AnimationEvent(View view, int type) {
eventStartTime = AnimationUtils.currentAnimationTimeMillis();
changingView = view;
animationType = type;
+ filter = FILTERS[type];
+ length = LENGTHS[type];
+ }
+
+ /**
+ * Combines the length of several animation events into a single value.
+ *
+ * @param events The events of the lengths to combine.
+ * @return The combined length. This is just the maximum of all length.
+ */
+ static long combineLength(ArrayList<AnimationEvent> events) {
+ long length = 0;
+ int size = events.size();
+ for (int i = 0; i < size; i++) {
+ length = Math.max(length, events.get(i).length);
+ }
+ return length;
}
}
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 9bde673..5e4d496 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -39,6 +39,10 @@
private static final int MAX_ITEMS_IN_BOTTOM_STACK = 3;
private static final int MAX_ITEMS_IN_TOP_STACK = 3;
+ /** When a child is activated, the other cards' alpha fade to this value. */
+ private static final float ACTIVATED_INVERSE_ALPHA = 0.9f;
+ private static final float DIMMED_SCALE = 0.95f;
+
private int mPaddingBetweenElements;
private int mCollapsedSize;
private int mTopStackPeekSize;
@@ -92,7 +96,7 @@
}
- public void getStackScrollState(StackScrollState resultState) {
+ public void getStackScrollState(AmbientState ambientState, StackScrollState resultState) {
// The state of the local variables are saved in an algorithmState to easily subdivide it
// into multiple phases.
StackScrollAlgorithmState algorithmState = mTempAlgorithmState;
@@ -106,7 +110,7 @@
algorithmState.scrolledPixelsTop = 0;
algorithmState.itemsInBottomStack = 0.0f;
algorithmState.partialInBottom = 0.0f;
- algorithmState.scrollY = resultState.getScrollY() + mCollapsedSize;
+ algorithmState.scrollY = ambientState.getScrollY() + mCollapsedSize;
updateVisibleChildren(resultState, algorithmState);
@@ -118,6 +122,57 @@
// Phase 3:
updateZValuesForState(resultState, algorithmState);
+
+ handleDraggedViews(ambientState, resultState, algorithmState);
+ updateDimmedActivated(ambientState, resultState, algorithmState);
+ }
+
+ /**
+ * Updates the dimmed and activated states of the children.
+ */
+ private void updateDimmedActivated(AmbientState ambientState, StackScrollState resultState,
+ StackScrollAlgorithmState algorithmState) {
+ boolean dimmed = ambientState.isDimmed();
+ View activatedChild = ambientState.getActivatedChild();
+ int childCount = algorithmState.visibleChildren.size();
+ for (int i = 0; i < childCount; i++) {
+ View child = algorithmState.visibleChildren.get(i);
+ StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
+ childViewState.dimmed = dimmed;
+ childViewState.scale = !dimmed || activatedChild == child
+ ? 1.0f
+ : DIMMED_SCALE;
+ if (dimmed && activatedChild != null && child != activatedChild) {
+ childViewState.alpha *= ACTIVATED_INVERSE_ALPHA;
+ }
+ }
+ }
+
+ /**
+ * Handle the special state when views are being dragged
+ */
+ private void handleDraggedViews(AmbientState ambientState, StackScrollState resultState,
+ StackScrollAlgorithmState algorithmState) {
+ ArrayList<View> draggedViews = ambientState.getDraggedViews();
+ for (View draggedView : draggedViews) {
+ int childIndex = algorithmState.visibleChildren.indexOf(draggedView);
+ if (childIndex >= 0 && childIndex < algorithmState.visibleChildren.size() - 1) {
+ View nextChild = algorithmState.visibleChildren.get(childIndex + 1);
+ if (!draggedViews.contains(nextChild)) {
+ // only if the view is not dragged itself we modify its state to be fully
+ // visible
+ StackScrollState.ViewState viewState = resultState.getViewStateForView(
+ nextChild);
+ // The child below the dragged one must be fully visible
+ viewState.alpha = 1;
+ }
+
+ // Lets set the alpha to the one it currently has, as its currently being dragged
+ StackScrollState.ViewState viewState = resultState.getViewStateForView(draggedView);
+ // The dragged child should keep the set alpha
+ viewState.alpha = draggedView.getAlpha();
+ }
+ }
}
/**
@@ -192,7 +247,7 @@
clampYTranslation(childViewState, childHeight);
// check if we are overlapping with the bottom stack
if (childViewState.yTranslation + childHeight + mPaddingBetweenElements
- >= bottomStackStart && !mIsExpansionChanging) {
+ >= bottomStackStart && !mIsExpansionChanging && i != 0) {
// TODO: handle overlapping sizes with end stack better
// we just collapse this element
childViewState.height = mCollapsedSize;
@@ -275,7 +330,7 @@
private int getMaxAllowedChildHeight(View child) {
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- return row.getMaximumAllowedExpandHeight();
+ return row.getIntrinsicHeight();
} else if (child instanceof ExpandableView) {
ExpandableView expandableView = (ExpandableView) child;
return expandableView.getActualHeight();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 8c75adc..8fc26d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -37,19 +37,10 @@
private final ViewGroup mHostView;
private Map<ExpandableView, ViewState> mStateMap;
- private int mScrollY;
private final Rect mClipRect = new Rect();
private int mBackgroundRoundedRectCornerRadius;
private final Outline mChildOutline = new Outline();
- public int getScrollY() {
- return mScrollY;
- }
-
- public void setScrollY(int scrollY) {
- this.mScrollY = scrollY;
- }
-
public StackScrollState(ViewGroup hostView) {
mHostView = hostView;
mStateMap = new HashMap<ExpandableView, ViewState>();
@@ -71,7 +62,7 @@
mStateMap.put(child, viewState);
}
// initialize with the default values of the view
- viewState.height = child.getActualHeight();
+ viewState.height = child.getIntrinsicHeight();
viewState.gone = child.getVisibility() == View.GONE;
viewState.alpha = 1;
}
@@ -93,6 +84,7 @@
int numChildren = mHostView.getChildCount();
float previousNotificationEnd = 0;
float previousNotificationStart = 0;
+ boolean previousNotificationIsSwiped = false;
for (int i = 0; i < numChildren; i++) {
ExpandableView child = (ExpandableView) mHostView.getChildAt(i);
ViewState state = mStateMap.get(child);
@@ -105,10 +97,12 @@
float alpha = child.getAlpha();
float yTranslation = child.getTranslationY();
float zTranslation = child.getTranslationZ();
+ float scale = child.getScaleX();
int height = child.getActualHeight();
float newAlpha = state.alpha;
float newYTranslation = state.yTranslation;
float newZTranslation = state.zTranslation;
+ float newScale = state.scale;
int newHeight = state.height;
boolean becomesInvisible = newAlpha == 0.0f;
if (alpha != newAlpha) {
@@ -146,19 +140,36 @@
child.setTranslationZ(newZTranslation);
}
+ // apply scale
+ if (scale != newScale) {
+ child.setScaleX(newScale);
+ child.setScaleY(newScale);
+ }
+
// apply height
if (height != newHeight) {
- child.setActualHeight(newHeight);
+ child.setActualHeight(newHeight, false /* notifyListeners */);
}
+ // apply dimming
+ child.setDimmed(state.dimmed, false /* animate */);
+
// apply clipping and shadow
float newNotificationEnd = newYTranslation + newHeight;
+
+ // When the previous notification is swiped, we don't clip the content to the
+ // bottom of it.
+ float clipHeight = previousNotificationIsSwiped
+ ? newHeight
+ : newNotificationEnd - (previousNotificationEnd);
+
updateChildClippingAndBackground(child, newHeight,
- newNotificationEnd - (previousNotificationEnd),
+ clipHeight,
(int) (newHeight - (previousNotificationStart - newYTranslation)));
- previousNotificationStart = newYTranslation;
+ previousNotificationStart = newYTranslation + child.getClipTopAmount();
previousNotificationEnd = newNotificationEnd;
+ previousNotificationIsSwiped = child.getTranslationX() != 0;
}
}
}
@@ -219,6 +230,8 @@
float zTranslation;
int height;
boolean gone;
+ float scale;
+ boolean dimmed;
/**
* The location this view is currently rendered at.
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 24daa4f..ca383aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -17,142 +17,518 @@
package com.android.systemui.statusbar.stack;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+
+import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableView;
import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Stack;
/**
* An stack state animator which handles animations to new StackScrollStates
*/
public class StackStateAnimator {
- private static final int ANIMATION_DURATION = 360;
+ public static final int ANIMATION_DURATION_STANDARD = 360;
+ public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220;
+
+ private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
+ private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
+ private static final int TAG_ANIMATOR_SCALE = R.id.scale_animator_tag;
+ private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag;
+ private static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag;
+ private static final int TAG_ANIMATOR_TOP_INSET = R.id.top_inset_animator_tag;
+ private static final int TAG_END_TRANSLATION_Y = R.id.translation_y_animator_end_value_tag;
+ private static final int TAG_END_TRANSLATION_Z = R.id.translation_z_animator_end_value_tag;
+ private static final int TAG_END_SCALE = R.id.scale_animator_end_value_tag;
+ private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag;
+ private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag;
+ private static final int TAG_END_TOP_INSET = R.id.top_inset_animator_end_value_tag;
+ private static final int TAG_START_TRANSLATION_Y = R.id.translation_y_animator_start_value_tag;
+ private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag;
+ private static final int TAG_START_SCALE = R.id.scale_animator_start_value_tag;
+ private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag;
+ private static final int TAG_START_HEIGHT = R.id.height_animator_start_value_tag;
+ private static final int TAG_START_TOP_INSET = R.id.top_inset_animator_start_value_tag;
private final Interpolator mFastOutSlowInInterpolator;
public NotificationStackScrollLayout mHostLayout;
- private boolean mAnimationIsRunning;
- private ArrayList<NotificationStackScrollLayout.ChildHierarchyChangeEvent> mHandledEvents =
+ private ArrayList<NotificationStackScrollLayout.AnimationEvent> mHandledEvents =
new ArrayList<>();
+ private ArrayList<NotificationStackScrollLayout.AnimationEvent> mNewEvents =
+ new ArrayList<>();
+ private Set<Animator> mAnimatorSet = new HashSet<Animator>();
+ private Stack<AnimatorListenerAdapter> mAnimationListenerPool
+ = new Stack<AnimatorListenerAdapter>();
+ private AnimationFilter mAnimationFilter = new AnimationFilter();
+ private long mCurrentLength;
public StackStateAnimator(NotificationStackScrollLayout hostLayout) {
mHostLayout = hostLayout;
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(hostLayout.getContext(),
- android.R.interpolator.fast_out_slow_in);
+ android.R.interpolator.fast_out_slow_in);
}
public boolean isRunning() {
- return mAnimationIsRunning;
+ return !mAnimatorSet.isEmpty();
}
public void startAnimationForEvents(
- ArrayList<NotificationStackScrollLayout.ChildHierarchyChangeEvent> mAnimationEvents,
+ ArrayList<NotificationStackScrollLayout.AnimationEvent> mAnimationEvents,
StackScrollState finalState) {
- int numEvents = mAnimationEvents.size();
- if (numEvents == 0) {
- // No events, so we don't perform any animation
- return;
- }
- long lastEventStartTime = mAnimationEvents.get(numEvents - 1).eventStartTime;
- long eventEnd = lastEventStartTime + ANIMATION_DURATION;
- long currentTime = AnimationUtils.currentAnimationTimeMillis();
- long newDuration = eventEnd - currentTime;
- if (newDuration <= 0) {
- // last event is long before this, so we don't do anything
- return;
- }
- initializeAddedViewStates(mAnimationEvents, finalState);
+
+ processAnimationEvents(mAnimationEvents, finalState);
+
int childCount = mHostLayout.getChildCount();
- boolean isFirstAnimatingView = true;
+ mAnimationFilter.applyCombination(mNewEvents);
+ mCurrentLength = NotificationStackScrollLayout.AnimationEvent.combineLength(mNewEvents);
for (int i = 0; i < childCount; i++) {
final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
StackScrollState.ViewState viewState = finalState.getViewStateForView(child);
if (viewState == null) {
continue;
}
- int childVisibility = child.getVisibility();
- boolean wasVisible = childVisibility == View.VISIBLE;
- final float alpha = viewState.alpha;
- if (!wasVisible && alpha != 0 && !viewState.gone) {
- child.setVisibility(View.VISIBLE);
- }
- startPropertyAnimation(newDuration, isFirstAnimatingView, child, viewState, alpha);
+ startAnimations(child, viewState);
- // TODO: animate clipBounds
child.setClipBounds(null);
- int currentHeigth = child.getActualHeight();
- if (viewState.height != currentHeigth) {
- startHeightAnimation(newDuration, child, viewState, currentHeigth);
- }
- isFirstAnimatingView = false;
}
- mAnimationIsRunning = true;
- }
-
- private void startPropertyAnimation(long newDuration, final boolean hasFinishAction,
- final ExpandableView child, StackScrollState.ViewState viewState, final float alpha) {
- child.animate().setInterpolator(mFastOutSlowInInterpolator)
- .alpha(alpha)
- .translationY(viewState.yTranslation)
- .translationZ(viewState.zTranslation)
- .setDuration(newDuration)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- mAnimationIsRunning = false;
- if (hasFinishAction) {
- mHandledEvents.clear();
- mHostLayout.onChildAnimationFinished();
- }
- if (alpha == 0) {
- child.setVisibility(View.INVISIBLE);
- }
- }
- });
- }
-
- private void startHeightAnimation(long newDuration, final ExpandableView child,
- StackScrollState.ViewState viewState, int currentHeigth) {
- ValueAnimator heightAnimator = ValueAnimator.ofInt(currentHeigth, viewState.height);
- heightAnimator.setInterpolator(mFastOutSlowInInterpolator);
- heightAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- child.setActualHeight((int) animation.getAnimatedValue());
- }
- });
- heightAnimator.setDuration(newDuration);
- heightAnimator.start();
+ if (!isRunning()) {
+ // no child has preformed any animation, lets finish
+ onAnimationFinished();
+ }
}
/**
- * Initialize the viewStates for the added children
+ * Start an animation to the given viewState
+ */
+ private void startAnimations(final ExpandableView child, StackScrollState.ViewState viewState) {
+ int childVisibility = child.getVisibility();
+ boolean wasVisible = childVisibility == View.VISIBLE;
+ final float alpha = viewState.alpha;
+ if (!wasVisible && alpha != 0 && !viewState.gone) {
+ child.setVisibility(View.VISIBLE);
+ }
+ // start translationY animation
+ if (child.getTranslationY() != viewState.yTranslation) {
+ startYTranslationAnimation(child, viewState);
+ }
+ // start translationZ animation
+ if (child.getTranslationZ() != viewState.zTranslation) {
+ startZTranslationAnimation(child, viewState);
+ }
+ // start scale animation
+ if (child.getScaleX() != viewState.scale) {
+ startScaleAnimation(child, viewState);
+ }
+ // start alpha animation
+ if (alpha != child.getAlpha()) {
+ startAlphaAnimation(child, viewState);
+ }
+ // start height animation
+ if (viewState.height != child.getActualHeight()) {
+ startHeightAnimation(child, viewState);
+ }
+ // start dimmed animation
+ child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed);
+ }
+
+ private void startHeightAnimation(final ExpandableView child,
+ StackScrollState.ViewState viewState) {
+ Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
+ Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
+ int newEndValue = viewState.height;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_HEIGHT);
+ if (!mAnimationFilter.animateHeight) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ int relativeDiff = newEndValue - previousEndValue;
+ int newStartValue = previousStartValue + relativeDiff;
+ values[0].setIntValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_HEIGHT, newStartValue);
+ child.setTag(TAG_END_HEIGHT, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setActualHeight(newEndValue, false);
+ return;
+ }
+ }
+
+ ValueAnimator animator = ValueAnimator.ofInt(child.getActualHeight(), newEndValue);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ child.setActualHeight((int) animation.getAnimatedValue(),
+ false /* notifyListeners */);
+ }
+ });
+ animator.setInterpolator(mFastOutSlowInInterpolator);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+ animator.setDuration(newDuration);
+ animator.addListener(getGlobalAnimationFinishedListener());
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_HEIGHT, null);
+ child.setTag(TAG_START_HEIGHT, null);
+ child.setTag(TAG_END_HEIGHT, null);
+ }
+ });
+ startInstantly(animator);
+ child.setTag(TAG_ANIMATOR_HEIGHT, animator);
+ child.setTag(TAG_START_HEIGHT, child.getActualHeight());
+ child.setTag(TAG_END_HEIGHT, newEndValue);
+ }
+
+ private void startAlphaAnimation(final ExpandableView child,
+ final StackScrollState.ViewState viewState) {
+ Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
+ Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
+ final float newEndValue = viewState.alpha;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_ALPHA);
+ if (!mAnimationFilter.animateAlpha) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_ALPHA, newStartValue);
+ child.setTag(TAG_END_ALPHA, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setAlpha(newEndValue);
+ if (newEndValue == 0) {
+ child.setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA,
+ child.getAlpha(), newEndValue);
+ animator.setInterpolator(mFastOutSlowInInterpolator);
+ // Handle layer type
+ final int currentLayerType = child.getLayerType();
+ child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ animator.addListener(new AnimatorListenerAdapter() {
+ public boolean mWasCancelled;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setLayerType(currentLayerType, null);
+ if (newEndValue == 0 && !mWasCancelled) {
+ child.setVisibility(View.INVISIBLE);
+ }
+ child.setTag(TAG_ANIMATOR_ALPHA, null);
+ child.setTag(TAG_START_ALPHA, null);
+ child.setTag(TAG_END_ALPHA, null);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mWasCancelled = true;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mWasCancelled = false;
+ }
+ });
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+ animator.setDuration(newDuration);
+ animator.addListener(getGlobalAnimationFinishedListener());
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+
+ }
+ });
+ startInstantly(animator);
+ child.setTag(TAG_ANIMATOR_ALPHA, animator);
+ child.setTag(TAG_START_ALPHA, child.getAlpha());
+ child.setTag(TAG_END_ALPHA, newEndValue);
+ }
+
+ private void startZTranslationAnimation(final ExpandableView child,
+ final StackScrollState.ViewState viewState) {
+ Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z);
+ Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
+ float newEndValue = viewState.zTranslation;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Z);
+ if (!mAnimationFilter.animateZ) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_TRANSLATION_Z, newStartValue);
+ child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setTranslationZ(newEndValue);
+ }
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Z,
+ child.getTranslationZ(), newEndValue);
+ animator.setInterpolator(mFastOutSlowInInterpolator);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+ animator.setDuration(newDuration);
+ animator.addListener(getGlobalAnimationFinishedListener());
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Z, null);
+ child.setTag(TAG_START_TRANSLATION_Z, null);
+ child.setTag(TAG_END_TRANSLATION_Z, null);
+ }
+ });
+ startInstantly(animator);
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Z, animator);
+ child.setTag(TAG_START_TRANSLATION_Z, child.getTranslationZ());
+ child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
+ }
+
+ private void startYTranslationAnimation(final ExpandableView child,
+ StackScrollState.ViewState viewState) {
+ Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y);
+ Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);
+ float newEndValue = viewState.yTranslation;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y);
+ if (!mAnimationFilter.animateY) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_TRANSLATION_Y, newStartValue);
+ child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setTranslationY(newEndValue);
+ return;
+ }
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y,
+ child.getTranslationY(), newEndValue);
+ animator.setInterpolator(mFastOutSlowInInterpolator);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+ animator.setDuration(newDuration);
+ animator.addListener(getGlobalAnimationFinishedListener());
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null);
+ child.setTag(TAG_START_TRANSLATION_Y, null);
+ child.setTag(TAG_END_TRANSLATION_Y, null);
+ }
+ });
+ startInstantly(animator);
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Y, animator);
+ child.setTag(TAG_START_TRANSLATION_Y, child.getTranslationY());
+ child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
+ }
+
+ private void startScaleAnimation(final ExpandableView child,
+ StackScrollState.ViewState viewState) {
+ Float previousStartValue = getChildTag(child, TAG_START_SCALE);
+ Float previousEndValue = getChildTag(child, TAG_END_SCALE);
+ float newEndValue = viewState.scale;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SCALE);
+ if (!mAnimationFilter.animateScale) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ values[1].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_SCALE, newStartValue);
+ child.setTag(TAG_END_SCALE, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setScaleX(newEndValue);
+ child.setScaleY(newEndValue);
+ }
+ }
+
+ PropertyValuesHolder holderX =
+ PropertyValuesHolder.ofFloat(View.SCALE_X, child.getScaleX(), newEndValue);
+ PropertyValuesHolder holderY =
+ PropertyValuesHolder.ofFloat(View.SCALE_Y, child.getScaleY(), newEndValue);
+ ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(child, holderX, holderY);
+ animator.setInterpolator(mFastOutSlowInInterpolator);
+ long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+ animator.setDuration(newDuration);
+ animator.addListener(getGlobalAnimationFinishedListener());
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_SCALE, null);
+ child.setTag(TAG_START_SCALE, null);
+ child.setTag(TAG_END_SCALE, null);
+ }
+ });
+ startInstantly(animator);
+ child.setTag(TAG_ANIMATOR_SCALE, animator);
+ child.setTag(TAG_START_SCALE, child.getScaleX());
+ child.setTag(TAG_END_SCALE, newEndValue);
+ }
+
+ /**
+ * Start an animator instantly instead of waiting on the next synchronization frame
+ */
+ private void startInstantly(ValueAnimator animator) {
+ animator.start();
+ animator.setCurrentPlayTime(0);
+ }
+
+ /**
+ * @return an adapter which ensures that onAnimationFinished is called once no animation is
+ * running anymore
+ */
+ private AnimatorListenerAdapter getGlobalAnimationFinishedListener() {
+ if (!mAnimationListenerPool.empty()) {
+ return mAnimationListenerPool.pop();
+ }
+
+ // We need to create a new one, no reusable ones found
+ return new AnimatorListenerAdapter() {
+ private boolean mWasCancelled;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimatorSet.remove(animation);
+ if (mAnimatorSet.isEmpty() && !mWasCancelled) {
+ onAnimationFinished();
+ }
+ mAnimationListenerPool.push(this);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mWasCancelled = true;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mAnimatorSet.add(animation);
+ mWasCancelled = false;
+ }
+ };
+ }
+
+ private <T> T getChildTag(View child, int tag) {
+ return (T) child.getTag(tag);
+ }
+
+ /**
+ * Cancel the previous animator and get the duration of the new animation.
*
- * @param animationEvents the animation events who contain the added children
+ * @param previousAnimator the animator which was running before
+ * @return the new duration
+ */
+ private long cancelAnimatorAndGetNewDuration(ValueAnimator previousAnimator) {
+ long newDuration = mCurrentLength;
+ if (previousAnimator != null) {
+ // We take either the desired length of the new animation or the remaining time of
+ // the previous animator, whichever is longer.
+ newDuration = Math.max(previousAnimator.getDuration()
+ - previousAnimator.getCurrentPlayTime(), newDuration);
+ previousAnimator.cancel();
+ }
+ return newDuration;
+ }
+
+ private void onAnimationFinished() {
+ mHandledEvents.clear();
+ mNewEvents.clear();
+ mHostLayout.onChildAnimationFinished();
+ }
+
+ /**
+ * Process the animationEvents for a new animation
+ *
+ * @param animationEvents the animation events for the animation to perform
* @param finalState the final state to animate to
*/
- private void initializeAddedViewStates(
- ArrayList<NotificationStackScrollLayout.ChildHierarchyChangeEvent> animationEvents,
+ private void processAnimationEvents(
+ ArrayList<NotificationStackScrollLayout.AnimationEvent> animationEvents,
StackScrollState finalState) {
- for (NotificationStackScrollLayout.ChildHierarchyChangeEvent event: animationEvents) {
+ mNewEvents.clear();
+ for (NotificationStackScrollLayout.AnimationEvent event: animationEvents) {
View changingView = event.changingView;
- if (event.animationType == NotificationStackScrollLayout.ChildHierarchyChangeEvent
- .ANIMATION_TYPE_ADD && !mHandledEvents.contains(event)) {
+ if (!mHandledEvents.contains(event)) {
+ if (event.animationType == NotificationStackScrollLayout.AnimationEvent
+ .ANIMATION_TYPE_ADD) {
- // This item is added, initialize it's properties.
- StackScrollState.ViewState viewState = finalState.getViewStateForView(changingView);
- if (viewState == null) {
- // The position for this child was never generated, let's continue.
- continue;
+ // This item is added, initialize it's properties.
+ StackScrollState.ViewState viewState = finalState
+ .getViewStateForView(changingView);
+ if (viewState == null) {
+ // The position for this child was never generated, let's continue.
+ continue;
+ }
+ changingView.setAlpha(0);
+ changingView.setTranslationY(viewState.yTranslation);
+ changingView.setTranslationZ(viewState.zTranslation);
}
- changingView.setAlpha(0);
- changingView.setTranslationY(viewState.yTranslation);
- changingView.setTranslationZ(viewState.zTranslation);
mHandledEvents.add(event);
+ mNewEvents.add(event);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index d615542..9006c9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -78,7 +78,8 @@
}
@Override
- public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
+ public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) {
}
@Override
@@ -120,11 +121,6 @@
}
@Override
- protected int getExpandedViewMaxHeight() {
- return 0;
- }
-
- @Override
protected boolean shouldDisableNavbarGestures() {
return true;
}
@@ -154,4 +150,11 @@
protected void refreshLayout(int layoutDirection) {
}
+ @Override
+ public void onActivated(View view) {
+ }
+
+ @Override
+ public void onActivationReset(View view) {
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 0550dd4..b1fea03 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -3560,27 +3560,19 @@
swipeDismiss.setOnDismissedListener(new SwipeDismissLayout.OnDismissedListener() {
@Override
public void onDismissed(SwipeDismissLayout layout) {
- Callback cb = getCallback();
- if (cb != null) {
- try {
- cb.onWindowDismissed();
- } catch (AbstractMethodError e) {
- Log.e(TAG, "onWindowDismissed not implemented in " +
- cb.getClass().getSimpleName(), e);
- }
- }
+ dispatchOnWindowDismissed();
}
});
swipeDismiss.setOnSwipeProgressChangedListener(
new SwipeDismissLayout.OnSwipeProgressChangedListener() {
+ private static final float ALPHA_DECREASE = 0.5f;
private boolean mIsTranslucent = false;
-
@Override
public void onSwipeProgressChanged(
SwipeDismissLayout layout, float progress, float translate) {
WindowManager.LayoutParams newParams = getAttributes();
newParams.x = (int) translate;
- newParams.alpha = 1 - progress;
+ newParams.alpha = 1 - (progress * ALPHA_DECREASE);
setAttributes(newParams);
int flags = 0;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 8bc669a..ae6aeee 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -667,7 +667,8 @@
private void interceptPowerKeyDown(boolean handled) {
mPowerKeyHandled = handled;
if (!handled) {
- mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
+ mHandler.postDelayed(mPowerLongPress,
+ ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
}
}
@@ -706,9 +707,9 @@
if (mKeyguardDelegate.isShowing()) {
// Double the time it takes to take a screenshot from the keyguard
return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *
- ViewConfiguration.getGlobalActionKeyTimeout());
+ ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
}
- return ViewConfiguration.getGlobalActionKeyTimeout();
+ return ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout();
}
private void cancelPendingScreenshotChordAction() {
@@ -990,9 +991,9 @@
// Match current screen state.
if (mPowerManager.isInteractive()) {
- screenTurningOn(null);
+ wakingUp(null);
} else {
- screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
+ goingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
}
}
@@ -4314,7 +4315,7 @@
}
@Override
- public void screenTurnedOff(int why) {
+ public void goingToSleep(int why) {
EventLog.writeEvent(70000, 0);
synchronized (mLock) {
mScreenOnEarly = false;
@@ -4330,7 +4331,7 @@
}
@Override
- public void screenTurningOn(final ScreenOnListener screenOnListener) {
+ public void wakingUp(final ScreenOnListener screenOnListener) {
EventLog.writeEvent(70000, 1);
if (false) {
RuntimeException here = new RuntimeException("here");
@@ -4776,7 +4777,11 @@
mHandler.post(new Runnable() {
@Override public void run() {
if (mBootMsgDialog == null) {
- mBootMsgDialog = new ProgressDialog(mContext) {
+ int theme = mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WATCH) ?
+ com.android.internal.R.style.Theme_Micro_Dialog_Alert : 0;
+
+ mBootMsgDialog = new ProgressDialog(mContext, theme) {
// This dialog will consume all events coming in to
// it, to avoid it trying to do things too early in boot.
@Override public boolean dispatchKeyEvent(KeyEvent event) {
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index dce4f581..a62d1fd 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -63,6 +63,25 @@
static Method registerNativeAllocation;
static Method registerNativeFree;
+ /*
+ * Context creation flag which specifies a normal context.
+ */
+ public static final long CREATE_FLAG_NONE = 0x0000;
+
+ /*
+ * Context creation flag which specifies a context optimized for low
+ * latency over peak performance. This is a hint and may have no effect
+ * on some implementations.
+ */
+ public static final long CREATE_FLAG_LOW_LATENCY = 0x0001;
+
+ /*
+ * Context creation flag which specifies a context optimized for long
+ * battery life over peak performance. This is a hint and may have no effect
+ * on some implementations.
+ */
+ public static final long CREATE_FLAG_LOW_POWER = 0x0002;
+
static {
sInitialized = false;
if (!SystemProperties.getBoolean("config.disable_renderscript", false)) {
@@ -1145,7 +1164,7 @@
* @hide
*/
public static RenderScript create(Context ctx, int sdkVersion) {
- return create(ctx, sdkVersion, ContextType.NORMAL);
+ return create(ctx, sdkVersion, ContextType.NORMAL, CREATE_FLAG_NONE);
}
/**
@@ -1155,7 +1174,7 @@
* @param ctx The context.
* @return RenderScript
*/
- public static RenderScript create(Context ctx, int sdkVersion, ContextType ct) {
+ public static RenderScript create(Context ctx, int sdkVersion, ContextType ct, long flags) {
if (!sInitialized) {
Log.e(LOG_TAG, "RenderScript.create() called when disabled; someone is likely to crash");
return null;
@@ -1194,7 +1213,21 @@
*/
public static RenderScript create(Context ctx, ContextType ct) {
int v = ctx.getApplicationInfo().targetSdkVersion;
- return create(ctx, v, ct);
+ return create(ctx, v, ct, CREATE_FLAG_NONE);
+ }
+
+ /**
+ * Create a RenderScript context.
+ *
+ *
+ * @param ctx The context.
+ * @param ct The type of context to be created.
+ * @param flags The OR of the CREATE_FLAG_* options desired
+ * @return RenderScript
+ */
+ public static RenderScript create(Context ctx, ContextType ct, long flags) {
+ int v = ctx.getApplicationInfo().targetSdkVersion;
+ return create(ctx, v, ct, flags);
}
/**
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
index 77d5076..2fa23c9 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
@@ -125,8 +125,10 @@
// Register for the boot completed broadcast, so we can send the
// ENABLE broacasts. If we try to send them now, they time out,
// because the system isn't ready to handle them yet.
+ IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
- new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
+ filter, null, null);
// Register for configuration changes so we can update the names
// of the widgets when the locale changes.
@@ -135,7 +137,6 @@
// Register for broadcasts about package install, etc., so we can
// update the provider list.
- IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 0d6f548..e2a8ca2 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -212,6 +212,7 @@
filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
registerForAirplaneMode(filter);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiver(mReceiver, filter);
loadStoredNameAndAddress();
if (isBluetoothPersistedStateOn()) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 45cdb65..ea03eb7 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -74,7 +74,7 @@
import android.net.NetworkUtils;
import android.net.Proxy;
import android.net.ProxyDataTracker;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.SamplingDataTracker;
import android.net.Uri;
@@ -406,12 +406,12 @@
private ArrayList mInetLog;
// track the current default http proxy - tell the world if we get a new one (real change)
- private ProxyProperties mDefaultProxy = null;
+ private ProxyInfo mDefaultProxy = null;
private Object mProxyLock = new Object();
private boolean mDefaultProxyDisabled = false;
// track the global proxy.
- private ProxyProperties mGlobalProxy = null;
+ private ProxyInfo mGlobalProxy = null;
private PacManager mPacManager = null;
@@ -3192,7 +3192,7 @@
break;
}
case EVENT_PROXY_HAS_CHANGED: {
- handleApplyDefaultProxy((ProxyProperties)msg.obj);
+ handleApplyDefaultProxy((ProxyInfo)msg.obj);
break;
}
}
@@ -3410,19 +3410,19 @@
return;
}
- public ProxyProperties getProxy() {
+ public ProxyInfo getProxy() {
// this information is already available as a world read/writable jvm property
// so this API change wouldn't have a benifit. It also breaks the passing
// of proxy info to all the JVMs.
// enforceAccessPermission();
synchronized (mProxyLock) {
- ProxyProperties ret = mGlobalProxy;
+ ProxyInfo ret = mGlobalProxy;
if ((ret == null) && !mDefaultProxyDisabled) ret = mDefaultProxy;
return ret;
}
}
- public void setGlobalProxy(ProxyProperties proxyProperties) {
+ public void setGlobalProxy(ProxyInfo proxyProperties) {
enforceConnectivityInternalPermission();
synchronized (mProxyLock) {
@@ -3435,18 +3435,18 @@
String exclList = "";
String pacFileUrl = "";
if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) ||
- !TextUtils.isEmpty(proxyProperties.getPacFileUrl()))) {
+ (proxyProperties.getPacFileUrl() != null))) {
if (!proxyProperties.isValid()) {
if (DBG)
log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
return;
}
- mGlobalProxy = new ProxyProperties(proxyProperties);
+ mGlobalProxy = new ProxyInfo(proxyProperties);
host = mGlobalProxy.getHost();
port = mGlobalProxy.getPort();
- exclList = mGlobalProxy.getExclusionList();
+ exclList = mGlobalProxy.getExclusionListAsString();
if (proxyProperties.getPacFileUrl() != null) {
- pacFileUrl = proxyProperties.getPacFileUrl();
+ pacFileUrl = proxyProperties.getPacFileUrl().toString();
}
} else {
mGlobalProxy = null;
@@ -3478,11 +3478,11 @@
Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC);
if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
- ProxyProperties proxyProperties;
+ ProxyInfo proxyProperties;
if (!TextUtils.isEmpty(pacFileUrl)) {
- proxyProperties = new ProxyProperties(pacFileUrl);
+ proxyProperties = new ProxyInfo(pacFileUrl);
} else {
- proxyProperties = new ProxyProperties(host, port, exclList);
+ proxyProperties = new ProxyInfo(host, port, exclList);
}
if (!proxyProperties.isValid()) {
if (DBG) log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
@@ -3495,7 +3495,7 @@
}
}
- public ProxyProperties getGlobalProxy() {
+ public ProxyInfo getGlobalProxy() {
// this information is already available as a world read/writable jvm property
// so this API change wouldn't have a benifit. It also breaks the passing
// of proxy info to all the JVMs.
@@ -3505,9 +3505,9 @@
}
}
- private void handleApplyDefaultProxy(ProxyProperties proxy) {
+ private void handleApplyDefaultProxy(ProxyInfo proxy) {
if (proxy != null && TextUtils.isEmpty(proxy.getHost())
- && TextUtils.isEmpty(proxy.getPacFileUrl())) {
+ && (proxy.getPacFileUrl() == null)) {
proxy = null;
}
synchronized (mProxyLock) {
@@ -3544,13 +3544,13 @@
return;
}
}
- ProxyProperties p = new ProxyProperties(data[0], proxyPort, "");
+ ProxyInfo p = new ProxyInfo(data[0], proxyPort, "");
setGlobalProxy(p);
}
}
- private void sendProxyBroadcast(ProxyProperties proxy) {
- if (proxy == null) proxy = new ProxyProperties("", 0, "");
+ private void sendProxyBroadcast(ProxyInfo proxy) {
+ if (proxy == null) proxy = new ProxyInfo("", 0, "");
if (mPacManager.setCurrentProxyScriptUrl(proxy)) return;
if (DBG) log("sending Proxy Broadcast for " + proxy);
Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 5083d44..6fab37c2 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -65,6 +65,8 @@
27501 notification_panel_hidden
# when notifications are newly displayed on screen, or disappear from screen
27510 notification_visibility_changed (newlyVisibleKeys|3),(noLongerVisibleKeys|3)
+# when a notification has been clicked
+27520 notification_clicked (key|3)
# ---------------------------
# Watchdog.java
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 6fc3e77..10315a7 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -1532,14 +1532,17 @@
}
mImeWindowVis = vis;
mBackDisposition = backDisposition;
- if (mStatusBar != null) {
- mStatusBar.setImeWindowStatus(token, vis, backDisposition);
- }
final boolean iconVisibility = ((vis & (InputMethodService.IME_ACTIVE)) != 0)
&& (mWindowManagerService.isHardKeyboardAvailable()
|| (vis & (InputMethodService.IME_VISIBLE)) != 0);
+ final boolean needsToShowImeSwitcher = iconVisibility
+ && needsToShowImeSwitchOngoingNotification();
+ if (mStatusBar != null) {
+ mStatusBar.setImeWindowStatus(token, vis, backDisposition,
+ needsToShowImeSwitcher);
+ }
final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
- if (imi != null && iconVisibility && needsToShowImeSwitchOngoingNotification()) {
+ if (imi != null && needsToShowImeSwitcher) {
// Used to load label
final CharSequence title = mRes.getText(
com.android.internal.R.string.select_input_method);
@@ -1548,7 +1551,8 @@
mImeSwitcherNotification.setLatestEventInfo(
mContext, title, summary, mImeSwitchPendingIntent);
- if (mNotificationManager != null) {
+ if ((mNotificationManager != null)
+ && !mWindowManagerService.hasNavigationBar()) {
if (DEBUG) {
Slog.d(TAG, "--- show notification: label = " + summary);
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 7ec9b82..d5f045e 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -201,8 +201,8 @@
public static final String[] CRYPTO_TYPES
= { "password", "default", "pattern", "pin" };
- private Context mContext;
- private NativeDaemonConnector mConnector;
+ private final Context mContext;
+ private final NativeDaemonConnector mConnector;
private final Object mVolumesLock = new Object();
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 8a30e50..4f0c9b5 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -20,19 +20,24 @@
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
+import android.net.INetworkScoreCache;
import android.net.INetworkScoreService;
-import android.net.NetworkKey;
import android.net.NetworkScorerAppManager;
-import android.net.RssiCurve;
import android.net.ScoredNetwork;
+import android.os.RemoteException;
import android.text.TextUtils;
+import android.util.Log;
import com.android.internal.R;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Backing service for {@link android.net.NetworkScoreManager}.
@@ -46,12 +51,11 @@
private final Context mContext;
- // TODO: Delete this temporary class once we have a real place for scores.
- private final Map<NetworkKey, RssiCurve> mScoredNetworks;
+ private final Map<Integer, INetworkScoreCache> mScoreCaches;
public NetworkScoreService(Context context) {
mContext = context;
- mScoredNetworks = new HashMap<>();
+ mScoreCaches = new HashMap<>();
}
/** Called when the system is ready to run third-party code but before it actually does so. */
@@ -76,10 +80,31 @@
" is not the active scorer.");
}
- // TODO: Propagate these scores down to the network subsystem layer instead of just holding
- // them in memory.
+ // Separate networks by type.
+ Map<Integer, List<ScoredNetwork>> networksByType = new HashMap<>();
for (ScoredNetwork network : networks) {
- mScoredNetworks.put(network.networkKey, network.rssiCurve);
+ List<ScoredNetwork> networkList = networksByType.get(network.networkKey.type);
+ if (networkList == null) {
+ networkList = new ArrayList<>();
+ networksByType.put(network.networkKey.type, networkList);
+ }
+ networkList.add(network);
+ }
+
+ // Pass the scores of each type down to the appropriate network scorer.
+ for (Map.Entry<Integer, List<ScoredNetwork>> entry : networksByType.entrySet()) {
+ INetworkScoreCache scoreCache = mScoreCaches.get(entry.getKey());
+ if (scoreCache != null) {
+ try {
+ scoreCache.updateScores(entry.getValue());
+ } catch (RemoteException e) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Unable to update scores of type " + entry.getKey(), e);
+ }
+ }
+ } else if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "No scorer registered for type " + entry.getKey() + ", discarding");
+ }
}
return true;
@@ -112,8 +137,29 @@
/** Clear scores. Callers are responsible for checking permissions as appropriate. */
private void clearInternal() {
- // TODO: Propagate the flush down to the network subsystem layer.
- mScoredNetworks.clear();
+ Set<INetworkScoreCache> cachesToClear = getScoreCaches();
+
+ for (INetworkScoreCache scoreCache : cachesToClear) {
+ try {
+ scoreCache.clearScores();
+ } catch (RemoteException e) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Unable to clear scores", e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
+ mContext.enforceCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS, TAG);
+ synchronized (mScoreCaches) {
+ if (mScoreCaches.containsKey(networkType)) {
+ throw new IllegalArgumentException(
+ "Score cache already registered for type " + networkType);
+ }
+ mScoreCaches.put(networkType, scoreCache);
+ }
}
@Override
@@ -125,12 +171,28 @@
return;
}
writer.println("Current scorer: " + currentScorer);
- if (mScoredNetworks.isEmpty()) {
- writer.println("No networks scored.");
- } else {
- for (Map.Entry<NetworkKey, RssiCurve> entry : mScoredNetworks.entrySet()) {
- writer.println(entry.getKey() + ": " + entry.getValue());
+
+ for (INetworkScoreCache scoreCache : getScoreCaches()) {
+ try {
+ scoreCache.asBinder().dump(fd, args);
+ } catch (RemoteException e) {
+ writer.println("Unable to dump score cache");
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Unable to dump score cache", e);
+ }
}
}
}
+
+ /**
+ * Returns a set of all score caches that are currently active.
+ *
+ * <p>May be used to perform an action on all score caches without potentially strange behavior
+ * if a new scorer is registered during that action's execution.
+ */
+ private Set<INetworkScoreCache> getScoreCaches() {
+ synchronized (mScoreCaches) {
+ return new HashSet<>(mScoreCaches.values());
+ }
+ }
}
diff --git a/services/core/java/com/android/server/RecognitionManagerService.java b/services/core/java/com/android/server/RecognitionManagerService.java
index c2e749d..60d38ae 100644
--- a/services/core/java/com/android/server/RecognitionManagerService.java
+++ b/services/core/java/com/android/server/RecognitionManagerService.java
@@ -78,8 +78,10 @@
mMonitor = new MyPackageMonitor();
mMonitor.register(context, null, UserHandle.ALL, true);
mIPm = AppGlobals.getPackageManager();
+ IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
- new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
+ filter, null, null);
}
public void systemReady() {
diff --git a/services/core/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java
index 415fcc1..50cfe48 100644
--- a/services/core/java/com/android/server/WiredAccessoryManager.java
+++ b/services/core/java/com/android/server/WiredAccessoryManager.java
@@ -97,13 +97,15 @@
mObserver = new WiredAccessoryObserver();
+ IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
context.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context ctx, Intent intent) {
bootCompleted();
}
},
- new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
+ filter, null, null);
}
private void bootCompleted() {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9eaddbd..29c781b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -95,7 +95,6 @@
import android.app.IProcessObserver;
import android.app.IServiceConnection;
import android.app.IStopUserCallback;
-import android.app.IThumbnailReceiver;
import android.app.IUiAutomationConnection;
import android.app.IUserSwitchObserver;
import android.app.Instrumentation;
@@ -137,7 +136,7 @@
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Proxy;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -703,13 +702,6 @@
String mBackupAppName = null;
BackupRecord mBackupTarget = null;
- /**
- * List of PendingThumbnailsRecord objects of clients who are still
- * waiting to receive all of the thumbnails for a task.
- */
- final ArrayList<PendingThumbnailsRecord> mPendingThumbnails =
- new ArrayList<PendingThumbnailsRecord>();
-
final ProviderMap mProviderMap;
/**
@@ -991,7 +983,7 @@
/**
* This is set if we had to do a delayed dexopt of an app before launching
- * it, to increasing the ANR timeouts in that case.
+ * it, to increase the ANR timeouts in that case.
*/
boolean mDidDexOpt;
@@ -1331,7 +1323,7 @@
}
} break;
case UPDATE_HTTP_PROXY_MSG: {
- ProxyProperties proxy = (ProxyProperties)msg.obj;
+ ProxyInfo proxy = (ProxyInfo)msg.obj;
String host = "";
String port = "";
String exclList = "";
@@ -1339,8 +1331,8 @@
if (proxy != null) {
host = proxy.getHost();
port = Integer.toString(proxy.getPort());
- exclList = proxy.getExclusionList();
- pacFileUrl = proxy.getPacFileUrl();
+ exclList = proxy.getExclusionListAsString();
+ pacFileUrl = proxy.getPacFileUrl().toString();
}
synchronized (ActivityManagerService.this) {
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
@@ -5452,21 +5444,15 @@
throw new IllegalArgumentException("File descriptors passed in Bundle");
}
- ActivityRecord r = null;
-
final long origId = Binder.clearCallingIdentity();
synchronized (this) {
- r = ActivityRecord.isInStackLocked(token);
+ ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
r.task.stack.activityStoppedLocked(r, icicle, thumbnail, description);
}
}
- if (r != null) {
- sendPendingThumbnail(r, null, null, null, false);
- }
-
trimApplications();
Binder.restoreCallingIdentity(origId);
@@ -6982,66 +6968,24 @@
// =========================================================
@Override
- public List<RunningTaskInfo> getTasks(int maxNum, int flags,
- IThumbnailReceiver receiver) {
+ public List<RunningTaskInfo> getTasks(int maxNum, int flags) {
+ final int callingUid = Binder.getCallingUid();
ArrayList<RunningTaskInfo> list = new ArrayList<RunningTaskInfo>();
- PendingThumbnailsRecord pending = new PendingThumbnailsRecord(receiver);
- ActivityRecord topRecord = null;
-
synchronized(this) {
if (localLOGV) Slog.v(
- TAG, "getTasks: max=" + maxNum + ", flags=" + flags
- + ", receiver=" + receiver);
+ TAG, "getTasks: max=" + maxNum + ", flags=" + flags);
- if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
- != PackageManager.PERMISSION_GRANTED) {
- if (receiver != null) {
- // If the caller wants to wait for pending thumbnails,
- // it ain't gonna get them.
- try {
- receiver.finished();
- } catch (RemoteException ex) {
- }
- }
- String msg = "Permission Denial: getTasks() from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid()
- + " requires " + android.Manifest.permission.GET_TASKS;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
+ final boolean allowed = checkCallingPermission(
+ android.Manifest.permission.GET_TASKS)
+ == PackageManager.PERMISSION_GRANTED;
+ if (!allowed) {
+ Slog.w(TAG, "getTasks: caller " + callingUid
+ + " does not hold GET_TASKS; limiting output");
}
// TODO: Improve with MRU list from all ActivityStacks.
- topRecord = mStackSupervisor.getTasksLocked(maxNum, receiver, pending, list);
-
- if (!pending.pendingRecords.isEmpty()) {
- mPendingThumbnails.add(pending);
- }
- }
-
- if (localLOGV) Slog.v(TAG, "We have pending thumbnails: " + pending);
-
- if (topRecord != null) {
- if (localLOGV) Slog.v(TAG, "Requesting top thumbnail");
- try {
- IApplicationThread topThumbnail = topRecord.app.thread;
- topThumbnail.requestThumbnail(topRecord.appToken);
- } catch (Exception e) {
- Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
- sendPendingThumbnail(null, topRecord.appToken, null, null, true);
- }
- }
-
- if (pending.pendingRecords.isEmpty() && receiver != null) {
- // In this case all thumbnails were available and the client
- // is being asked to be told when the remaining ones come in...
- // which is unusually, since the top-most currently running
- // activity should never have a canned thumbnail! Oh well.
- try {
- receiver.finished();
- } catch (RemoteException ex) {
- }
+ mStackSupervisor.getTasksLocked(maxNum, list, callingUid, allowed);
}
return list;
@@ -7054,12 +6998,18 @@
@Override
public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
int flags, int userId) {
- userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
+ final int callingUid = Binder.getCallingUid();
+ userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
false, true, "getRecentTasks", null);
synchronized (this) {
- enforceCallingPermission(android.Manifest.permission.GET_TASKS,
- "getRecentTasks()");
+ final boolean allowed = checkCallingPermission(
+ android.Manifest.permission.GET_TASKS)
+ == PackageManager.PERMISSION_GRANTED;
+ if (!allowed) {
+ Slog.w(TAG, "getRecentTasks: caller " + callingUid
+ + " does not hold GET_TASKS; limiting output");
+ }
final boolean detailed = checkCallingPermission(
android.Manifest.permission.GET_DETAILED_TASKS)
== PackageManager.PERMISSION_GRANTED;
@@ -7094,6 +7044,13 @@
|| (tr.intent == null)
|| ((tr.intent.getFlags()
&Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
+ if (!allowed) {
+ // If the caller doesn't have the GET_TASKS permission, then only
+ // allow them to see a small subset of tasks -- their own and home.
+ if (!tr.isHomeTask() && tr.creatorUid != callingUid) {
+ continue;
+ }
+ }
ActivityManager.RecentTaskInfo rti
= new ActivityManager.RecentTaskInfo();
rti.id = tr.numActivities > 0 ? tr.taskId : -1;
@@ -7122,14 +7079,34 @@
break;
}
}
- // Traverse downwards starting below break looking for set label and icon.
- for (--activityNdx; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = activities.get(activityNdx);
- if (r.activityLabel != null || r.activityIcon != null) {
- rti.activityLabel = r.activityLabel;
- rti.activityIcon = r.activityIcon;
- 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) {
@@ -7197,13 +7174,11 @@
}
@Override
- public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
- Bitmap activityIcon) {
+ public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues rav) {
synchronized (this) {
ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
- r.activityLabel = activityLabel.toString();
- r.activityIcon = activityIcon;
+ r.activityValues = rav;
}
}
}
@@ -7635,82 +7610,6 @@
}
// =========================================================
- // THUMBNAILS
- // =========================================================
-
- public void reportThumbnail(IBinder token,
- Bitmap thumbnail, CharSequence description) {
- //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
- final long origId = Binder.clearCallingIdentity();
- sendPendingThumbnail(null, token, thumbnail, description, true);
- Binder.restoreCallingIdentity(origId);
- }
-
- final void sendPendingThumbnail(ActivityRecord r, IBinder token,
- Bitmap thumbnail, CharSequence description, boolean always) {
- TaskRecord task;
- ArrayList<PendingThumbnailsRecord> receivers = null;
-
- //System.out.println("Send pending thumbnail: " + r);
-
- synchronized(this) {
- if (r == null) {
- r = ActivityRecord.isInStackLocked(token);
- if (r == null) {
- return;
- }
- }
- if (thumbnail == null && r.thumbHolder != null) {
- thumbnail = r.thumbHolder.lastThumbnail;
- description = r.thumbHolder.lastDescription;
- }
- if (thumbnail == null && !always) {
- // If there is no thumbnail, and this entry is not actually
- // going away, then abort for now and pick up the next
- // thumbnail we get.
- return;
- }
- task = r.task;
-
- int N = mPendingThumbnails.size();
- int i=0;
- while (i<N) {
- PendingThumbnailsRecord pr = mPendingThumbnails.get(i);
- //System.out.println("Looking in " + pr.pendingRecords);
- if (pr.pendingRecords.remove(r)) {
- if (receivers == null) {
- receivers = new ArrayList<PendingThumbnailsRecord>();
- }
- receivers.add(pr);
- if (pr.pendingRecords.size() == 0) {
- pr.finished = true;
- mPendingThumbnails.remove(i);
- N--;
- continue;
- }
- }
- i++;
- }
- }
-
- if (receivers != null) {
- final int N = receivers.size();
- for (int i=0; i<N; i++) {
- try {
- PendingThumbnailsRecord pr = receivers.get(i);
- pr.receiver.newThumbnail(
- task != null ? task.taskId : -1, thumbnail, description);
- if (pr.finished) {
- pr.receiver.finished();
- }
- } catch (Exception e) {
- Slog.w(TAG, "Exception thrown when sending thumbnail", e);
- }
- }
- }
- }
-
- // =========================================================
// CONTENT PROVIDERS
// =========================================================
@@ -13859,7 +13758,7 @@
}
if (Proxy.PROXY_CHANGE_ACTION.equals(intent.getAction())) {
- ProxyProperties proxy = intent.getParcelableExtra("proxy");
+ ProxyInfo proxy = intent.getParcelableExtra("proxy");
mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
}
@@ -15305,8 +15204,8 @@
// it when computing the final cached adj later. Note that we don't need to
// worry about this for max adj above, since max adj will always be used to
// keep it out of the cached vaues.
- adj = app.modifyRawOomAdj(adj);
-
+ app.curAdj = app.modifyRawOomAdj(adj);
+ app.curSchedGroup = schedGroup;
app.curProcState = procState;
app.foregroundActivities = foregroundActivities;
@@ -16624,7 +16523,7 @@
}
if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
- if (userId != 0) {
+ if (userId != UserHandle.USER_OWNER) {
Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntentLocked(null, null, intent, null,
@@ -16653,6 +16552,8 @@
EventLogTags.writeAmSwitchUser(userId);
getUserManagerLocked().userForeground(userId);
sendUserSwitchBroadcastsLocked(oldUserId, userId);
+ } else {
+ mStackSupervisor.startBackgroundUserLocked(userId, uss);
}
if (needStart) {
@@ -16828,7 +16729,7 @@
}
}
- void finishUserSwitch(UserStartedState uss) {
+ void finishUserBoot(UserStartedState uss) {
synchronized (this) {
if (uss.mState == UserStartedState.STATE_BOOTING
&& mStartedUsers.get(uss.mHandle.getIdentifier()) == uss) {
@@ -16842,6 +16743,12 @@
android.Manifest.permission.RECEIVE_BOOT_COMPLETED, AppOpsManager.OP_NONE,
true, false, MY_PID, Process.SYSTEM_UID, userId);
}
+ }
+ }
+
+ void finishUserSwitch(UserStartedState uss) {
+ synchronized (this) {
+ finishUserBoot(uss);
startProfilesLocked();
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 7a44473..efd2b57 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -17,12 +17,12 @@
package com.android.server.am;
import android.os.Trace;
-import com.android.internal.R.styleable;
import com.android.internal.app.ResolverActivity;
import com.android.server.AttributeCache;
import com.android.server.am.ActivityStack.ActivityState;
import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
+import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ResultInfo;
import android.content.ComponentName;
@@ -131,7 +131,6 @@
boolean sleeping; // have we told the activity to sleep?
boolean waitingVisible; // true if waiting for a new act to become vis
boolean nowVisible; // is this activity's window visible?
- boolean thumbnailNeeded;// has someone requested a thumbnail?
boolean idle; // has the activity gone idle?
boolean hasBeenLaunched;// has this activity ever been launched?
boolean frozenBeforeDestroy;// has been frozen but not yet destroyed.
@@ -148,8 +147,7 @@
boolean mStartingWindowShown = false;
ActivityContainer mInitialActivityContainer;
- String activityLabel;
- Bitmap activityIcon;
+ ActivityManager.RecentsActivityValues activityValues; // the recents information for this activity
void dump(PrintWriter pw, String prefix) {
final long now = SystemClock.uptimeMillis();
@@ -239,7 +237,6 @@
pw.print(" immersive="); pw.print(immersive);
pw.print(" launchMode="); pw.println(launchMode);
pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
- pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded);
pw.print(" forceNewConfig="); pw.println(forceNewConfig);
pw.print(prefix); pw.print("mActivityType=");
pw.println(activityTypeToString(mActivityType));
@@ -375,7 +372,6 @@
visible = true;
waitingVisible = false;
nowVisible = false;
- thumbnailNeeded = false;
idle = false;
hasBeenLaunched = false;
mStackSupervisor = supervisor;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 6769c9c..a95710b 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -36,8 +36,6 @@
import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.CONTAINER_STATE_HAS_SURFACE;
-
import android.service.voice.IVoiceInteractionSession;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.BatteryStatsImpl;
@@ -53,7 +51,6 @@
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IActivityController;
-import android.app.IThumbnailReceiver;
import android.app.ResultInfo;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.ComponentName;
@@ -73,7 +70,6 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.util.EventLog;
@@ -1098,6 +1094,36 @@
ensureActivitiesVisibleLocked(r, starting, null, configChanges, forceHomeShown);
}
+ // Checks if any of the stacks above this one has a fullscreen activity behind it.
+ // If so, this stack is hidden, otherwise it is visible.
+ private boolean isStackVisible() {
+ if (!isAttached()) {
+ return false;
+ }
+
+ if (mStackSupervisor.isFrontStack(this)) {
+ return true;
+ }
+
+ // Start at the task above this one and go up, looking for a visible
+ // fullscreen activity, or a translucent activity that requested the
+ // wallpaper to be shown behind it.
+ for (int i = mStacks.indexOf(this) + 1; i < mStacks.size(); i++) {
+ final ArrayList<TaskRecord> tasks = mStacks.get(i).getAllTasks();
+ for (int taskNdx = 0; taskNdx < tasks.size(); taskNdx++) {
+ final ArrayList<ActivityRecord> activities = tasks.get(taskNdx).mActivities;
+ for (int activityNdx = 0; activityNdx < activities.size(); activityNdx++) {
+ final ActivityRecord r = activities.get(activityNdx);
+ if (!r.finishing && r.visible && r.fullscreen) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
/**
* Make sure that all activities that need to be visible (that is, they
* currently can be seen by the user) actually are.
@@ -1122,8 +1148,8 @@
// make sure any activities under it are now visible.
boolean aboveTop = true;
boolean showHomeBehindStack = false;
- boolean behindFullscreen = !mStackSupervisor.isFrontStack(this) &&
- !(forceHomeShown && isHomeStack());
+ boolean behindFullscreen = !isStackVisible();
+
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
final ArrayList<ActivityRecord> activities = task.mActivities;
@@ -2537,13 +2563,6 @@
finishActivityResultsLocked(r, resultCode, resultData);
- if (!mService.mPendingThumbnails.isEmpty()) {
- // There are clients waiting to receive thumbnails so, in case
- // this is an activity that someone is waiting for, add it
- // to the pending list so we can correctly update the clients.
- mStackSupervisor.mCancelledThumbnails.add(r);
- }
-
if (mResumedActivity == r) {
boolean endTask = index <= 0;
if (DEBUG_VISBILITY || DEBUG_TRANSITION) Slog.v(TAG,
@@ -2782,13 +2801,6 @@
cleanUpActivityServicesLocked(r);
}
- if (!mService.mPendingThumbnails.isEmpty()) {
- // There are clients waiting to receive thumbnails so, in case
- // this is an activity that someone is waiting for, add it
- // to the pending list so we can correctly update the clients.
- mStackSupervisor.mCancelledThumbnails.add(r);
- }
-
// Get rid of any pending idle timeouts.
removeTimeoutsForActivityLocked(r);
}
@@ -3535,9 +3547,7 @@
return didSomething;
}
- ActivityRecord getTasksLocked(IThumbnailReceiver receiver,
- PendingThumbnailsRecord pending, List<RunningTaskInfo> list) {
- ActivityRecord topRecord = null;
+ void getTasksLocked(List<RunningTaskInfo> list, int callingUid, boolean allowed) {
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
ActivityRecord r = null;
@@ -3548,6 +3558,9 @@
if (activities.isEmpty()) {
continue;
}
+ if (!allowed && !task.isHomeTask() && task.creatorUid != callingUid) {
+ continue;
+ }
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
r = activities.get(activityNdx);
@@ -3581,23 +3594,8 @@
ci.numRunning = numRunning;
//System.out.println(
// "#" + maxNum + ": " + " descr=" + ci.description);
- if (receiver != null) {
- if (localLOGV) Slog.v(
- TAG, "State=" + top.state + "Idle=" + top.idle
- + " app=" + top.app
- + " thr=" + (top.app != null ? top.app.thread : null));
- if (top.state == ActivityState.RESUMED || top.state == ActivityState.PAUSING) {
- if (top.idle && top.app != null && top.app.thread != null) {
- topRecord = top;
- } else {
- top.thumbnailNeeded = true;
- }
- }
- pending.pendingRecords.add(top);
- }
list.add(ci);
}
- return topRecord;
}
public void unhandledBackLocked() {
@@ -3731,10 +3729,20 @@
mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
}
mTaskHistory.remove(task);
- if (task.voiceInteractor != null) {
- // This task was a voice interaction, so it should not remain on the
- // recent tasks list.
- mService.mRecentTasks.remove(task);
+
+ if (task.mActivities.isEmpty()) {
+ final boolean isVoiceSession = task.voiceSession != null;
+ if (isVoiceSession) {
+ try {
+ task.voiceSession.taskFinished(task.intent, task.taskId);
+ } catch (RemoteException e) {
+ }
+ }
+ if (task.autoRemoveFromRecents() || isVoiceSession) {
+ // Task creator asked to remove this when done, or this task was a voice
+ // interaction, so it should not remain on the recent tasks list.
+ mService.mRecentTasks.remove(task);
+ }
}
if (mTaskHistory.isEmpty()) {
@@ -3753,7 +3761,7 @@
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
boolean toTop) {
TaskRecord task = new TaskRecord(taskId, info, intent, voiceSession, voiceInteractor);
- addTask(task, toTop);
+ addTask(task, toTop, false);
return task;
}
@@ -3761,13 +3769,19 @@
return new ArrayList<TaskRecord>(mTaskHistory);
}
- void addTask(final TaskRecord task, final boolean toTop) {
+ void addTask(final TaskRecord task, final boolean toTop, boolean moving) {
task.stack = this;
if (toTop) {
insertTaskAtTop(task);
} else {
mTaskHistory.add(0, task);
}
+ if (!moving && task.voiceSession != null) {
+ try {
+ task.voiceSession.taskStarted(task.intent, task.taskId);
+ } catch (RemoteException e) {
+ }
+ }
}
public int getStackId() {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 3770a07..00327ac 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -41,7 +41,6 @@
import android.app.IActivityContainerCallback;
import android.app.IActivityManager;
import android.app.IApplicationThread;
-import android.app.IThumbnailReceiver;
import android.app.PendingIntent;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.IActivityManager.WaitResult;
@@ -191,13 +190,12 @@
/** List of activities that are in the process of going to sleep. */
final ArrayList<ActivityRecord> mGoingToSleepActivities = new ArrayList<ActivityRecord>();
- /** List of ActivityRecord objects that have been finished and must still report back to a
- * pending thumbnail receiver. */
- final ArrayList<ActivityRecord> mCancelledThumbnails = new ArrayList<ActivityRecord>();
-
/** Used on user changes */
final ArrayList<UserStartedState> mStartingUsers = new ArrayList<UserStartedState>();
+ /** Used to queue up any background users being started */
+ final ArrayList<UserStartedState> mStartingBackgroundUsers = new ArrayList<UserStartedState>();
+
/** Set to indicate whether to issue an onUserLeaving callback when a newly launched activity
* is being brought in front of us. */
boolean mUserLeaving = false;
@@ -591,10 +589,7 @@
return null;
}
- ActivityRecord getTasksLocked(int maxNum, IThumbnailReceiver receiver,
- PendingThumbnailsRecord pending, List<RunningTaskInfo> list) {
- ActivityRecord r = null;
-
+ void getTasksLocked(int maxNum, List<RunningTaskInfo> list, int callingUid, boolean allowed) {
// Gather all of the running tasks for each stack into runningTaskLists.
ArrayList<ArrayList<RunningTaskInfo>> runningTaskLists =
new ArrayList<ArrayList<RunningTaskInfo>>();
@@ -605,10 +600,7 @@
final ActivityStack stack = stacks.get(stackNdx);
ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<RunningTaskInfo>();
runningTaskLists.add(stackTaskList);
- final ActivityRecord ar = stack.getTasksLocked(receiver, pending, stackTaskList);
- if (r == null && isFrontStack(stack)) {
- r = ar;
- }
+ stack.getTasksLocked(stackTaskList, callingUid, allowed);
}
}
@@ -635,8 +627,6 @@
break;
}
}
-
- return r;
}
ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
@@ -1484,6 +1474,17 @@
}
}
+ switch (r.info.documentLaunchMode) {
+ case ActivityInfo.DOCUMENT_LAUNCH_NONE:
+ break;
+ case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
+ intent.addFlags(
+ Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ break;
+ case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+ break;
+ }
final boolean newDocument = intent.isDocument();
if (sourceRecord == null) {
// This activity is not being started from another... in this
@@ -1912,7 +1913,6 @@
ArrayList<UserStartedState> startingUsers = null;
int NS = 0;
int NF = 0;
- IApplicationThread sendThumbnail = null;
boolean booting = false;
boolean enableScreen = false;
boolean activityRemoved = false;
@@ -1940,11 +1940,6 @@
// us, we can now deliver.
r.idle = true;
- if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
- sendThumbnail = r.app.thread;
- r.thumbnailNeeded = false;
- }
-
//Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
if (!mService.mBooted && isFrontStack(r.task.stack)) {
mService.mBooted = true;
@@ -1976,15 +1971,6 @@
mFinishingActivities.clear();
}
- final ArrayList<ActivityRecord> thumbnails;
- final int NT = mCancelledThumbnails.size();
- if (NT > 0) {
- thumbnails = new ArrayList<ActivityRecord>(mCancelledThumbnails);
- mCancelledThumbnails.clear();
- } else {
- thumbnails = null;
- }
-
if (isFrontStack(mHomeStack)) {
booting = mService.mBooting;
mService.mBooting = false;
@@ -1995,28 +1981,6 @@
mStartingUsers.clear();
}
- // Perform the following actions from unsynchronized state.
- final IApplicationThread thumbnailThread = sendThumbnail;
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (thumbnailThread != null) {
- try {
- thumbnailThread.requestThumbnail(token);
- } catch (Exception e) {
- Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
- mService.sendPendingThumbnail(null, token, null, null, true);
- }
- }
-
- // Report back to any thumbnail receivers.
- for (int i = 0; i < NT; i++) {
- ActivityRecord r = thumbnails.get(i);
- mService.sendPendingThumbnail(r, null, null, null, true);
- }
- }
- });
-
// Stop any activities that are scheduled to do so but have been
// waiting for the next one to start.
for (int i = 0; i < NS; i++) {
@@ -2038,9 +2002,20 @@
if (booting) {
mService.finishBooting();
- } else if (startingUsers != null) {
- for (int i = 0; i < startingUsers.size(); i++) {
- mService.finishUserSwitch(startingUsers.get(i));
+ } else {
+ // Complete user switch
+ if (startingUsers != null) {
+ for (int i = 0; i < startingUsers.size(); i++) {
+ mService.finishUserSwitch(startingUsers.get(i));
+ }
+ }
+ // Complete starting up of background users
+ if (mStartingBackgroundUsers.size() > 0) {
+ startingUsers = new ArrayList<UserStartedState>(mStartingBackgroundUsers);
+ mStartingBackgroundUsers.clear();
+ for (int i = 0; i < startingUsers.size(); i++) {
+ mService.finishUserBoot(startingUsers.get(i));
+ }
}
}
@@ -2288,7 +2263,7 @@
return;
}
task.stack.removeTask(task);
- stack.addTask(task, toTop);
+ stack.addTask(task, toTop, true);
mWindowManager.addTask(taskId, stackId, toTop);
resumeTopActivitiesLocked();
}
@@ -2546,6 +2521,15 @@
return homeInFront;
}
+ /**
+ * Add background users to send boot completed events to.
+ * @param userId The user being started in the background
+ * @param uss The state object for the user.
+ */
+ public void startBackgroundUserLocked(int userId, UserStartedState uss) {
+ mStartingBackgroundUsers.add(uss);
+ }
+
final ArrayList<ActivityRecord> processStoppingActivitiesLocked(boolean remove) {
int N = mStoppingActivities.size();
if (N <= 0) return null;
@@ -3169,7 +3153,7 @@
}
}
ActivityInfo aInfo = resolveActivity(intent, resolvedType, 0, null, null, userId);
- if ((aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
+ if (aInfo != null && (aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
throw new SecurityException(
"Attempt to embed activity that has not set allowEmbedded=\"true\"");
}
@@ -3288,9 +3272,9 @@
} else {
mContainerState = CONTAINER_STATE_NO_SURFACE;
((VirtualActivityDisplay) mActivityDisplay).setSurface(null);
-// if (mStack.mPausingActivity == null && mStack.mResumedActivity != null) {
-// mStack.startPausingLocked(false, true);
-// }
+ if (mStack.mPausingActivity == null && mStack.mResumedActivity != null) {
+ mStack.startPausingLocked(false, true);
+ }
}
setSurfaceIfReady();
@@ -3300,6 +3284,11 @@
}
@Override
+ boolean isAttached() {
+ return mSurface != null && super.isAttached();
+ }
+
+ @Override
void setDrawn() {
synchronized (mService) {
mDrawn = true;
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 83e8a4b..dd12a65 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -230,10 +230,10 @@
}
}
- public void noteScreenOn() {
+ public void noteScreenState(int state) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.noteScreenOnLocked();
+ mStats.noteScreenStateLocked(state);
}
}
@@ -244,24 +244,19 @@
}
}
- public void noteScreenOff() {
- enforceCallingPermission();
- synchronized (mStats) {
- mStats.noteScreenOffLocked();
- }
- }
-
- public void noteInputEvent() {
- enforceCallingPermission();
- mStats.noteInputEventAtomic();
- }
-
public void noteUserActivity(int uid, int event) {
enforceCallingPermission();
synchronized (mStats) {
mStats.noteUserActivityLocked(uid, event);
}
}
+
+ public void noteInteractive(boolean interactive) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteInteractiveLocked(interactive);
+ }
+ }
public void noteMobileRadioPowerState(int powerState, long timestampNs) {
enforceCallingPermission();
diff --git a/services/core/java/com/android/server/am/PendingThumbnailsRecord.java b/services/core/java/com/android/server/am/PendingThumbnailsRecord.java
deleted file mode 100644
index e4eb4d0..0000000
--- a/services/core/java/com/android/server/am/PendingThumbnailsRecord.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.am;
-
-import android.app.IThumbnailReceiver;
-
-import java.util.HashSet;
-
-/**
- * This class keeps track of calls to getTasks() that are still
- * waiting for thumbnail images.
- */
-final class PendingThumbnailsRecord
-{
- final IThumbnailReceiver receiver; // who is waiting.
- final HashSet<ActivityRecord> pendingRecords; // HistoryRecord objects we still wait for.
- boolean finished; // Is pendingRecords empty?
-
- PendingThumbnailsRecord(IThumbnailReceiver _receiver)
- {
- receiver = _receiver;
- pendingRecords = new HashSet<ActivityRecord>();
- finished = false;
- }
-}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 68da54d..862932c 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -52,9 +52,15 @@
String stringName; // caching of toString() result.
int userId; // user for which this task was created
+ int creatorUid; // The app uid that originally created the task
int numFullscreen; // Number of fullscreen activities.
+ // This represents the last resolved activity values for this task
+ // NOTE: This value needs to be persisted with each task
+ ActivityManager.RecentsActivityValues lastActivityValues =
+ new ActivityManager.RecentsActivityValues();
+
/** List of all activities in the task arranged in history order */
final ArrayList<ActivityRecord> mActivities = new ArrayList<ActivityRecord>();
@@ -131,8 +137,10 @@
rootWasReset = true;
}
- if (info.applicationInfo != null) {
- userId = UserHandle.getUserId(info.applicationInfo.uid);
+ userId = UserHandle.getUserId(info.applicationInfo.uid);
+ creatorUid = info.applicationInfo.uid;
+ if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
+ intent.addFlags(Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
}
}
@@ -241,6 +249,11 @@
return mActivities.size() == 0;
}
+ boolean autoRemoveFromRecents() {
+ return intent != null &&
+ (intent.getFlags() & Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS) != 0;
+ }
+
/**
* Completely remove all activities associated with an existing
* task starting at a specified index.
diff --git a/services/core/java/com/android/server/am/UsageStatsService.java b/services/core/java/com/android/server/am/UsageStatsService.java
index 587f949..42cf900 100644
--- a/services/core/java/com/android/server/am/UsageStatsService.java
+++ b/services/core/java/com/android/server/am/UsageStatsService.java
@@ -73,42 +73,44 @@
private static final boolean localLOGV = false;
private static final boolean REPORT_UNEXPECTED = false;
private static final String TAG = "UsageStats";
-
+
// Current on-disk Parcel version
private static final int VERSION = 1008;
private static final int CHECKIN_VERSION = 4;
-
+
private static final String FILE_PREFIX = "usage-";
private static final String FILE_HISTORY = FILE_PREFIX + "history.xml";
- private static final int FILE_WRITE_INTERVAL = 30*60*1000; //ms
-
+ private static final int FILE_WRITE_INTERVAL = (localLOGV) ? 0 : 30*60*1000; // 30m in ms
+
private static final int MAX_NUM_FILES = 5;
-
+
private static final int NUM_LAUNCH_TIME_BINS = 10;
private static final int[] LAUNCH_TIME_BINS = {
250, 500, 750, 1000, 1500, 2000, 3000, 4000, 5000
};
-
+
static IUsageStats sService;
private Context mContext;
// structure used to maintain statistics since the last checkin.
- final private ArrayMap<String, PkgUsageStatsExtended> mStats;
+ final private ArrayMap<String, PkgUsageStatsExtended> mStats
+ = new ArrayMap<String, PkgUsageStatsExtended>();
// Maintains the last time any component was resumed, for all time.
- final private ArrayMap<String, ArrayMap<String, Long>> mLastResumeTimes;
+ final private ArrayMap<String, ArrayMap<String, Long>> mLastResumeTimes
+ = new ArrayMap<String, ArrayMap<String, Long>>();
// To remove last-resume time stats when a pacakge is removed.
private PackageMonitor mPackageMonitor;
// Lock to update package stats. Methods suffixed by SLOCK should invoked with
// this lock held
- final Object mStatsLock;
+ final Object mStatsLock = new Object();
// Lock to write to file. Methods suffixed by FLOCK should invoked with
// this lock held.
- final Object mFileLock;
+ final Object mFileLock = new Object();
// Order of locks is mFileLock followed by mStatsLock to avoid deadlocks
private String mLastResumedPkg;
private String mLastResumedComp;
@@ -118,52 +120,53 @@
private String mFileLeaf;
private File mDir;
- private Calendar mCal; // guarded by itself
+ private final Calendar mCal // guarded by itself
+ = Calendar.getInstance(TimeZone.getTimeZone("GMT+0"));
private final AtomicInteger mLastWriteDay = new AtomicInteger(-1);
private final AtomicLong mLastWriteElapsedTime = new AtomicLong(0);
private final AtomicBoolean mUnforcedDiskWriteRunning = new AtomicBoolean(false);
-
+
static class TimeStats {
- int count;
- int[] times = new int[NUM_LAUNCH_TIME_BINS];
-
+ int mCount;
+ final int[] mTimes = new int[NUM_LAUNCH_TIME_BINS];
+
TimeStats() {
}
-
+
void incCount() {
- count++;
+ mCount++;
}
-
+
void add(int val) {
final int[] bins = LAUNCH_TIME_BINS;
for (int i=0; i<NUM_LAUNCH_TIME_BINS-1; i++) {
if (val < bins[i]) {
- times[i]++;
+ mTimes[i]++;
return;
}
}
- times[NUM_LAUNCH_TIME_BINS-1]++;
+ mTimes[NUM_LAUNCH_TIME_BINS-1]++;
}
-
+
TimeStats(Parcel in) {
- count = in.readInt();
- final int[] localTimes = times;
+ mCount = in.readInt();
+ final int[] localTimes = mTimes;
for (int i=0; i<NUM_LAUNCH_TIME_BINS; i++) {
localTimes[i] = in.readInt();
}
}
-
+
void writeToParcel(Parcel out) {
- out.writeInt(count);
- final int[] localTimes = times;
+ out.writeInt(mCount);
+ final int[] localTimes = mTimes;
for (int i=0; i<NUM_LAUNCH_TIME_BINS; i++) {
out.writeInt(localTimes[i]);
}
}
}
-
- private class PkgUsageStatsExtended {
+
+ static class PkgUsageStatsExtended {
final ArrayMap<String, TimeStats> mLaunchTimes
= new ArrayMap<String, TimeStats>();
final ArrayMap<String, TimeStats> mFullyDrawnTimes
@@ -172,18 +175,18 @@
long mUsageTime;
long mPausedTime;
long mResumedTime;
-
+
PkgUsageStatsExtended() {
mLaunchCount = 0;
mUsageTime = 0;
}
-
+
PkgUsageStatsExtended(Parcel in) {
mLaunchCount = in.readInt();
mUsageTime = in.readLong();
if (localLOGV) Slog.v(TAG, "Launch count: " + mLaunchCount
+ ", Usage time:" + mUsageTime);
-
+
final int numLaunchTimeStats = in.readInt();
if (localLOGV) Slog.v(TAG, "Reading launch times: " + numLaunchTimeStats);
mLaunchTimes.ensureCapacity(numLaunchTimeStats);
@@ -207,16 +210,16 @@
void updateResume(String comp, boolean launched) {
if (launched) {
- mLaunchCount ++;
+ mLaunchCount++;
}
mResumedTime = SystemClock.elapsedRealtime();
}
-
+
void updatePause() {
mPausedTime = SystemClock.elapsedRealtime();
mUsageTime += (mPausedTime - mResumedTime);
}
-
+
void addLaunchCount(String comp) {
TimeStats times = mLaunchTimes.get(comp);
if (times == null) {
@@ -225,7 +228,7 @@
}
times.incCount();
}
-
+
void addLaunchTime(String comp, int millis) {
TimeStats times = mLaunchTimes.get(comp);
if (times == null) {
@@ -260,7 +263,7 @@
mFullyDrawnTimes.valueAt(i).writeToParcel(out);
}
}
-
+
void clear() {
mLaunchTimes.clear();
mFullyDrawnTimes.clear();
@@ -268,32 +271,25 @@
mUsageTime = 0;
}
}
-
+
UsageStatsService(String dir) {
- mStats = new ArrayMap<String, PkgUsageStatsExtended>();
- mLastResumeTimes = new ArrayMap<String, ArrayMap<String, Long>>();
- mStatsLock = new Object();
- mFileLock = new Object();
+ if (localLOGV) Slog.v(TAG, "UsageStatsService: " + dir);
mDir = new File(dir);
- mCal = Calendar.getInstance(TimeZone.getTimeZone("GMT+0"));
-
mDir.mkdir();
-
- // Remove any old usage files from previous versions.
+
+ // Remove any old /data/system/usagestats.* files from previous versions.
File parentDir = mDir.getParentFile();
- String fList[] = parentDir.list();
- if (fList != null) {
+ String files[] = parentDir.list();
+ if (files != null) {
String prefix = mDir.getName() + ".";
- int i = fList.length;
- while (i > 0) {
- i--;
- if (fList[i].startsWith(prefix)) {
- Slog.i(TAG, "Deleting old usage file: " + fList[i]);
- (new File(parentDir, fList[i])).delete();
+ for (String file : files) {
+ if (file.startsWith(prefix)) {
+ Slog.i(TAG, "Deleting old usage file: " + file);
+ (new File(parentDir, file)).delete();
}
}
}
-
+
// Update current stats which are binned by date
mFileLeaf = getCurrentDateStr(FILE_PREFIX);
mFile = new File(mDir, mFileLeaf);
@@ -310,11 +306,11 @@
*/
private String getCurrentDateStr(String prefix) {
StringBuilder sb = new StringBuilder();
+ if (prefix != null) {
+ sb.append(prefix);
+ }
synchronized (mCal) {
mCal.setTimeInMillis(System.currentTimeMillis());
- if (prefix != null) {
- sb.append(prefix);
- }
sb.append(mCal.get(Calendar.YEAR));
int mm = mCal.get(Calendar.MONTH) - Calendar.JANUARY +1;
if (mm < 10) {
@@ -329,17 +325,20 @@
}
return sb.toString();
}
-
+
private Parcel getParcelForFile(File file) throws IOException {
FileInputStream stream = new FileInputStream(file);
- byte[] raw = readFully(stream);
- Parcel in = Parcel.obtain();
- in.unmarshall(raw, 0, raw.length);
- in.setDataPosition(0);
- stream.close();
- return in;
+ try {
+ byte[] raw = readFully(stream);
+ Parcel in = Parcel.obtain();
+ in.unmarshall(raw, 0, raw.length);
+ in.setDataPosition(0);
+ return in;
+ } finally {
+ stream.close();
+ }
}
-
+
private void readStatsFromFile() {
File newFile = mFile;
synchronized (mFileLock) {
@@ -356,12 +355,13 @@
}
}
}
-
+
private void readStatsFLOCK(File file) throws IOException {
Parcel in = getParcelForFile(file);
int vers = in.readInt();
- if (vers != VERSION) {
- Slog.w(TAG, "Usage stats version changed; dropping");
+ if (vers != VERSION) { // vers will be 0 if the parcel file was empty
+ Slog.w(TAG, "Usage stats version of " + file + " changed from " + vers + " to "
+ + VERSION + "; dropping");
return;
}
int N = in.readInt();
@@ -382,12 +382,12 @@
private void readHistoryStatsFromFile() {
synchronized (mFileLock) {
if (mHistoryFile.getBaseFile().exists()) {
- readHistoryStatsFLOCK(mHistoryFile);
+ readHistoryStatsFLOCK();
}
}
}
- private void readHistoryStatsFLOCK(AtomicFile file) {
+ private void readHistoryStatsFLOCK() {
FileInputStream fis = null;
try {
fis = mHistoryFile.openRead();
@@ -470,12 +470,12 @@
}
return fileList;
}
-
+
private void checkFileLimitFLOCK() {
// Get all usage stats output files
ArrayList<String> fileList = getUsageStatsFileListFLOCK();
if (fileList == null) {
- // Strange but we dont have to delete any thing
+ // Empty /data/system/usagestats/ so we don't have anything to delete
return;
}
int count = fileList.size();
@@ -575,8 +575,8 @@
}
if (dayChanged || forceWriteHistoryStats) {
- // Write history stats daily, or when forced (due to shutdown).
- writeHistoryStatsFLOCK(mHistoryFile);
+ // Write history stats daily or when forced (due to shutdown) or when debugging.
+ writeHistoryStatsFLOCK();
}
// Delete the backup file
@@ -638,10 +638,10 @@
}
}
- private void writeHistoryStatsFLOCK(AtomicFile historyFile) {
+ private void writeHistoryStatsFLOCK() {
FileOutputStream fos = null;
try {
- fos = historyFile.startWrite();
+ fos = mHistoryFile.startWrite();
XmlSerializer out = new FastXmlSerializer();
out.setOutput(fos, "utf-8");
out.startDocument(null, true);
@@ -664,11 +664,11 @@
out.endTag(null, "usage-history");
out.endDocument();
- historyFile.finishWrite(fos);
+ mHistoryFile.finishWrite(fos);
} catch (IOException e) {
Slog.w(TAG,"Error writing history stats" + e);
if (fos != null) {
- historyFile.failWrite(fos);
+ mHistoryFile.failWrite(fos);
}
}
}
@@ -711,7 +711,8 @@
sService = asInterface(b);
return sService;
}
-
+
+ @Override
public void noteResumeComponent(ComponentName componentName) {
enforceCallingPermission();
String pkgName;
@@ -720,7 +721,7 @@
((pkgName = componentName.getPackageName()) == null)) {
return;
}
-
+
final boolean samePackage = pkgName.equals(mLastResumedPkg);
if (mIsResumed) {
if (mLastResumedPkg != null) {
@@ -734,14 +735,14 @@
}
}
}
-
+
final boolean sameComp = samePackage
&& componentName.getClassName().equals(mLastResumedComp);
-
+
mIsResumed = true;
mLastResumedPkg = pkgName;
mLastResumedComp = componentName.getClassName();
-
+
if (localLOGV) Slog.i(TAG, "started component:" + pkgName);
PkgUsageStatsExtended pus = mStats.get(pkgName);
if (pus == null) {
@@ -762,9 +763,10 @@
}
}
+ @Override
public void notePauseComponent(ComponentName componentName) {
enforceCallingPermission();
-
+
synchronized (mStatsLock) {
String pkgName;
if ((componentName == null) ||
@@ -777,9 +779,9 @@
return;
}
mIsResumed = false;
-
+
if (localLOGV) Slog.i(TAG, "paused component:"+pkgName);
-
+
PkgUsageStatsExtended pus = mStats.get(pkgName);
if (pus == null) {
// Weird some error here
@@ -788,11 +790,12 @@
}
pus.updatePause();
}
-
+
// Persist current data to file if needed.
writeStatsToFile(false, false);
}
-
+
+ @Override
public void noteLaunchTime(ComponentName componentName, int millis) {
enforceCallingPermission();
String pkgName;
@@ -800,10 +803,10 @@
((pkgName = componentName.getPackageName()) == null)) {
return;
}
-
+
// Persist current data to file if needed.
writeStatsToFile(false, false);
-
+
synchronized (mStatsLock) {
PkgUsageStatsExtended pus = mStats.get(pkgName);
if (pus != null) {
@@ -811,7 +814,7 @@
}
}
}
-
+
public void noteFullyDrawnTime(ComponentName componentName, int millis) {
enforceCallingPermission();
String pkgName;
@@ -838,7 +841,8 @@
mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
Binder.getCallingPid(), Binder.getCallingUid(), null);
}
-
+
+ @Override
public PkgUsageStats getPkgUsageStats(ComponentName componentName) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
@@ -858,7 +862,8 @@
return new PkgUsageStats(pkgName, launchCount, usageTime, lastResumeTimes);
}
}
-
+
+ @Override
public PkgUsageStats[] getAllPkgUsageStats() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
@@ -884,8 +889,8 @@
return retArr;
}
}
-
- static byte[] readFully(FileInputStream stream) throws java.io.IOException {
+
+ static byte[] readFully(FileInputStream stream) throws IOException {
int pos = 0;
int avail = stream.available();
byte[] data = new byte[avail];
@@ -903,7 +908,7 @@
}
}
}
-
+
private void collectDumpInfoFLOCK(PrintWriter pw, boolean isCompactOutput,
boolean deleteAfterPrint, HashSet<String> packages) {
List<String> fileList = getUsageStatsFileListFLOCK();
@@ -932,15 +937,12 @@
// Delete old file after collecting info only for checkin requests
dFile.delete();
}
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "Failed with "+e+" when collecting dump info from file : " + file);
- return;
} catch (IOException e) {
Slog.w(TAG, "Failed with "+e+" when collecting dump info from file : "+file);
- }
+ }
}
}
-
+
private void collectDumpInfoFromParcelFLOCK(Parcel in, PrintWriter pw,
String date, boolean isCompactOutput, HashSet<String> packages) {
StringBuilder sb = new StringBuilder(512);
@@ -951,19 +953,19 @@
} else {
sb.append("Date: ");
}
-
+
sb.append(date);
-
+
int vers = in.readInt();
if (vers != VERSION) {
sb.append(" (old data version)");
pw.println(sb.toString());
return;
}
-
+
pw.println(sb.toString());
int N = in.readInt();
-
+
while (N > 0) {
N--;
String pkgName = in.readString();
@@ -990,10 +992,10 @@
sb.append(activity);
TimeStats times = pus.mLaunchTimes.valueAt(i);
sb.append(',');
- sb.append(times.count);
+ sb.append(times.mCount);
for (int j=0; j<NUM_LAUNCH_TIME_BINS; j++) {
sb.append(",");
- sb.append(times.times[j]);
+ sb.append(times.mTimes[j]);
}
sb.append('\n');
}
@@ -1005,7 +1007,7 @@
TimeStats times = pus.mFullyDrawnTimes.valueAt(i);
for (int j=0; j<NUM_LAUNCH_TIME_BINS; j++) {
sb.append(",");
- sb.append(times.times[j]);
+ sb.append(times.mTimes[j]);
}
sb.append('\n');
}
@@ -1025,26 +1027,26 @@
sb.append(pus.mLaunchTimes.keyAt(i));
TimeStats times = pus.mLaunchTimes.valueAt(i);
sb.append(": ");
- sb.append(times.count);
+ sb.append(times.mCount);
sb.append(" starts");
int lastBin = 0;
for (int j=0; j<NUM_LAUNCH_TIME_BINS-1; j++) {
- if (times.times[j] != 0) {
+ if (times.mTimes[j] != 0) {
sb.append(", ");
sb.append(lastBin);
sb.append('-');
sb.append(LAUNCH_TIME_BINS[j]);
sb.append("ms=");
- sb.append(times.times[j]);
+ sb.append(times.mTimes[j]);
}
lastBin = LAUNCH_TIME_BINS[j];
}
- if (times.times[NUM_LAUNCH_TIME_BINS-1] != 0) {
+ if (times.mTimes[NUM_LAUNCH_TIME_BINS-1] != 0) {
sb.append(", ");
sb.append(">=");
sb.append(lastBin);
sb.append("ms=");
- sb.append(times.times[NUM_LAUNCH_TIME_BINS-1]);
+ sb.append(times.mTimes[NUM_LAUNCH_TIME_BINS-1]);
}
sb.append('\n');
}
@@ -1057,7 +1059,7 @@
boolean needComma = false;
int lastBin = 0;
for (int j=0; j<NUM_LAUNCH_TIME_BINS-1; j++) {
- if (times.times[j] != 0) {
+ if (times.mTimes[j] != 0) {
if (needComma) {
sb.append(", ");
} else {
@@ -1067,27 +1069,27 @@
sb.append('-');
sb.append(LAUNCH_TIME_BINS[j]);
sb.append("ms=");
- sb.append(times.times[j]);
+ sb.append(times.mTimes[j]);
}
lastBin = LAUNCH_TIME_BINS[j];
}
- if (times.times[NUM_LAUNCH_TIME_BINS-1] != 0) {
+ if (times.mTimes[NUM_LAUNCH_TIME_BINS-1] != 0) {
if (needComma) {
sb.append(", ");
}
sb.append(">=");
sb.append(lastBin);
sb.append("ms=");
- sb.append(times.times[NUM_LAUNCH_TIME_BINS-1]);
+ sb.append(times.mTimes[NUM_LAUNCH_TIME_BINS-1]);
}
sb.append('\n');
}
}
-
+
pw.write(sb.toString());
}
}
-
+
/**
* Searches array of arguments for the specified string
* @param args array of argument strings
@@ -1104,7 +1106,7 @@
}
return false;
}
-
+
/**
* Searches array of arguments for the specified string's data
* @param args array of argument strings
@@ -1123,11 +1125,11 @@
}
return null;
}
-
- @Override
+
/*
- * The data persisted to file is parsed and the stats are computed.
+ * The data persisted to file is parsed and the stats are computed.
*/
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
@@ -1141,23 +1143,23 @@
final boolean isCompactOutput = isCheckinRequest || scanArgs(args, "-c");
final boolean deleteAfterPrint = isCheckinRequest || scanArgs(args, "-d");
final String rawPackages = scanArgsData(args, "--packages");
-
+
// Make sure the current stats are written to the file. This
// doesn't need to be done if we are deleting files after printing,
- // since it that case we won't print the current stats.
+ // since in that case we won't print the current stats.
if (!deleteAfterPrint) {
writeStatsToFile(true, false);
}
-
+
HashSet<String> packages = null;
if (rawPackages != null) {
if (!"*".equals(rawPackages)) {
// A * is a wildcard to show all packages.
String[] names = rawPackages.split(",");
+ if (names.length != 0) {
+ packages = new HashSet<String>();
+ }
for (String n : names) {
- if (packages == null) {
- packages = new HashSet<String>();
- }
packages.add(n);
}
}
@@ -1167,7 +1169,7 @@
Slog.w(TAG, "Checkin without packages");
return;
}
-
+
synchronized (mFileLock) {
collectDumpInfoFLOCK(pw, isCompactOutput, deleteAfterPrint, packages);
}
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 8815d0f..0749f24 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -24,7 +24,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -157,14 +157,14 @@
* @param proxy Proxy information that is about to be broadcast.
* @return Returns true when the broadcast should not be sent
*/
- public synchronized boolean setCurrentProxyScriptUrl(ProxyProperties proxy) {
- if (!TextUtils.isEmpty(proxy.getPacFileUrl())) {
+ public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
+ if (proxy.getPacFileUrl() != null) {
if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) {
// Allow to send broadcast, nothing to do.
return false;
}
synchronized (mProxyLock) {
- mPacUrl = proxy.getPacFileUrl();
+ mPacUrl = proxy.getPacFileUrl().toString();
}
mCurrentDelay = DELAY_1;
mHasSentBroadcast = false;
@@ -268,7 +268,7 @@
// Already bound no need to bind again.
if ((mProxyConnection != null) && (mConnection != null)) {
if (mLastPort != -1) {
- sendPacBroadcast(new ProxyProperties(mPacUrl, mLastPort));
+ sendPacBroadcast(new ProxyInfo(mPacUrl, mLastPort));
} else {
Log.e(TAG, "Received invalid port from Local Proxy,"
+ " PAC will not be operational");
@@ -362,7 +362,7 @@
mLastPort = -1;
}
- private void sendPacBroadcast(ProxyProperties proxy) {
+ private void sendPacBroadcast(ProxyInfo proxy) {
mConnectivityHandler.sendMessage(mConnectivityHandler.obtainMessage(mProxyMessage, proxy));
}
@@ -371,7 +371,7 @@
return;
}
if (!mHasSentBroadcast) {
- sendPacBroadcast(new ProxyProperties(mPacUrl, mLastPort));
+ sendPacBroadcast(new ProxyInfo(mPacUrl, mLastPort));
mHasSentBroadcast = true;
}
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 026fd296..1b40cdf 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -411,6 +411,7 @@
if (!factoryTest) {
intentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+ intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
context.registerReceiver(mBootCompletedReceiver, intentFilter);
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 1f38eb6..3ae0fd5 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -393,11 +393,7 @@
// Initialize screen state for battery stats.
try {
- if (mPowerState.getScreenState() != Display.STATE_OFF) {
- mBatteryStats.noteScreenOn();
- } else {
- mBatteryStats.noteScreenOff();
- }
+ mBatteryStats.noteScreenState(mPowerState.getScreenState());
mBatteryStats.noteScreenBrightness(mPowerState.getScreenBrightness());
} catch (RemoteException ex) {
// same process
@@ -641,11 +637,7 @@
if (mPowerState.getScreenState() != state) {
mPowerState.setScreenState(state);
try {
- if (state != Display.STATE_OFF) {
- mBatteryStats.noteScreenOn();
- } else {
- mBatteryStats.noteScreenOff();
- }
+ mBatteryStats.noteScreenState(state);
} catch (RemoteException ex) {
// same process
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 91afec7..7f43e43 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -21,6 +21,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.SystemProperties;
+import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayEventReceiver;
@@ -47,8 +48,6 @@
new SparseArray<LocalDisplayDevice>();
private HotplugDisplayEventReceiver mHotplugReceiver;
- private final SurfaceControl.PhysicalDisplayInfo mTempPhys = new SurfaceControl.PhysicalDisplayInfo();
-
// Called with SyncRoot lock held.
public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener) {
@@ -68,14 +67,31 @@
private void tryConnectDisplayLocked(int builtInDisplayId) {
IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);
- if (displayToken != null && SurfaceControl.getDisplayInfo(displayToken, mTempPhys)) {
+ if (displayToken != null) {
+ SurfaceControl.PhysicalDisplayInfo[] configs =
+ SurfaceControl.getDisplayConfigs(displayToken);
+ if (configs == null) {
+ // There are no valid configs for this device, so we can't use it
+ Slog.w(TAG, "No valid configs found for display device " +
+ builtInDisplayId);
+ return;
+ }
+ int activeConfig = SurfaceControl.getActiveConfig(displayToken);
+ if (activeConfig < 0) {
+ // There is no active config, and for now we don't have the
+ // policy to set one.
+ Slog.w(TAG, "No active config found for display device " +
+ builtInDisplayId);
+ return;
+ }
LocalDisplayDevice device = mDevices.get(builtInDisplayId);
if (device == null) {
// Display was added.
- device = new LocalDisplayDevice(displayToken, builtInDisplayId, mTempPhys);
+ device = new LocalDisplayDevice(displayToken, builtInDisplayId,
+ configs[activeConfig]);
mDevices.put(builtInDisplayId, device);
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
- } else if (device.updatePhysicalDisplayInfoLocked(mTempPhys)) {
+ } else if (device.updatePhysicalDisplayInfoLocked(configs[activeConfig])) {
// Display properties changed.
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
}
@@ -228,4 +244,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index a165f26..14ef5a9 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -146,9 +146,7 @@
@Override
public void performTraversalInTransactionLocked() {
- if (mSurface != null) {
- setSurfaceInTransactionLocked(mSurface);
- }
+ setSurfaceInTransactionLocked(mSurface);
}
public void setSurfaceLocked(Surface surface) {
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index fd2f8a1..8968da3 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -642,8 +642,9 @@
try {
synchronized (mMcuHal) {
if (mReleased) {
- throw new IllegalStateException("This operation cannot be performed "
- + "because the dream has ended.");
+ Slog.w(TAG, "Ignoring message to MCU HAL because the dream "
+ + "has already ended: " + msg);
+ return null;
}
return mMcuHal.sendMessage(msg, arg);
}
diff --git a/services/core/java/com/android/server/hdmi/FeatureAction.java b/services/core/java/com/android/server/hdmi/FeatureAction.java
new file mode 100644
index 0000000..296cc5b
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/FeatureAction.java
@@ -0,0 +1,211 @@
+/*
+ * 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 android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Encapsulates a sequence of CEC/MHL command exchange for a certain feature.
+ *
+ * <p>Many CEC/MHL features are accomplished by CEC devices on the bus exchanging
+ * more than one command. {@link FeatureAction} represents the life cycle of the communication,
+ * manages the state as the process progresses, and if necessary, returns the result
+ * to the caller which initiates the action, through the callback given at the creation
+ * of the object. All the actual action classes inherit FeatureAction.
+ *
+ * <p>More than one FeatureAction objects can be up and running simultaneously,
+ * maintained by {@link HdmiControlService}. Each action is passed a new command
+ * arriving from the bus, and either consumes it if the command is what the action expects,
+ * or yields it to other action.
+ *
+ * Declared as package private, accessed by {@link HdmiControlService} only.
+ */
+abstract class FeatureAction {
+
+ private static final String TAG = "FeatureAction";
+
+ // Timer handler message used for timeout event
+ protected static final int MSG_TIMEOUT = 100;
+
+ // Default timeout for the incoming command to arrive in response to a request
+ protected static final int TIMEOUT_MS = 1000;
+
+ // Default state used in common by all the feature actions.
+ protected static final int STATE_NONE = 0;
+
+ // Internal state indicating the progress of action.
+ protected int mState = STATE_NONE;
+
+ protected final HdmiControlService mService;
+
+ // Logical address of the device for which the feature action is taken. The commands
+ // generated in an action all use this field as source address.
+ protected final int mSourceAddress;
+
+ // Timer that manages timeout events.
+ protected ActionTimer mActionTimer;
+
+ FeatureAction(HdmiControlService service, int sourceAddress) {
+ mService = service;
+ mSourceAddress = sourceAddress;
+ mActionTimer = createActionTimer(service.getServiceLooper());
+ }
+
+ @VisibleForTesting
+ void setActionTimer(ActionTimer actionTimer) {
+ mActionTimer = actionTimer;
+ }
+
+ /**
+ * Called right after the action is created. Initialization or first step to take
+ * for the action can be done in this method.
+ *
+ * @return true if the operation is successful; otherwise false.
+ */
+ abstract boolean start();
+
+ /**
+ * Process the command. Called whenever a new command arrives.
+ *
+ * @param cmd command to process
+ * @return true if the command was consumed in the process; Otherwise false, which
+ * indicates that the command shall be handled by other actions.
+ */
+ abstract boolean processCommand(HdmiCecMessage cmd);
+
+ /**
+ * Called when the action should handle the timer event it created before.
+ *
+ * <p>CEC standard mandates each command transmission should be responded within
+ * certain period of time. The method is called when the timer it created as it transmitted
+ * a command gets expired. Inner logic should take an appropriate action.
+ *
+ * @param state the state associated with the time when the timer was created
+ */
+ abstract void handleTimerEvent(int state);
+
+ /**
+ * Timer handler interface used for FeatureAction classes.
+ */
+ interface ActionTimer {
+ /**
+ * Send a timer message.
+ *
+ * Also carries the state of the action when the timer is created. Later this state is
+ * compared to the one the action is in when it receives the timer to let the action tell
+ * the right timer to handle.
+ *
+ * @param state state of the action is in
+ * @param delayMillis amount of delay for the timer
+ */
+ void sendTimerMessage(int state, long delayMillis);
+ }
+
+ private class ActionTimerHandler extends Handler implements ActionTimer {
+
+ public ActionTimerHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void sendTimerMessage(int state, long delayMillis) {
+ sendMessageDelayed(obtainMessage(MSG_TIMEOUT, state), delayMillis);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_TIMEOUT:
+ handleTimerEvent(msg.arg1);
+ break;
+ default:
+ Slog.w(TAG, "Unsupported message:" + msg.what);
+ break;
+ }
+ }
+ }
+
+ private ActionTimer createActionTimer(Looper looper) {
+ return new ActionTimerHandler(looper);
+ }
+
+ // Add a new timer. The timer event will come to mActionTimer.handleMessage() in
+ // delayMillis.
+ protected void addTimer(int state, int delayMillis) {
+ 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.
+ */
+ protected void finish() {
+ mState = STATE_NONE;
+ removeAction(this);
+ }
+
+ /**
+ * Remove the action from the action queue. This is called after the action finishes
+ * its role.
+ *
+ * @param action
+ */
+ 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 5f07108..b103a4d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -16,9 +16,20 @@
package com.android.server.hdmi;
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import libcore.util.EmptyArray;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
/**
* Manages HDMI-CEC command and behaviors. It converts user's command into CEC command
@@ -29,20 +40,51 @@
*
* <p>Declared as package-private, accessed by {@link HdmiControlService} only.
*/
-class HdmiCecController {
+final class HdmiCecController {
private static final String TAG = "HdmiCecController";
+ private static final byte[] EMPTY_BODY = EmptyArray.BYTE;
+
+ // A message to pass cec send command to IO looper.
+ private static final int MSG_SEND_CEC_COMMAND = 1;
+ // A message to delegate logical allocation to IO looper.
+ private static final int MSG_ALLOCATE_LOGICAL_ADDRESS = 2;
+
+ // Message types to handle incoming message in main service looper.
+ private final static int MSG_RECEIVE_CEC_COMMAND = 1;
+ // 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.
+ private static final int ERROR_SUCCESS = 0;
+
// Handler instance to process synchronous I/O (mainly send) message.
private Handler mIoHandler;
// Handler instance to process various messages coming from other CEC
// device or issued by internal state change.
- private Handler mMessageHandler;
+ private Handler mControlHandler;
// Stores the pointer to the native implementation of the service that
// interacts with HAL.
private long mNativePtr;
+ // 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>();
+
// Private constructor. Use HdmiCecController.create().
private HdmiCecController() {
}
@@ -52,14 +94,12 @@
* inner device or has no device it will return {@code null}.
*
* <p>Declared as package-private, accessed by {@link HdmiControlService} only.
- *
- * @param ioLooper a Looper instance to handle IO (mainly send message) operation.
- * @param messageHandler a message handler that processes a message coming from other
- * CEC compatible device or callback of internal state change.
+ * @param service {@link HdmiControlService} instance used to create internal handler
+ * and to pass callback for incoming message or event.
* @return {@link HdmiCecController} if device is initialized successfully. Otherwise,
* returns {@code null}.
*/
- static HdmiCecController create(Looper ioLooper, Handler messageHandler) {
+ static HdmiCecController create(HdmiControlService service) {
HdmiCecController handler = new HdmiCecController();
long nativePtr = nativeInit(handler);
if (nativePtr == 0L) {
@@ -67,28 +107,325 @@
return null;
}
- handler.init(ioLooper, messageHandler, nativePtr);
+ handler.init(service, nativePtr);
return handler;
}
- private void init(Looper ioLooper, Handler messageHandler, long nativePtr) {
- mIoHandler = new Handler(ioLooper) {
- @Override
- public void handleMessage(Message msg) {
- // TODO: Call native sendMessage.
- }
- };
-
- mMessageHandler = messageHandler;
- mNativePtr = nativePtr;
+ /**
+ * Interface to report allocated logical address.
+ */
+ interface AllocateLogicalAddressCallback {
+ /**
+ * Called when a new logical address is allocated.
+ *
+ * @param deviceType requested device type to allocate logical address
+ * @param logicalAddress allocated logical address. If it is
+ * {@link HdmiCec#ADDR_UNREGISTERED}, it means that
+ * it failed to allocate logical address for the given device type
+ */
+ void onAllocated(int deviceType, int logicalAddress);
}
/**
- * Called by native when an HDMI-CEC message arrived.
+ * Allocate a new logical address of the given device type. Allocated
+ * address will be reported through {@link AllocateLogicalAddressCallback}.
+ *
+ * <p> Declared as package-private, accessed by {@link HdmiControlService} only.
+ *
+ * @param deviceType type of device to used to determine logical address
+ * @param preferredAddress a logical address preferred to be allocated.
+ * If sets {@link HdmiCec#ADDR_UNREGISTERED}, scans
+ * the smallest logical address matched with the given device type.
+ * Otherwise, scan address will start from {@code preferredAddress}
+ * @param callback callback interface to report allocated logical address to caller
*/
- private void handleMessage(int srcAddress, int dstAddres, int opcode, byte[] params) {
- // TODO: Translate message and delegate it to main message handler.
+ void allocateLogicalAddress(int deviceType, int preferredAddress,
+ AllocateLogicalAddressCallback callback) {
+ Message msg = mIoHandler.obtainMessage(MSG_ALLOCATE_LOGICAL_ADDRESS);
+ msg.arg1 = deviceType;
+ msg.arg2 = preferredAddress;
+ msg.obj = callback;
+ mIoHandler.sendMessage(msg);
+ }
+
+ private static byte[] buildBody(int opcode, byte[] params) {
+ byte[] body = new byte[params.length + 1];
+ body[0] = (byte) opcode;
+ System.arraycopy(params, 0, body, 1, params.length);
+ return body;
+ }
+
+ private final class IoHandler extends Handler {
+ private IoHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SEND_CEC_COMMAND:
+ HdmiCecMessage cecMessage = (HdmiCecMessage) msg.obj;
+ byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams());
+ nativeSendCecCommand(mNativePtr, cecMessage.getSource(),
+ cecMessage.getDestination(), body);
+ break;
+ case MSG_ALLOCATE_LOGICAL_ADDRESS:
+ int deviceType = msg.arg1;
+ int preferredAddress = msg.arg2;
+ AllocateLogicalAddressCallback callback =
+ (AllocateLogicalAddressCallback) msg.obj;
+ handleAllocateLogicalAddress(deviceType, preferredAddress, callback);
+ break;
+ default:
+ Slog.w(TAG, "Unsupported CEC Io request:" + msg.what);
+ break;
+ }
+ }
+
+ private void handleAllocateLogicalAddress(int deviceType, int preferredAddress,
+ AllocateLogicalAddressCallback callback) {
+ int startAddress = preferredAddress;
+ // If preferred address is "unregistered", start_index will be the smallest
+ // address matched with the given device type.
+ if (preferredAddress == HdmiCec.ADDR_UNREGISTERED) {
+ for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
+ if (deviceType == HdmiCec.getTypeFromAddress(i)) {
+ startAddress = i;
+ break;
+ }
+ }
+ }
+
+ int logcialAddress = HdmiCec.ADDR_UNREGISTERED;
+ // Iterates all possible addresses which has the same device type.
+ for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
+ int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS;
+ if (curAddress != HdmiCec.ADDR_UNREGISTERED
+ && deviceType == HdmiCec.getTypeFromAddress(i)) {
+ // <Polling Message> is a message which has empty body and
+ // uses same address for both source and destination address.
+ // If sending <Polling Message> failed (NAK), it becomes
+ // new logical address for the device because no device uses
+ // it as logical address of the device.
+ int error = nativeSendCecCommand(mNativePtr, curAddress, curAddress,
+ EMPTY_BODY);
+ if (error != ERROR_SUCCESS) {
+ logcialAddress = curAddress;
+ break;
+ }
+ }
+ }
+
+ Message msg = mControlHandler.obtainMessage(MSG_REPORT_LOGICAL_ADDRESS);
+ msg.arg1 = deviceType;
+ msg.arg2 = logcialAddress;
+ msg.obj = callback;
+ mControlHandler.sendMessage(msg);
+ }
+ }
+
+ private final class ControlHandler extends Handler {
+ private ControlHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_RECEIVE_CEC_COMMAND:
+ // TODO: delegate it to HdmiControl service.
+ onReceiveCommand((HdmiCecMessage) msg.obj);
+ break;
+ case MSG_REPORT_LOGICAL_ADDRESS:
+ int deviceType = msg.arg1;
+ int logicalAddress = msg.arg2;
+ AllocateLogicalAddressCallback callback =
+ (AllocateLogicalAddressCallback) msg.obj;
+ callback.onAllocated(deviceType, logicalAddress);
+ break;
+ default:
+ Slog.i(TAG, "Unsupported message type:" + msg.what);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Add a new {@link HdmiCecDeviceInfo}. It returns old device info which has the same
+ * logical address as new device info's.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ *
+ * @param deviceInfo a new {@link HdmiCecDeviceInfo} to be added.
+ * @return {@code null} if it is new device. Otherwise, returns old {@HdmiCecDeviceInfo}
+ * that has the same logical address as new one has.
+ */
+ HdmiCecDeviceInfo addDeviceInfo(HdmiCecDeviceInfo deviceInfo) {
+ HdmiCecDeviceInfo oldDeviceInfo = getDeviceInfo(deviceInfo.getLogicalAddress());
+ if (oldDeviceInfo != null) {
+ removeDeviceInfo(deviceInfo.getLogicalAddress());
+ }
+ mDeviceInfos.append(deviceInfo.getLogicalAddress(), deviceInfo);
+ return oldDeviceInfo;
+ }
+
+ /**
+ * Remove a device info corresponding to the given {@code logicalAddress}.
+ * It returns removed {@link HdmiCecDeviceInfo} if exists.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ *
+ * @param logicalAddress logical address of device to be removed
+ * @return removed {@link HdmiCecDeviceInfo} it exists. Otherwise, returns {@code null}
+ */
+ HdmiCecDeviceInfo removeDeviceInfo(int logicalAddress) {
+ HdmiCecDeviceInfo deviceInfo = mDeviceInfos.get(logicalAddress);
+ if (deviceInfo != null) {
+ mDeviceInfos.remove(logicalAddress);
+ }
+ return deviceInfo;
+ }
+
+ /**
+ * Return a list of all {@HdmiCecDeviceInfo}.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ */
+ List<HdmiCecDeviceInfo> getDeviceInfoList() {
+ List<HdmiCecDeviceInfo> deviceInfoList = new ArrayList<HdmiCecDeviceInfo>(
+ mDeviceInfos.size());
+ for (int i = 0; i < mDeviceInfos.size(); ++i) {
+ deviceInfoList.add(mDeviceInfos.valueAt(i));
+ }
+ return deviceInfoList;
+ }
+
+ /**
+ * Return a {@link HdmiCecDeviceInfo} corresponding to the given {@code logicalAddress}.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ *
+ * @param logicalAddress logical address to be retrieved
+ * @return {@link HdmiCecDeviceInfo} matched with the given {@code logicalAddress}.
+ * Returns null if no logical address matched
+ */
+ HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) {
+ return mDeviceInfos.get(logicalAddress);
+ }
+
+ /**
+ * Add a new logical address to the device. Device's HW should be notified
+ * when a new logical address is assigned to a device, so that it can accept
+ * a command having available destinations.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ *
+ * @param newLogicalAddress a logical address to be added
+ * @return 0 on success. Otherwise, returns negative value
+ */
+ int addLogicalAddress(int newLogicalAddress) {
+ if (HdmiCec.isValidAddress(newLogicalAddress)) {
+ return nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
+ } else {
+ return -1;
+ }
+ }
+
+ /**
+ * Clear all logical addresses registered in the device.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ */
+ void clearLogicalAddress() {
+ nativeClearLogicalAddress(mNativePtr);
+ }
+
+ /**
+ * Return the physical address of the device.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ *
+ * @return CEC physical address of the device. The range of success address
+ * is between 0x0000 and 0xFFFF. If failed it returns -1
+ */
+ int getPhysicalAddress() {
+ return nativeGetPhysicalAddress(mNativePtr);
+ }
+
+ /**
+ * Return CEC version of the device.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ */
+ int getVersion() {
+ return nativeGetVersion(mNativePtr);
+ }
+
+ /**
+ * Return vendor id of the device.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ */
+ int getVendorId() {
+ return nativeGetVendorId(mNativePtr);
+ }
+
+ private void init(HdmiControlService service, long nativePtr) {
+ mIoHandler = new IoHandler(service.getServiceLooper());
+ mControlHandler = new ControlHandler(service.getServiceLooper());
+ mNativePtr = nativePtr;
+ }
+
+ private void onReceiveCommand(HdmiCecMessage message) {
+ // TODO: Handle message according to opcode type.
+
+ // 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);
+ }
+
+ 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);
+ Message message = mIoHandler.obtainMessage(MSG_SEND_CEC_COMMAND, cecMessage);
+ mIoHandler.sendMessage(message);
+ }
+
+ /**
+ * Called by native when incoming CEC message arrived.
+ */
+ private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) {
+ byte opcode = body[0];
+ byte params[] = Arrays.copyOfRange(body, 1, body.length);
+ HdmiCecMessage cecMessage = new HdmiCecMessage(srcAddress, dstAddress, opcode, params);
+
+ // Delegate message to main handler so that it handles in main thread.
+ Message message = mControlHandler.obtainMessage(
+ MSG_RECEIVE_CEC_COMMAND, cecMessage);
+ mControlHandler.sendMessage(message);
+ }
+
+ /**
+ * Called by native when a hotplug event issues.
+ */
+ private void handleHotplug(boolean connected) {
+ // TODO: Delegate event to main message handler.
}
private static native long nativeInit(HdmiCecController handler);
+ private static native int nativeSendCecCommand(long controllerPtr, int srcAddress,
+ int dstAddress, byte[] body);
+ private static native int nativeAddLogicalAddress(long controllerPtr, int logicalAddress);
+ private static native void nativeClearLogicalAddress(long controllerPtr);
+ private static native int nativeGetPhysicalAddress(long controllerPtr);
+ private static native int nativeGetVersion(long controllerPtr);
+ private static native int nativeGetVendorId(long controllerPtr);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 56c5b49..f99c717 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -18,9 +18,10 @@
import android.annotation.Nullable;
import android.content.Context;
-import android.os.Handler;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
import android.os.HandlerThread;
-import android.os.Message;
+import android.os.Looper;
import android.util.Slog;
import com.android.server.SystemService;
@@ -37,14 +38,6 @@
// and sparse call it shares a thread to handle IO operations.
private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread");
- // Main handler class to handle incoming message from each controller.
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- // TODO: Add handler for each message type.
- }
- };
-
@Nullable
private HdmiCecController mCecController;
@@ -57,14 +50,70 @@
@Override
public void onStart() {
- mCecController = HdmiCecController.create(mIoThread.getLooper(), mHandler);
+ mCecController = HdmiCecController.create(this);
if (mCecController == null) {
Slog.i(TAG, "Device does not support HDMI-CEC.");
}
- mMhlController = HdmiMhlController.create(mIoThread.getLooper(), mHandler);
+ mMhlController = HdmiMhlController.create(this);
if (mMhlController == null) {
Slog.i(TAG, "Device does not support MHL-control.");
}
}
+
+ /**
+ * Returns {@link Looper} for IO operation.
+ *
+ * <p>Declared as package-private.
+ */
+ Looper getIoLooper() {
+ return mIoThread.getLooper();
+ }
+
+ /**
+ * Returns {@link Looper} of main thread. Use this {@link Looper} instance
+ * for tasks that are running on main service thread.
+ *
+ * <p>Declared as package-private.
+ */
+ Looper getServiceLooper() {
+ return Looper.myLooper();
+ }
+
+ /**
+ * Add a new {@link FeatureAction} to the action queue.
+ *
+ * @param action {@link FeatureAction} to add
+ */
+ void addAction(FeatureAction action) {
+ // TODO: Implement this.
+ }
+
+
+ /**
+ * Remove the given {@link FeatureAction} object from the action queue.
+ *
+ * @param action {@link FeatureAction} to add
+ */
+ void removeAction(FeatureAction action) {
+ // TODO: Implement this.
+ }
+
+ /**
+ * Transmit a CEC command to CEC bus.
+ *
+ * @param command CEC command to send out
+ */
+ void sendCecCommand(HdmiCecMessage command) {
+ // TODO: Implement this.
+ }
+
+ /**
+ * Add a new {@link HdmiCecDeviceInfo} to controller.
+ *
+ * @param deviceInfo new device information object to add
+ */
+ void addDeviceInfo(HdmiCecDeviceInfo deviceInfo) {
+ // TODO: Implement this.
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
new file mode 100644
index 0000000..c84a067
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -0,0 +1,165 @@
+/*
+ * 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.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.util.Slog;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Feature action that discovers the information of a newly found logical device.
+ *
+ * This action is created when receiving <Report Physical Address>, a CEC command a newly
+ * connected HDMI-CEC device broadcasts to announce its advent. Additional commands are issued in
+ * this action to gather more information on the device such as OSD name and device vendor ID.
+ *
+ * <p>The result is made in the form of {@link HdmiCecDeviceInfo} object, and passed to service
+ * for the management through its life cycle.
+ *
+ * <p>Package-private, accessed by {@link HdmiControlService} only.
+ */
+final class NewDeviceAction extends FeatureAction {
+
+ private static final String TAG = "NewDeviceAction";
+
+ // State in which the action sent <Give OSD Name> and is waiting for <Set OSD Name>
+ // that contains the name of the device for display on screen.
+ static final int STATE_WAITING_FOR_SET_OSD_NAME = 1;
+
+ // State in which the action sent <Give Device Vendor ID> and is waiting for
+ // <Device Vendor ID> that contains the vendor ID of the device.
+ static final int STATE_WAITING_FOR_DEVICE_VENDOR_ID = 2;
+
+ private final int mDeviceLogicalAddress;
+ private final int mDevicePhysicalAddress;
+
+ private int mVendorId;
+ private String mDisplayName;
+
+ /**
+ * Constructor.
+ *
+ * @param service {@link HdmiControlService} instance
+ * @param sourceAddress logical address to be used as source address
+ * @param deviceLogicalAddress logical address of the device in interest
+ * @param devicePhysicalAddress physical address of the device in interest
+ */
+ NewDeviceAction(HdmiControlService service, int sourceAddress, int deviceLogicalAddress,
+ int devicePhysicalAddress) {
+ super(service, sourceAddress);
+ mDeviceLogicalAddress = deviceLogicalAddress;
+ mDevicePhysicalAddress = devicePhysicalAddress;
+ mVendorId = HdmiCec.UNKNOWN_VENDOR_ID;
+ }
+
+ @Override
+ public boolean start() {
+ sendCommand(
+ buildCommand(mSourceAddress, mDeviceLogicalAddress, HdmiCec.MESSAGE_GET_OSD_NAME));
+ mState = STATE_WAITING_FOR_SET_OSD_NAME;
+ addTimer(mState, TIMEOUT_MS);
+ return true;
+ }
+
+ @Override
+ public boolean processCommand(HdmiCecMessage cmd) {
+ // For the logical device in interest, we want two more pieces of information -
+ // osd name and vendor id. They are requested in sequence. In case we don't
+ // get the expected responses (either by timeout or by receiving <feature abort> command),
+ // set them to a default osd name and unknown vendor id respectively.
+ int opcode = cmd.getOpcode();
+ int src = cmd.getSource();
+ byte[] params = cmd.getParams();
+
+ if (mDeviceLogicalAddress != src) {
+ return false;
+ }
+
+ if (mState == STATE_WAITING_FOR_SET_OSD_NAME) {
+ if (opcode == HdmiCec.MESSAGE_SET_OSD_NAME) {
+ try {
+ mDisplayName = new String(params, "US-ASCII");
+ } catch (UnsupportedEncodingException e) {
+ Slog.e(TAG, "Failed to get OSD name: " + e.getMessage());
+ }
+ mState = STATE_WAITING_FOR_DEVICE_VENDOR_ID;
+ requestVendorId();
+ return true;
+ } else if (opcode == HdmiCec.MESSAGE_FEATURE_ABORT) {
+ int requestOpcode = params[1];
+ if (requestOpcode == HdmiCec.MESSAGE_SET_OSD_NAME) {
+ mState = STATE_WAITING_FOR_DEVICE_VENDOR_ID;
+ requestVendorId();
+ return true;
+ }
+ }
+ } else if (mState == STATE_WAITING_FOR_DEVICE_VENDOR_ID) {
+ if (opcode == HdmiCec.MESSAGE_DEVICE_VENDOR_ID) {
+ if (params.length == 3) {
+ mVendorId = (params[0] << 16) + (params[1] << 8) + params[2];
+ } else {
+ Slog.e(TAG, "Failed to get device vendor ID: ");
+ }
+ addDeviceInfo();
+ finish();
+ return true;
+ } else if (opcode == HdmiCec.MESSAGE_FEATURE_ABORT) {
+ int requestOpcode = params[1];
+ if (requestOpcode == HdmiCec.MESSAGE_DEVICE_VENDOR_ID) {
+ addDeviceInfo();
+ finish();
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private void requestVendorId() {
+ sendCommand(buildCommand(mSourceAddress, mDeviceLogicalAddress,
+ HdmiCec.MESSAGE_GIVE_DEVICE_VENDOR_ID));
+ addTimer(mState, TIMEOUT_MS);
+ }
+
+ private void addDeviceInfo() {
+ if (mDisplayName == null) {
+ mDisplayName = HdmiCec.getDefaultDeviceName(mDeviceLogicalAddress);
+ }
+ mService.addDeviceInfo(new HdmiCecDeviceInfo(
+ mDeviceLogicalAddress, mDevicePhysicalAddress,
+ HdmiCec.getTypeFromAddress(mDeviceLogicalAddress),
+ mVendorId, mDisplayName));
+ }
+
+ @Override
+ public void handleTimerEvent(int state) {
+ if (mState == STATE_NONE || mState != state) {
+ return;
+ }
+ if (state == STATE_WAITING_FOR_SET_OSD_NAME) {
+ // Osd name request timed out. Try vendor id
+ mState = STATE_WAITING_FOR_DEVICE_VENDOR_ID;
+ requestVendorId();
+ } else if (state == STATE_WAITING_FOR_DEVICE_VENDOR_ID) {
+ // vendor id timed out. Go ahead creating the device info what we've got so far.
+ addDeviceInfo();
+ finish();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaRouteProviderProxy.java b/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
index d314ea7..c4e2058 100644
--- a/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
@@ -36,6 +36,7 @@
import android.util.Log;
import android.util.Slog;
+import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@@ -55,13 +56,12 @@
private final String mId;
private final ComponentName mComponentName;
private final int mUserId;
+ // Interfaces declared in the manifest
+ private final ArrayList<String> mInterfaces = new ArrayList<String>();
+ private final ArrayList<RouteConnectionRecord> mConnections = new ArrayList<RouteConnectionRecord>();
+ private final Handler mHandler = new Handler();
private Intent mBindIntent;
- // Interfaces declared in the manifest
- private ArrayList<String> mInterfaces;
- private ArrayList<RouteConnectionRecord> mConnections = new ArrayList<RouteConnectionRecord>();
- private Handler mHandler = new Handler();
-
private IRouteProvider mBinder;
private boolean mRunning;
private boolean mInterested;
@@ -76,7 +76,9 @@
mId = id;
mComponentName = component;
mUserId = uid;
- mInterfaces = interfaces;
+ if (interfaces != null) {
+ mInterfaces.addAll(interfaces);
+ }
mBindIntent = new Intent(RouteProviderService.SERVICE_INTERFACE);
mBindIntent.setComponent(mComponentName);
}
@@ -202,7 +204,7 @@
if (connection != null) {
RouteConnectionRecord record = new RouteConnectionRecord(
- connection);
+ connection, mComponentName.getPackageName(), mUserId);
mConnections.add(record);
if (mRouteListener != null) {
mRouteListener.onRouteConnected(sessionId, route, request, record);
@@ -234,6 +236,19 @@
return mId;
}
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + mId + " " + this);
+ String indent = prefix + " ";
+
+ pw.println(indent + "component=" + mComponentName.toString());
+ pw.println(indent + "user id=" + mUserId);
+ pw.println(indent + "interfaces=" + mInterfaces.toString());
+ pw.println(indent + "connections=" + mConnections.toString());
+ pw.println(indent + "running=" + mRunning);
+ pw.println(indent + "interested=" + mInterested);
+ pw.println(indent + "bound=" + mBound);
+ }
+
private void updateBinding() {
if (shouldBind()) {
bind();
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index ac7f4f3..015032b 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -17,6 +17,7 @@
package com.android.server.media;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.media.routeprovider.RouteRequest;
import android.media.session.ISessionController;
import android.media.session.ISessionControllerCallback;
@@ -40,12 +41,14 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.view.KeyEvent;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@@ -57,6 +60,24 @@
public class MediaSessionRecord implements IBinder.DeathRecipient {
private static final String TAG = "MediaSessionRecord";
+ /**
+ * These are the playback states that count as currently active.
+ */
+ private static final int[] ACTIVE_STATES = {
+ PlaybackState.PLAYSTATE_FAST_FORWARDING,
+ PlaybackState.PLAYSTATE_REWINDING,
+ PlaybackState.PLAYSTATE_SKIPPING_BACKWARDS,
+ PlaybackState.PLAYSTATE_SKIPPING_FORWARDS,
+ PlaybackState.PLAYSTATE_BUFFERING,
+ PlaybackState.PLAYSTATE_CONNECTING,
+ PlaybackState.PLAYSTATE_PLAYING };
+
+ /**
+ * The length of time a session will still be considered active after
+ * pausing in ms.
+ */
+ private static final int ACTIVE_BUFFER = 30000;
+
private final MessageHandler mHandler;
private final int mPid;
@@ -72,21 +93,22 @@
new ArrayList<ISessionControllerCallback>();
private final ArrayList<RouteRequest> mRequests = new ArrayList<RouteRequest>();
- private boolean mTransportPerformerEnabled = false;
private RouteInfo mRoute;
private RouteOptions mRequest;
private RouteConnectionRecord mConnection;
// TODO define a RouteState class with relevant info
private int mRouteState;
+ private long mFlags;
// TransportPerformer fields
private MediaMetadata mMetadata;
private PlaybackState mPlaybackState;
private int mRatingType;
+ private long mLastActiveTime;
// End TransportPerformer fields
- private boolean mIsPublished = false;
+ private boolean mIsActive = false;
public MediaSessionRecord(int pid, String packageName, ISessionCallback cb, String tag,
MediaSessionService service, Handler handler) {
@@ -146,6 +168,35 @@
}
/**
+ * Get this session's flags.
+ *
+ * @return The flags for this session.
+ */
+ public long getFlags() {
+ return mFlags;
+ }
+
+ /**
+ * Check if this session has the specified flag.
+ *
+ * @param flag The flag to check.
+ * @return True if this session has that flag set, false otherwise.
+ */
+ public boolean hasFlag(int flag) {
+ return (mFlags & flag) != 0;
+ }
+
+ /**
+ * Check if this session has system priorty and should receive media buttons
+ * before any other sessions.
+ *
+ * @return True if this is a system priority session, false otherwise
+ */
+ public boolean isSystemPriority() {
+ return (mFlags & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0;
+ }
+
+ /**
* Set the selected route. This does not connect to the route, just notifies
* the app that a new route has been selected.
*
@@ -213,12 +264,36 @@
}
/**
- * Check if this session has been published by the app yet.
+ * Check if this session has been set to active by the app.
*
- * @return True if it has been published, false otherwise.
+ * @return True if the session is active, false otherwise.
*/
- public boolean isPublished() {
- return mIsPublished;
+ public boolean isActive() {
+ return mIsActive;
+ }
+
+ /**
+ * Check if the session is currently performing playback. This will also
+ * return true if the session was recently paused.
+ *
+ * @return True if the session is performing playback, false otherwise.
+ */
+ public boolean isPlaybackActive() {
+ int state = mPlaybackState == null ? 0 : mPlaybackState.getState();
+ if (isActiveState(state)) {
+ return true;
+ }
+ if (state == mPlaybackState.PLAYSTATE_PAUSED) {
+ long inactiveTime = SystemClock.uptimeMillis() - mLastActiveTime;
+ if (inactiveTime < ACTIVE_BUFFER) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isTransportControlEnabled() {
+ return hasFlag(Session.FLAG_HANDLES_TRANSPORT_CONTROLS);
}
@Override
@@ -226,6 +301,45 @@
mService.sessionDied(this);
}
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + mTag + " " + this);
+
+ final String indent = prefix + " ";
+ pw.println(indent + "pid=" + mPid);
+ pw.println(indent + "info=" + mSessionInfo.toString());
+ pw.println(indent + "published=" + mIsActive);
+ pw.println(indent + "flags=" + mFlags);
+ pw.println(indent + "rating type=" + mRatingType);
+ pw.println(indent + "controllers: " + mControllerCallbacks.size());
+ pw.println(indent + "state=" + (mPlaybackState == null ? null : mPlaybackState.toString()));
+ pw.println(indent + "metadata:" + getShortMetadataString());
+ pw.println(indent + "route requests {");
+ int size = mRequests.size();
+ for (int i = 0; i < size; i++) {
+ pw.println(indent + " " + mRequests.get(i).toString());
+ }
+ pw.println(indent + "}");
+ pw.println(indent + "route=" + (mRoute == null ? null : mRoute.toString()));
+ pw.println(indent + "connection=" + (mConnection == null ? null : mConnection.toString()));
+ pw.println(indent + "params=" + (mRequest == null ? null : mRequest.toString()));
+ }
+
+ private boolean isActiveState(int state) {
+ for (int i = 0; i < ACTIVE_STATES.length; i++) {
+ if (ACTIVE_STATES[i] == state) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private String getShortMetadataString() {
+ int fields = mMetadata == null ? 0 : mMetadata.size();
+ String title = mMetadata == null ? null : mMetadata
+ .getString(MediaMetadata.METADATA_KEY_TITLE);
+ return "size=" + fields + ", title=" + title;
+ }
+
private void onDestroy() {
mService.destroySession(this);
}
@@ -301,6 +415,34 @@
}
}
+ private PlaybackState getStateWithUpdatedPosition() {
+ PlaybackState state = mPlaybackState;
+ long duration = -1;
+ if (mMetadata != null && mMetadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
+ duration = mMetadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
+ }
+ PlaybackState result = null;
+ if (state != null) {
+ if (state.getState() == PlaybackState.PLAYSTATE_PLAYING
+ || state.getState() == PlaybackState.PLAYSTATE_FAST_FORWARDING
+ || state.getState() == PlaybackState.PLAYSTATE_REWINDING) {
+ long updateTime = state.getLastPositionUpdateTime();
+ if (updateTime > 0) {
+ long position = (long) (state.getRate()
+ * (SystemClock.elapsedRealtime() - updateTime)) + state.getPosition();
+ if (duration >= 0 && position > duration) {
+ position = duration;
+ } else if (position < 0) {
+ position = 0;
+ }
+ result = new PlaybackState(state);
+ result.setState(state.getState(), position, state.getRate());
+ }
+ }
+ }
+ return result == null ? state : result;
+ }
+
private final RouteConnectionRecord.Listener mConnectionListener
= new RouteConnectionRecord.Listener() {
@Override
@@ -333,12 +475,21 @@
}
@Override
- public void publish() {
- mIsPublished = true; // TODO push update to service
+ public void setActive(boolean active) {
+ mIsActive = active;
+ mService.updateSession(MediaSessionRecord.this);
+ mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
}
+
@Override
- public void setTransportPerformerEnabled() {
- mTransportPerformerEnabled = true;
+ public void setFlags(int flags) {
+ if ((flags & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
+ int pid = getCallingPid();
+ int uid = getCallingUid();
+ mService.enforcePhoneStatePermission(pid, uid);
+ }
+ mFlags = flags;
+ mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
}
@Override
@@ -349,7 +500,13 @@
@Override
public void setPlaybackState(PlaybackState state) {
+ int oldState = mPlaybackState == null ? 0 : mPlaybackState.getState();
+ int newState = state == null ? 0 : state.getState();
+ if (isActiveState(oldState) && newState == PlaybackState.PLAYSTATE_PAUSED) {
+ mLastActiveTime = SystemClock.elapsedRealtime();
+ }
mPlaybackState = state;
+ mService.onSessionPlaystateChange(MediaSessionRecord.this, oldState, newState);
mHandler.post(MessageHandler.MSG_UPDATE_PLAYBACK_STATE);
}
@@ -603,7 +760,7 @@
@Override
public PlaybackState getPlaybackState() {
- return mPlaybackState;
+ return getStateWithUpdatedPosition();
}
@Override
@@ -613,7 +770,7 @@
@Override
public boolean isTransportControlEnabled() {
- return mTransportPerformerEnabled;
+ return MediaSessionRecord.this.isTransportControlEnabled();
}
@Override
@@ -629,6 +786,7 @@
private static final int MSG_SEND_EVENT = 4;
private static final int MSG_UPDATE_ROUTE_FILTERS = 5;
private static final int MSG_SEND_COMMAND = 6;
+ private static final int MSG_UPDATE_SESSION_STATE = 7;
public MessageHandler(Looper looper) {
super(looper);
@@ -653,6 +811,9 @@
(Pair<RouteCommand, ResultReceiver>) msg.obj;
pushRouteCommand(cmd.first, cmd.second);
break;
+ case MSG_UPDATE_SESSION_STATE:
+ // TODO add session state
+ break;
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index bc91370..fb858fc 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -16,41 +16,58 @@
package com.android.server.media;
+import android.Manifest;
+import android.app.ActivityManager;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.media.routeprovider.RouteRequest;
import android.media.session.ISession;
import android.media.session.ISessionCallback;
+import android.media.session.ISessionController;
import android.media.session.ISessionManager;
+import android.media.session.PlaybackState;
import android.media.session.RouteInfo;
import android.media.session.RouteOptions;
import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import com.android.server.SystemService;
+import com.android.server.Watchdog;
+import com.android.server.Watchdog.Monitor;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
/**
* System implementation of MediaSessionManager
*/
-public class MediaSessionService extends SystemService {
+public class MediaSessionService extends SystemService implements Monitor {
private static final String TAG = "MediaSessionService";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final SessionManagerImpl mSessionManagerImpl;
private final MediaRouteProviderWatcher mRouteProviderWatcher;
+ private final MediaSessionStack mPriorityStack;
- private final ArrayList<MediaSessionRecord> mSessions
- = new ArrayList<MediaSessionRecord>();
+ private final ArrayList<MediaSessionRecord> mRecords = new ArrayList<MediaSessionRecord>();
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;
+
// Used to keep track of the current request to show routes for a specific
// session so we drop late callbacks properly.
private int mShowRoutesRequestId = 0;
@@ -63,12 +80,14 @@
mSessionManagerImpl = new SessionManagerImpl();
mRouteProviderWatcher = new MediaRouteProviderWatcher(context, mProviderWatcherCallback,
mHandler, context.getUserId());
+ mPriorityStack = new MediaSessionStack();
}
@Override
public void onStart() {
publishBinderService(Context.MEDIA_SESSION_SERVICE, mSessionManagerImpl);
mRouteProviderWatcher.start();
+ Watchdog.getInstance().addMonitor(this);
}
/**
@@ -114,20 +133,55 @@
}
}
+ public void updateSession(MediaSessionRecord record) {
+ synchronized (mLock) {
+ mPriorityStack.onSessionStateChange(record);
+ if (record.isSystemPriority()) {
+ if (record.isActive()) {
+ if (mPrioritySession != null) {
+ Log.w(TAG, "Replacing existing priority session with a new session");
+ }
+ mPrioritySession = record;
+ } else {
+ if (mPrioritySession == record) {
+ mPrioritySession = null;
+ }
+ }
+ }
+ }
+ }
+
+ public void onSessionPlaystateChange(MediaSessionRecord record, int oldState, int newState) {
+ synchronized (mLock) {
+ mPriorityStack.onPlaystateChange(record, oldState, newState);
+ }
+ }
+
+ @Override
+ public void monitor() {
+ synchronized (mLock) {
+ // Check for deadlock
+ }
+ }
+
void sessionDied(MediaSessionRecord session) {
- synchronized (mSessions) {
+ synchronized (mLock) {
destroySessionLocked(session);
}
}
void destroySession(MediaSessionRecord session) {
- synchronized (mSessions) {
+ synchronized (mLock) {
destroySessionLocked(session);
}
}
private void destroySessionLocked(MediaSessionRecord session) {
- mSessions.remove(session);
+ mRecords.remove(session);
+ mPriorityStack.removeSession(session);
+ if (session == mPrioritySession) {
+ mPrioritySession = null;
+ }
}
private void enforcePackageName(String packageName, int uid) {
@@ -144,8 +198,64 @@
throw new IllegalArgumentException("packageName is not owned by the calling process");
}
+ protected void enforcePhoneStatePermission(int pid, int uid) {
+ if (getContext().checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Must hold the MODIFY_PHONE_STATE permission.");
+ }
+ }
+
+ /**
+ * Checks a caller's authorization to register an IRemoteControlDisplay.
+ * Authorization is granted if one of the following is true:
+ * <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>
+ * </ul>
+ */
+ private void enforceMediaPermissions(ComponentName compName, int pid, int uid) {
+ if (getContext()
+ .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
+ != PackageManager.PERMISSION_GRANTED
+ && !isEnabledNotificationListener(compName)) {
+ throw new SecurityException("Missing permission to control media.");
+ }
+ }
+
+ private boolean isEnabledNotificationListener(ComponentName compName) {
+ if (compName != null) {
+ final int currentUser = ActivityManager.getCurrentUser();
+ final String enabledNotifListeners = Settings.Secure.getStringForUser(
+ getContext().getContentResolver(),
+ Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+ currentUser);
+ if (enabledNotifListeners != null) {
+ final String[] components = enabledNotifListeners.split(":");
+ for (int i = 0; i < components.length; i++) {
+ final ComponentName component =
+ ComponentName.unflattenFromString(components[i]);
+ if (component != null) {
+ if (compName.equals(component)) {
+ if (DEBUG) {
+ Log.d(TAG, "ok to get sessions: " + component +
+ " is authorized notification listener");
+ }
+ return true;
+ }
+ }
+ }
+ }
+ if (DEBUG) {
+ Log.d(TAG, "not ok to get sessions, " + compName +
+ " is not in list of ENABLED_NOTIFICATION_LISTENERS");
+ }
+ }
+ return false;
+ }
+
private MediaSessionRecord createSessionInternal(int pid, String packageName,
- ISessionCallback cb, String tag) {
+ ISessionCallback cb, String tag, boolean forCalls) {
synchronized (mLock) {
return createSessionLocked(pid, packageName, cb, tag);
}
@@ -160,15 +270,24 @@
} catch (RemoteException e) {
throw new RuntimeException("Media Session owner died prematurely.", e);
}
- synchronized (mSessions) {
- mSessions.add(session);
- }
+ mRecords.add(session);
+ mPriorityStack.addSession(session);
if (DEBUG) {
Log.d(TAG, "Created session for package " + packageName + " with tag " + tag);
}
return session;
}
+ private int findIndexOfSessionForIdLocked(String sessionId) {
+ for (int i = mRecords.size() - 1; i >= 0; i--) {
+ MediaSessionRecord session = mRecords.get(i);
+ if (TextUtils.equals(session.getSessionInfo().getId(), sessionId)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
private MediaRouteProviderProxy getProviderLocked(String providerId) {
for (int i = mProviders.size() - 1; i >= 0; i--) {
MediaRouteProviderProxy provider = mProviders.get(i);
@@ -179,14 +298,9 @@
return null;
}
- private int findIndexOfSessionForIdLocked(String sessionId) {
- for (int i = mSessions.size() - 1; i >= 0; i--) {
- MediaSessionRecord session = mSessions.get(i);
- if (TextUtils.equals(session.getSessionInfo().getId(), sessionId)) {
- return i;
- }
- }
- return -1;
+ private boolean isSessionDiscoverable(MediaSessionRecord record) {
+ // TODO probably want to check more than if it's published.
+ return record.isActive();
}
private MediaRouteProviderWatcher.Callback mProviderWatcherCallback
@@ -220,7 +334,7 @@
synchronized (mLock) {
int index = findIndexOfSessionForIdLocked(sessionId);
if (index != -1 && routes != null && routes.size() > 0) {
- MediaSessionRecord record = mSessions.get(index);
+ MediaSessionRecord record = mRecords.get(index);
record.selectRoute(routes.get(0));
}
}
@@ -232,7 +346,7 @@
synchronized (mLock) {
int index = findIndexOfSessionForIdLocked(sessionId);
if (index != -1) {
- MediaSessionRecord session = mSessions.get(index);
+ MediaSessionRecord session = mRecords.get(index);
session.setRouteConnected(route, options.getConnectionOptions(), connection);
}
}
@@ -254,11 +368,76 @@
if (cb == null) {
throw new IllegalArgumentException("Controller callback cannot be null");
}
- return createSessionInternal(pid, packageName, cb, tag).getSessionBinder();
+ return createSessionInternal(pid, packageName, cb, tag, false).getSessionBinder();
} finally {
Binder.restoreCallingIdentity(token);
}
}
+
+ @Override
+ public List<IBinder> getSessions(ComponentName componentName) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+
+ try {
+ if (componentName != null) {
+ // If they gave us a component name verify they own the
+ // package
+ enforcePackageName(componentName.getPackageName(), uid);
+ }
+ // Then check if they have the permissions or their component is
+ // allowed
+ enforceMediaPermissions(componentName, pid, uid);
+ ArrayList<IBinder> binders = new ArrayList<IBinder>();
+ synchronized (mLock) {
+ ArrayList<MediaSessionRecord> records = mPriorityStack
+ .getActiveSessions();
+ int size = records.size();
+ for (int i = 0; i < size; i++) {
+ binders.add(records.get(i).getControllerBinder().asBinder());
+ }
+ }
+ return binders;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
+ if (getContext().checkCallingOrSelfPermission(Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump MediaSessionService from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ pw.println("MEDIA SESSION SERVICE (dumpsys media_session)");
+ pw.println();
+
+ synchronized (mLock) {
+ pw.println("Session for calls:" + mPrioritySession);
+ if (mPrioritySession != null) {
+ mPrioritySession.dump(pw, "");
+ }
+ int count = mRecords.size();
+ pw.println(count + " Sessions:");
+ for (int i = 0; i < count; i++) {
+ mRecords.get(i).dump(pw, "");
+ pw.println();
+ }
+ mPriorityStack.dumpLocked(pw, "");
+
+ pw.println("Providers:");
+ count = mProviders.size();
+ for (int i = 0; i < count; i++) {
+ MediaRouteProviderProxy provider = mProviders.get(i);
+ provider.dump(pw, "");
+ }
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
new file mode 100644
index 0000000..f9f004d
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -0,0 +1,267 @@
+/*
+ * 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.media;
+
+import android.media.session.PlaybackState;
+import android.media.session.Session;
+import android.text.TextUtils;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Keeps track of media sessions and their priority for notifications, media
+ * button routing, etc.
+ */
+public class MediaSessionStack {
+ /**
+ * These are states that usually indicate the user took an action and should
+ * bump priority regardless of the old state.
+ */
+ private static final int[] ALWAYS_PRIORITY_STATES = {
+ PlaybackState.PLAYSTATE_FAST_FORWARDING,
+ PlaybackState.PLAYSTATE_REWINDING,
+ PlaybackState.PLAYSTATE_SKIPPING_BACKWARDS,
+ PlaybackState.PLAYSTATE_SKIPPING_FORWARDS };
+ /**
+ * These are states that usually indicate the user took an action if they
+ * were entered from a non-priority state.
+ */
+ private static final int[] TRANSITION_PRIORITY_STATES = {
+ PlaybackState.PLAYSTATE_BUFFERING,
+ PlaybackState.PLAYSTATE_CONNECTING,
+ PlaybackState.PLAYSTATE_PLAYING };
+
+ private final ArrayList<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
+
+ private MediaSessionRecord mCachedButtonReceiver;
+ private MediaSessionRecord mCachedDefault;
+ private ArrayList<MediaSessionRecord> mCachedActiveList;
+ private ArrayList<MediaSessionRecord> mCachedTransportControlList;
+
+ /**
+ * Add a record to the priority tracker.
+ *
+ * @param record The record to add.
+ */
+ public void addSession(MediaSessionRecord record) {
+ mSessions.add(record);
+ clearCache();
+ }
+
+ /**
+ * Remove a record from the priority tracker.
+ *
+ * @param record The record to remove.
+ */
+ public void removeSession(MediaSessionRecord record) {
+ mSessions.remove(record);
+ clearCache();
+ }
+
+ /**
+ * Notify the priority tracker that a session's state changed.
+ *
+ * @param record The record that changed.
+ * @param oldState Its old playback state.
+ * @param newState Its new playback state.
+ */
+ public void onPlaystateChange(MediaSessionRecord record, int oldState, int newState) {
+ if (shouldUpdatePriority(oldState, newState)) {
+ mSessions.remove(record);
+ mSessions.add(0, record);
+ clearCache();
+ }
+ }
+
+ /**
+ * Handle any stack changes that need to occur in response to a session
+ * state change. TODO add the old and new session state as params
+ *
+ * @param record The record that changed.
+ */
+ public void onSessionStateChange(MediaSessionRecord record) {
+ // For now just clear the cache. Eventually we'll selectively clear
+ // depending on what changed.
+ clearCache();
+ }
+
+ /**
+ * Get the current priority sorted list of active sessions. The most
+ * important session is at index 0 and the least important at size - 1.
+ *
+ * @return All the active sessions in priority order.
+ */
+ public ArrayList<MediaSessionRecord> getActiveSessions() {
+ if (mCachedActiveList == null) {
+ mCachedActiveList = getPriorityListLocked(true, 0);
+ }
+ return mCachedActiveList;
+ }
+
+ /**
+ * Get the current priority sorted list of active sessions that use
+ * transport controls. The most important session is at index 0 and the
+ * least important at size -1.
+ *
+ * @return All the active sessions that handle transport controls in
+ * priority order.
+ */
+ public ArrayList<MediaSessionRecord> getTransportControlSessions() {
+ if (mCachedTransportControlList == null) {
+ mCachedTransportControlList = getPriorityListLocked(true,
+ Session.FLAG_HANDLES_TRANSPORT_CONTROLS);
+ }
+ return mCachedTransportControlList;
+ }
+
+ /**
+ * Get the highest priority active session.
+ *
+ * @return The current highest priority session or null.
+ */
+ public MediaSessionRecord getDefaultSession() {
+ if (mCachedDefault != null) {
+ return mCachedDefault;
+ }
+ ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0);
+ if (records.size() > 0) {
+ return records.get(0);
+ }
+ return null;
+ }
+
+ /**
+ * Get the highest priority session that can handle media buttons.
+ *
+ * @return The default media button session or null.
+ */
+ public MediaSessionRecord getDefaultMediaButtonSession() {
+ if (mCachedButtonReceiver != null) {
+ return mCachedButtonReceiver;
+ }
+ ArrayList<MediaSessionRecord> records = getPriorityListLocked(true,
+ Session.FLAG_HANDLES_MEDIA_BUTTONS);
+ if (records.size() > 0) {
+ mCachedButtonReceiver = records.get(0);
+ }
+ return mCachedButtonReceiver;
+ }
+
+ public void dumpLocked(PrintWriter pw, String prefix) {
+ ArrayList<MediaSessionRecord> sortedSessions = getPriorityListLocked(false, 0);
+ int count = sortedSessions.size();
+ pw.println(prefix + "Sessions Stack - have " + count + " sessions:");
+ String indent = prefix + " ";
+ for (int i = 0; i < count; i++) {
+ MediaSessionRecord record = sortedSessions.get(i);
+ record.dump(pw, indent);
+ pw.println();
+ }
+ }
+
+ /**
+ * Get a priority sorted list of sessions. Can filter to only return active
+ * sessions or sessions with specific flags.
+ *
+ * @param activeOnly True to only return active sessions, false to return
+ * all sessions.
+ * @param withFlags Only return sessions with all the specified flags set. 0
+ * returns all sessions.
+ * @return The priority sorted list of sessions.
+ */
+ private ArrayList<MediaSessionRecord> getPriorityListLocked(boolean activeOnly, int withFlags) {
+ ArrayList<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>();
+ int lastLocalIndex = 0;
+ int lastActiveIndex = 0;
+ int lastPublishedIndex = 0;
+
+ int size = mSessions.size();
+ for (int i = 0; i < size; i++) {
+ final MediaSessionRecord session = mSessions.get(i);
+
+ if ((session.getFlags() & withFlags) != withFlags) {
+ continue;
+ }
+ if (!session.isActive()) {
+ if (!activeOnly) {
+ // If we're getting unpublished as well always put them at
+ // the end
+ result.add(session);
+ }
+ continue;
+ }
+
+ if (session.isSystemPriority()) {
+ // System priority sessions are special and always go at the
+ // front. We expect there to only be one of these at a time.
+ result.add(0, session);
+ lastLocalIndex++;
+ lastActiveIndex++;
+ lastPublishedIndex++;
+ } else if (session.isPlaybackActive()) {
+ // TODO replace getRoute() == null with real local route check
+ if(session.getRoute() == null) {
+ // Active local sessions get top priority
+ result.add(lastLocalIndex, session);
+ lastLocalIndex++;
+ lastActiveIndex++;
+ lastPublishedIndex++;
+ } else {
+ // Then active remote sessions
+ result.add(lastActiveIndex, session);
+ lastActiveIndex++;
+ lastPublishedIndex++;
+ }
+ } else {
+ // inactive sessions go at the end in order of whoever last did
+ // something.
+ result.add(lastPublishedIndex, session);
+ lastPublishedIndex++;
+ }
+ }
+
+ return result;
+ }
+
+ private boolean shouldUpdatePriority(int oldState, int newState) {
+ if (containsState(newState, ALWAYS_PRIORITY_STATES)) {
+ return true;
+ }
+ if (!containsState(oldState, TRANSITION_PRIORITY_STATES)
+ && containsState(newState, TRANSITION_PRIORITY_STATES)) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean containsState(int state, int[] states) {
+ for (int i = 0; i < states.length; i++) {
+ if (states[i] == state) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void clearCache() {
+ mCachedDefault = null;
+ mCachedButtonReceiver = null;
+ mCachedActiveList = null;
+ mCachedTransportControlList = null;
+ }
+}
diff --git a/services/core/java/com/android/server/media/RouteConnectionRecord.java b/services/core/java/com/android/server/media/RouteConnectionRecord.java
index 8da0f95..90ddf29 100644
--- a/services/core/java/com/android/server/media/RouteConnectionRecord.java
+++ b/services/core/java/com/android/server/media/RouteConnectionRecord.java
@@ -29,10 +29,14 @@
public class RouteConnectionRecord {
private static final String TAG = "RouteConnRecord";
private final IRouteConnection mBinder;
+ private final String mPackageName;
+ private final int mUid;
private Listener mListener;
- public RouteConnectionRecord(IRouteConnection binder) {
+ public RouteConnectionRecord(IRouteConnection binder, String packageName, int uid) {
mBinder = binder;
+ mPackageName = packageName;
+ mUid = uid;
}
/**
@@ -89,6 +93,12 @@
}
}
+ @Override
+ public String toString() {
+ return "RouteConnection { binder=" + mBinder.toString() + ", package=" + mPackageName
+ + ", uid=" + mUid + "}";
+ }
+
/**
* Listener to receive updates from the provider for this connection.
*/
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 5567944..d074565 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import android.content.ComponentName;
import android.content.Context;
import android.net.Uri;
import android.os.Handler;
@@ -28,31 +29,31 @@
import android.service.notification.ConditionProviderService;
import android.service.notification.IConditionListener;
import android.service.notification.IConditionProvider;
+import android.service.notification.ZenModeConfig;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.R;
-import libcore.util.Objects;
-
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
public class ConditionProviders extends ManagedServices {
+ private static final Condition[] NO_CONDITIONS = new Condition[0];
private final ZenModeHelper mZenModeHelper;
private final ArrayMap<IBinder, IConditionListener> mListeners
= new ArrayMap<IBinder, IConditionListener>();
- private final ArrayMap<Uri, ManagedServiceInfo> mConditions
- = new ArrayMap<Uri, ManagedServiceInfo>();
-
- private Uri mCurrentConditionId;
+ private final ArrayList<ConditionRecord> mRecords = new ArrayList<ConditionRecord>();
public ConditionProviders(Context context, Handler handler,
UserProfiles userProfiles, ZenModeHelper zenModeHelper) {
super(context, handler, new Object(), userProfiles);
mZenModeHelper = zenModeHelper;
mZenModeHelper.addCallback(new ZenModeHelperCallback());
+ loadZenConfig();
}
@Override
@@ -71,20 +72,13 @@
public void dump(PrintWriter pw) {
super.dump(pw);
synchronized(mMutex) {
- pw.print(" mCurrentConditionId="); pw.println(mCurrentConditionId);
pw.print(" mListeners("); pw.print(mListeners.size()); pw.println("):");
for (int i = 0; i < mListeners.size(); i++) {
pw.print(" "); pw.println(mListeners.keyAt(i));
}
- pw.print(" mConditions("); pw.print(mConditions.size()); pw.println("):");
- for (int i = 0; i < mConditions.size(); i++) {
- pw.print(" "); pw.print(mConditions.keyAt(i));
- final ManagedServiceInfo info = mConditions.valueAt(i);
- pw.print(" -> "); pw.print(info.component);
- if (!mServices.contains(info)) {
- pw.print(" (orphan)");
- }
- pw.println();
+ pw.print(" mRecords("); pw.print(mRecords.size()); pw.println("):");
+ for (int i = 0; i < mRecords.size(); i++) {
+ pw.print(" "); pw.println(mRecords.get(i));
}
}
}
@@ -95,29 +89,49 @@
}
@Override
- protected void onServiceAdded(IInterface service) {
- Slog.d(TAG, "onServiceAdded " + service);
- final IConditionProvider provider = (IConditionProvider) service;
+ protected void onServiceAdded(ManagedServiceInfo info) {
+ Slog.d(TAG, "onServiceAdded " + info);
+ final IConditionProvider provider = provider(info);
try {
provider.onConnected();
} catch (RemoteException e) {
// we tried
}
+ synchronized (mMutex) {
+ final int N = mRecords.size();
+ for(int i = 0; i < N; i++) {
+ final ConditionRecord r = mRecords.get(i);
+ if (!r.component.equals(info.component)) continue;
+ r.info = info;
+ // if automatic, auto-subscribe
+ if (r.isAutomatic) {
+ try {
+ final Uri id = r.id;
+ if (DEBUG) Slog.d(TAG, "Auto-subscribing to configured condition " + id);
+ provider.onSubscribe(id);
+ } catch (RemoteException e) {
+ // we tried
+ }
+ }
+ }
+ }
}
@Override
protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
if (removed == null) return;
- if (mCurrentConditionId != null) {
- if (removed.equals(mConditions.get(mCurrentConditionId))) {
- mCurrentConditionId = null;
+ for (int i = mRecords.size() - 1; i >= 0; i--) {
+ final ConditionRecord r = mRecords.get(i);
+ if (!r.component.equals(removed.component)) continue;
+ if (r.isManual) {
+ // removing the current manual condition, exit zen
mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF);
}
- }
- for (int i = mConditions.size() - 1; i >= 0; i--) {
- if (removed.equals(mConditions.valueAt(i))) {
- mConditions.removeAt(i);
+ if (r.isAutomatic) {
+ // removing an automatic condition, exit zen
+ mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF);
}
+ mRecords.remove(i);
}
}
@@ -127,14 +141,15 @@
}
}
- public void requestZenModeConditions(IConditionListener callback, boolean requested) {
+ public void requestZenModeConditions(IConditionListener callback, int relevance) {
synchronized(mMutex) {
if (DEBUG) Slog.d(TAG, "requestZenModeConditions callback=" + callback
- + " requested=" + requested);
+ + " relevance=" + Condition.relevanceToString(relevance));
if (callback == null) return;
- if (requested) {
+ relevance = relevance & (Condition.FLAG_RELEVANT_NOW | Condition.FLAG_RELEVANT_ALWAYS);
+ if (relevance != 0) {
mListeners.put(callback.asBinder(), callback);
- requestConditionsLocked(Condition.FLAG_RELEVANT_NOW);
+ requestConditionsLocked(relevance);
} else {
mListeners.remove(callback.asBinder());
if (mListeners.isEmpty()) {
@@ -144,25 +159,51 @@
}
}
+ private Condition[] validateConditions(String pkg, Condition[] conditions) {
+ if (conditions == null || conditions.length == 0) return null;
+ final int N = conditions.length;
+ final ArrayMap<Uri, Condition> valid = new ArrayMap<Uri, Condition>(N);
+ for (int i = 0; i < N; i++) {
+ final Uri id = conditions[i].id;
+ if (!Condition.isValidId(id, pkg)) {
+ Slog.w(TAG, "Ignoring condition from " + pkg + " for invalid id: " + id);
+ continue;
+ }
+ if (valid.containsKey(id)) {
+ Slog.w(TAG, "Ignoring condition from " + pkg + " for duplicate id: " + id);
+ continue;
+ }
+ valid.put(id, conditions[i]);
+ }
+ if (valid.size() == 0) return null;
+ if (valid.size() == N) return conditions;
+ final Condition[] rt = new Condition[valid.size()];
+ for (int i = 0; i < rt.length; i++) {
+ rt[i] = valid.valueAt(i);
+ }
+ return rt;
+ }
+
+ private ConditionRecord getRecordLocked(Uri id, ComponentName component) {
+ final int N = mRecords.size();
+ for (int i = 0; i < N; i++) {
+ final ConditionRecord r = mRecords.get(i);
+ if (r.id.equals(id) && r.component.equals(component)) {
+ return r;
+ }
+ }
+ final ConditionRecord r = new ConditionRecord(id, component);
+ mRecords.add(r);
+ return r;
+ }
+
public void notifyConditions(String pkg, ManagedServiceInfo info, Condition[] conditions) {
synchronized(mMutex) {
if (DEBUG) Slog.d(TAG, "notifyConditions pkg=" + pkg + " info=" + info + " conditions="
+ (conditions == null ? null : Arrays.asList(conditions)));
+ conditions = validateConditions(pkg, conditions);
if (conditions == null || conditions.length == 0) return;
final int N = conditions.length;
- boolean valid = true;
- for (int i = 0; i < N; i++) {
- final Uri id = conditions[i].id;
- if (!Condition.isValidId(id, pkg)) {
- Slog.w(TAG, "Ignoring conditions from " + pkg + " for invalid id: " + id);
- valid = false;
- }
- }
- if (!valid) return;
-
- for (int i = 0; i < N; i++) {
- mConditions.put(conditions[i].id, info);
- }
for (IConditionListener listener : mListeners.values()) {
try {
listener.onConditionsReceived(conditions);
@@ -170,62 +211,154 @@
Slog.w(TAG, "Error sending conditions to listener " + listener, e);
}
}
- if (mCurrentConditionId != null) {
- for (int i = 0; i < N; i++) {
- final Condition c = conditions[i];
- if (!c.id.equals(mCurrentConditionId)) continue;
- if (c.state == Condition.STATE_TRUE || c.state == Condition.STATE_ERROR) {
- triggerExitLocked(c.state == Condition.STATE_ERROR);
- return;
+ for (int i = 0; i < N; i++) {
+ final Condition c = conditions[i];
+ final ConditionRecord r = getRecordLocked(c.id, info.component);
+ r.info = info;
+ r.condition = c;
+ // if manual, exit zen if false (or failed)
+ if (r.isManual) {
+ if (c.state == Condition.STATE_FALSE || c.state == Condition.STATE_ERROR) {
+ final boolean failed = c.state == Condition.STATE_ERROR;
+ if (failed) {
+ Slog.w(TAG, "Exit zen: manual condition failed: " + c);
+ } else if (DEBUG) {
+ Slog.d(TAG, "Exit zen: manual condition false: " + c);
+ }
+ mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
+ unsubscribeLocked(r);
+ r.isManual = false;
+ }
+ }
+ // if automatic, exit zen if false (or failed), enter zen if true
+ if (r.isAutomatic) {
+ if (c.state == Condition.STATE_FALSE || c.state == Condition.STATE_ERROR) {
+ final boolean failed = c.state == Condition.STATE_ERROR;
+ if (failed) {
+ Slog.w(TAG, "Exit zen: automatic condition failed: " + c);
+ } else if (DEBUG) {
+ Slog.d(TAG, "Exit zen: automatic condition false: " + c);
+ }
+ mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
+ } else if (c.state == Condition.STATE_TRUE) {
+ Slog.d(TAG, "Enter zen: automatic condition true: " + c);
+ mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_ON);
}
}
}
}
}
- private void triggerExitLocked(boolean error) {
- if (error) {
- Slog.w(TAG, "Zen mode exit condition failed");
- } else if (DEBUG) {
- Slog.d(TAG, "Zen mode exit condition triggered");
- }
- mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
- unsubscribeLocked(mCurrentConditionId);
- mCurrentConditionId = null;
- }
-
public void setZenModeCondition(Uri conditionId) {
+ if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId);
synchronized(mMutex) {
- if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId);
- if (Objects.equal(mCurrentConditionId, conditionId)) return;
-
- if (mCurrentConditionId != null) {
- unsubscribeLocked(mCurrentConditionId);
- }
- if (conditionId != null) {
- final ManagedServiceInfo info = mConditions.get(conditionId);
- final IConditionProvider provider = provider(info);
- if (provider == null) return;
- try {
- provider.onSubscribe(conditionId);
- } catch (RemoteException e) {
- Slog.w(TAG, "Error subscribing to " + conditionId
- + " from " + info.component, e);
+ final int N = mRecords.size();
+ for (int i = 0; i < N; i++) {
+ final ConditionRecord r = mRecords.get(i);
+ final boolean idEqual = r.id.equals(conditionId);
+ if (r.isManual && !idEqual) {
+ // was previous manual condition, unsubscribe
+ unsubscribeLocked(r);
+ r.isManual = false;
+ } else if (idEqual && !r.isManual) {
+ // is new manual condition, subscribe
+ subscribeLocked(r);
+ r.isManual = true;
}
}
- mCurrentConditionId = conditionId;
}
}
- private void unsubscribeLocked(Uri conditionId) {
- final ManagedServiceInfo info = mConditions.get(mCurrentConditionId);
- final IConditionProvider provider = provider(info);
- if (provider == null) return;
- try {
- provider.onUnsubscribe(conditionId);
- } catch (RemoteException e) {
- Slog.w(TAG, "Error unsubscribing to " + conditionId + " from " + info.component, e);
+ private void subscribeLocked(ConditionRecord r) {
+ if (DEBUG) Slog.d(TAG, "subscribeLocked " + r);
+ final IConditionProvider provider = provider(r);
+ if (provider == null) {
+ Slog.w(TAG, "subscribeLocked: no provider");
+ return;
}
+ try {
+ provider.onSubscribe(r.id);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error subscribing to " + r, e);
+ }
+ }
+
+ private static <T> ArraySet<T> safeSet(T... items) {
+ final ArraySet<T> rt = new ArraySet<T>();
+ if (items == null || items.length == 0) return rt;
+ final int N = items.length;
+ for (int i = 0; i < N; i++) {
+ final T item = items[i];
+ if (item != null) {
+ rt.add(item);
+ }
+ }
+ return rt;
+ }
+
+ public void setAutomaticZenModeConditions(Uri[] conditionIds) {
+ setAutomaticZenModeConditions(conditionIds, true /*save*/);
+ }
+
+ private void setAutomaticZenModeConditions(Uri[] conditionIds, boolean save) {
+ if (DEBUG) Slog.d(TAG, "setAutomaticZenModeConditions "
+ + (conditionIds == null ? null : Arrays.asList(conditionIds)));
+ synchronized(mMutex) {
+ final ArraySet<Uri> newIds = safeSet(conditionIds);
+ final int N = mRecords.size();
+ boolean changed = false;
+ for (int i = 0; i < N; i++) {
+ final ConditionRecord r = mRecords.get(i);
+ final boolean automatic = newIds.contains(r.id);
+ if (!r.isAutomatic && automatic) {
+ // subscribe to new automatic
+ subscribeLocked(r);
+ r.isAutomatic = true;
+ changed = true;
+ } else if (r.isAutomatic && !automatic) {
+ // unsubscribe from old automatic
+ unsubscribeLocked(r);
+ r.isAutomatic = false;
+ changed = true;
+ }
+ }
+ if (save && changed) {
+ saveZenConfigLocked();
+ }
+ }
+ }
+
+ public Condition[] getAutomaticZenModeConditions() {
+ synchronized(mMutex) {
+ final int N = mRecords.size();
+ ArrayList<Condition> rt = null;
+ for (int i = 0; i < N; i++) {
+ final ConditionRecord r = mRecords.get(i);
+ if (r.isAutomatic && r.condition != null) {
+ if (rt == null) rt = new ArrayList<Condition>();
+ rt.add(r.condition);
+ }
+ }
+ return rt == null ? NO_CONDITIONS : rt.toArray(new Condition[rt.size()]);
+ }
+ }
+
+ private void unsubscribeLocked(ConditionRecord r) {
+ if (DEBUG) Slog.d(TAG, "unsubscribeLocked " + r);
+ final IConditionProvider provider = provider(r);
+ if (provider == null) {
+ Slog.w(TAG, "unsubscribeLocked: no provider");
+ return;
+ }
+ try {
+ provider.onUnsubscribe(r.id);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error unsubscribing to " + r, e);
+ }
+ }
+
+ private static IConditionProvider provider(ConditionRecord r) {
+ return r == null ? null : provider(r.info);
}
private static IConditionProvider provider(ManagedServiceInfo info) {
@@ -244,20 +377,99 @@
}
}
+ private void loadZenConfig() {
+ final ZenModeConfig config = mZenModeHelper.getConfig();
+ if (config == null) {
+ if (DEBUG) Slog.d(TAG, "loadZenConfig: no config");
+ return;
+ }
+ synchronized (mMutex) {
+ if (config.conditionComponents == null || config.conditionIds == null
+ || config.conditionComponents.length != config.conditionIds.length) {
+ if (DEBUG) Slog.d(TAG, "loadZenConfig: no conditions");
+ setAutomaticZenModeConditions(null, false /*save*/);
+ return;
+ }
+ final ArraySet<Uri> newIds = new ArraySet<Uri>();
+ final int N = config.conditionComponents.length;
+ for (int i = 0; i < N; i++) {
+ final ComponentName component = config.conditionComponents[i];
+ final Uri id = config.conditionIds[i];
+ if (component != null && id != null) {
+ getRecordLocked(id, component); // ensure record exists
+ newIds.add(id);
+ }
+ }
+ if (DEBUG) Slog.d(TAG, "loadZenConfig: N=" + N);
+ setAutomaticZenModeConditions(newIds.toArray(new Uri[newIds.size()]), false /*save*/);
+ }
+ }
+
+ private void saveZenConfigLocked() {
+ ZenModeConfig config = mZenModeHelper.getConfig();
+ if (config == null) return;
+ config = config.copy();
+ final ArrayList<ConditionRecord> automatic = new ArrayList<ConditionRecord>();
+ final int automaticN = mRecords.size();
+ for (int i = 0; i < automaticN; i++) {
+ final ConditionRecord r = mRecords.get(i);
+ if (r.isAutomatic) {
+ automatic.add(r);
+ }
+ }
+ if (automatic.isEmpty()) {
+ config.conditionComponents = null;
+ config.conditionIds = null;
+ } else {
+ final int N = automatic.size();
+ config.conditionComponents = new ComponentName[N];
+ config.conditionIds = new Uri[N];
+ for (int i = 0; i < N; i++) {
+ final ConditionRecord r = automatic.get(i);
+ config.conditionComponents[i] = r.component;
+ config.conditionIds[i] = r.id;
+ }
+ }
+ if (DEBUG) Slog.d(TAG, "Setting zen config to: " + config);
+ mZenModeHelper.setConfig(config);
+ }
+
private class ZenModeHelperCallback extends ZenModeHelper.Callback {
@Override
+ void onConfigChanged() {
+ loadZenConfig();
+ }
+
+ @Override
void onZenModeChanged() {
final int mode = mZenModeHelper.getZenMode();
if (mode == Global.ZEN_MODE_OFF) {
- synchronized (mMutex) {
- if (mCurrentConditionId != null) {
- if (DEBUG) Slog.d(TAG, "Zen mode off, forcing unsubscribe from "
- + mCurrentConditionId);
- unsubscribeLocked(mCurrentConditionId);
- mCurrentConditionId = null;
- }
- }
+ // ensure any manual condition is cleared
+ setZenModeCondition(null);
}
}
}
+
+ private static class ConditionRecord {
+ public final Uri id;
+ public final ComponentName component;
+ public Condition condition;
+ public ManagedServiceInfo info;
+ public boolean isAutomatic;
+ public boolean isManual;
+
+ private ConditionRecord(Uri id, ComponentName component) {
+ this.id = id;
+ this.component = component;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("ConditionRecord[id=")
+ .append(id).append(",component=").append(component);
+ if (isAutomatic) sb.append(",automatic");
+ if (isManual) sb.append(",manual");
+ return sb.append(']').toString();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 0621f58..d34b09c 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -101,7 +101,7 @@
abstract protected IInterface asInterface(IBinder binder);
- abstract protected void onServiceAdded(IInterface service);
+ abstract protected void onServiceAdded(ManagedServiceInfo info);
protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
@@ -368,11 +368,12 @@
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
boolean added = false;
+ ManagedServiceInfo info = null;
synchronized (mMutex) {
mServicesBinding.remove(servicesBindingTag);
try {
mService = asInterface(binder);
- ManagedServiceInfo info = newServiceInfo(mService, name,
+ info = newServiceInfo(mService, name,
userid, false /*isSystem*/, this, targetSdkVersion);
binder.linkToDeath(info, 0);
added = mServices.add(info);
@@ -381,7 +382,7 @@
}
}
if (added) {
- onServiceAdded(mService);
+ onServiceAdded(info);
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
index ce4c1ed..b41b478 100644
--- a/services/core/java/com/android/server/notification/NotificationDelegate.java
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -21,8 +21,7 @@
public interface NotificationDelegate {
void onSetDisabled(int status);
void onClearAll(int callingUid, int callingPid, int userId);
- void onNotificationClick(int callingUid, int callingPid,
- String pkg, String tag, int id, int userId);
+ void onNotificationClick(int callingUid, int callingPid, String key);
void onNotificationClear(int callingUid, int callingPid,
String pkg, String tag, int id, int userId);
void onNotificationError(int callingUid, int callingPid,
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6e4eb565..fce86e8 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -198,8 +198,7 @@
private final UserProfiles mUserProfiles = new UserProfiles();
private NotificationListeners mListeners;
private ConditionProviders mConditionProviders;
-
- private final NotificationUsageStats mUsageStats = new NotificationUsageStats();
+ private NotificationUsageStats mUsageStats;
private static final String EXTRA_INTERCEPT = "android.intercept";
@@ -472,6 +471,7 @@
pw.println(prefix + String.format(" defaults=0x%08x flags=0x%08x",
notification.defaults, notification.flags));
pw.println(prefix + " sound=" + notification.sound);
+ pw.println(prefix + String.format(" color=0x%08x", notification.color));
pw.println(prefix + " vibrate=" + Arrays.toString(notification.vibrate));
pw.println(prefix + String.format(" led=0x%08x onMs=%d offMs=%d",
notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
@@ -602,10 +602,20 @@
}
@Override
- public void onNotificationClick(int callingUid, int callingPid,
- String pkg, String tag, int id, int userId) {
- cancelNotification(callingUid, callingPid, pkg, tag, id, Notification.FLAG_AUTO_CANCEL,
- Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_DELEGATE_CLICK, null);
+ public void onNotificationClick(int callingUid, int callingPid, String key) {
+ synchronized (mNotificationList) {
+ EventLogTags.writeNotificationClicked(key);
+ NotificationRecord r = mNotificationsByKey.get(key);
+ if (r == null) {
+ Log.w(TAG, "No notification with key: " + key);
+ return;
+ }
+ StatusBarNotification sbn = r.sbn;
+ cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
+ sbn.getId(), Notification.FLAG_AUTO_CANCEL,
+ Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
+ REASON_DELEGATE_CLICK, null);
+ }
}
@Override
@@ -848,6 +858,7 @@
});
final File systemDir = new File(Environment.getDataDirectory(), "system");
mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
+ mUsageStats = new NotificationUsageStats(getContext());
importOldBlockDb();
@@ -1355,9 +1366,9 @@
}
@Override
- public void requestZenModeConditions(IConditionListener callback, boolean requested) {
+ public void requestZenModeConditions(IConditionListener callback, int relevance) {
enforceSystemOrSystemUI("INotificationManager.requestZenModeConditions");
- mConditionProviders.requestZenModeConditions(callback, requested);
+ mConditionProviders.requestZenModeConditions(callback, relevance);
}
@Override
@@ -1366,6 +1377,18 @@
mConditionProviders.setZenModeCondition(conditionId);
}
+ @Override
+ public void setAutomaticZenModeConditions(Uri[] conditionIds) {
+ enforceSystemOrSystemUI("INotificationManager.setAutomaticZenModeConditions");
+ mConditionProviders.setAutomaticZenModeConditions(conditionIds);
+ }
+
+ @Override
+ public Condition[] getAutomaticZenModeConditions() {
+ enforceSystemOrSystemUI("INotificationManager.getAutomaticZenModeConditions");
+ return mConditionProviders.getAutomaticZenModeConditions();
+ }
+
private void enforceSystemOrSystemUI(String message) {
if (isCallerSystem()) return;
getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
@@ -1600,7 +1623,8 @@
// Should this notification make noise, vibe, or use the LED?
final boolean canInterrupt = (score >= SCORE_INTERRUPTION_THRESHOLD) && !intercept;
- if (DBG) Slog.v(TAG, "canInterrupt=" + canInterrupt + " intercept=" + intercept);
+ 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,
@@ -2320,8 +2344,8 @@
}
@Override
- public void onServiceAdded(IInterface service) {
- final INotificationListener listener = (INotificationListener) service;
+ public void onServiceAdded(ManagedServiceInfo info) {
+ final INotificationListener listener = (INotificationListener) info.service;
final String[] keys = getActiveNotificationKeysFromListener(listener);
try {
listener.onListenerConnected(keys);
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index d9e2b91..45ab3d3 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -18,8 +18,17 @@
import com.android.server.notification.NotificationManagerService.NotificationRecord;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
import android.os.SystemClock;
import android.service.notification.StatusBarNotification;
+import android.util.Log;
import java.io.PrintWriter;
import java.util.HashMap;
@@ -37,9 +46,13 @@
* {@hide}
*/
public class NotificationUsageStats {
-
// Guarded by synchronized(this).
private final Map<String, AggregatedStats> mStats = new HashMap<String, AggregatedStats>();
+ private final SQLiteLog mSQLiteLog;
+
+ public NotificationUsageStats(Context context) {
+ mSQLiteLog = new SQLiteLog(context);
+ }
/**
* Called when a notification has been posted.
@@ -49,6 +62,7 @@
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
stats.numPostedByApp++;
}
+ mSQLiteLog.logPosted(notification);
}
/**
@@ -68,6 +82,7 @@
stats.numRemovedByApp++;
stats.collect(notification.stats);
}
+ mSQLiteLog.logRemoved(notification);
}
/**
@@ -79,6 +94,7 @@
stats.numDismissedByUser++;
stats.collect(notification.stats);
}
+ mSQLiteLog.logDismissed(notification);
}
/**
@@ -89,6 +105,7 @@
for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
stats.numClickedByUser++;
}
+ mSQLiteLog.logClicked(notification);
}
/**
@@ -146,6 +163,7 @@
for (AggregatedStats as : mStats.values()) {
as.dump(pw, indent);
}
+ mSQLiteLog.dump(pw, indent);
}
/**
@@ -274,4 +292,211 @@
'}';
}
}
+
+ private static class SQLiteLog {
+ private static final String TAG = "NotificationSQLiteLog";
+
+ // Message types passed to the background handler.
+ private static final int MSG_POST = 1;
+ private static final int MSG_CLICK = 2;
+ private static final int MSG_REMOVE = 3;
+ private static final int MSG_DISMISS = 4;
+
+ private static final String DB_NAME = "notification_log.db";
+ private static final int DB_VERSION = 1;
+
+ /** Age in ms after which events are pruned from the DB. */
+ private static final long HORIZON_MS = 7 * 24 * 60 * 60 * 1000L; // 1 week
+ /** Delay between pruning the DB. Used to throttle pruning. */
+ private static final long PRUNE_MIN_DELAY_MS = 6 * 60 * 60 * 1000L; // 6 hours
+ /** Mininum number of writes between pruning the DB. Used to throttle pruning. */
+ private static final long PRUNE_MIN_WRITES = 1024;
+
+ // Table 'log'
+ private static final String TAB_LOG = "log";
+ private static final String COL_EVENT_USER_ID = "event_user_id";
+ private static final String COL_EVENT_TYPE = "event_type";
+ private static final String COL_EVENT_TIME = "event_time_ms";
+ private static final String COL_KEY = "key";
+ private static final String COL_PKG = "pkg";
+ private static final String COL_NOTIFICATION_ID = "nid";
+ private static final String COL_TAG = "tag";
+ private static final String COL_WHEN_MS = "when_ms";
+ private static final String COL_DEFAULTS = "defaults";
+ private static final String COL_FLAGS = "flags";
+ 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 int EVENT_TYPE_POST = 1;
+ private static final int EVENT_TYPE_CLICK = 2;
+ private static final int EVENT_TYPE_REMOVE = 3;
+ private static final int EVENT_TYPE_DISMISS = 4;
+
+ private static long sLastPruneMs;
+ private static long sNumWrites;
+
+ private final SQLiteOpenHelper mHelper;
+ private final Handler mWriteHandler;
+
+ private static final long DAY_MS = 24 * 60 * 60 * 1000;
+
+ public SQLiteLog(Context context) {
+ HandlerThread backgroundThread = new HandlerThread("notification-sqlite-log",
+ android.os.Process.THREAD_PRIORITY_BACKGROUND);
+ backgroundThread.start();
+ mWriteHandler = new Handler(backgroundThread.getLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ NotificationRecord r = (NotificationRecord) msg.obj;
+ long nowMs = System.currentTimeMillis();
+ switch (msg.what) {
+ case MSG_POST:
+ writeEvent(r.sbn.getPostTime(), EVENT_TYPE_POST, r, true);
+ break;
+ case MSG_CLICK:
+ writeEvent(nowMs, EVENT_TYPE_CLICK, r, false);
+ break;
+ case MSG_REMOVE:
+ writeEvent(nowMs, EVENT_TYPE_REMOVE, r, false);
+ break;
+ case MSG_DISMISS:
+ writeEvent(nowMs, EVENT_TYPE_DISMISS, r, false);
+ break;
+ default:
+ Log.wtf(TAG, "Unknown message type: " + msg.what);
+ break;
+ }
+ }
+ };
+ mHelper = new SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TAB_LOG + " (" +
+ "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
+ COL_EVENT_USER_ID + " INT," +
+ COL_EVENT_TYPE + " INT," +
+ COL_EVENT_TIME + " INT," +
+ COL_KEY + " TEXT," +
+ COL_PKG + " TEXT," +
+ COL_NOTIFICATION_ID + " INT," +
+ COL_TAG + " TEXT," +
+ COL_WHEN_MS + " INT," +
+ COL_DEFAULTS + " INT," +
+ COL_FLAGS + " INT," +
+ COL_PRIORITY + " INT," +
+ COL_CATEGORY + " TEXT," +
+ COL_ACTION_COUNT + " INT" +
+ ")");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ db.execSQL("DROP TABLE IF EXISTS " + TAB_LOG);
+ onCreate(db);
+ }
+ };
+ }
+
+ public void logPosted(NotificationRecord notification) {
+ mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_POST, notification));
+ }
+
+ public void logClicked(NotificationRecord notification) {
+ mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_CLICK, notification));
+ }
+
+ public void logRemoved(NotificationRecord notification) {
+ mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_REMOVE, notification));
+ }
+
+ public void logDismissed(NotificationRecord notification) {
+ mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_DISMISS, notification));
+ }
+
+ public void printPostFrequencies(PrintWriter pw, String indent) {
+ SQLiteDatabase db = mHelper.getReadableDatabase();
+ long nowMs = System.currentTimeMillis();
+ String q = "SELECT " +
+ COL_EVENT_USER_ID + ", " +
+ COL_PKG + ", " +
+ // Bucket by day by looking at 'floor((nowMs - eventTimeMs) / dayMs)'
+ "CAST(((" + nowMs + " - " + COL_EVENT_TIME + ") / " + DAY_MS + ") AS int) " +
+ "AS day, " +
+ "COUNT(*) AS cnt " +
+ "FROM " + TAB_LOG + " " +
+ "WHERE " +
+ COL_EVENT_TYPE + "=" + EVENT_TYPE_POST + " " +
+ "GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG;
+ Cursor cursor = db.rawQuery(q, null);
+ try {
+ for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
+ int userId = cursor.getInt(0);
+ String pkg = cursor.getString(1);
+ int day = cursor.getInt(2);
+ int count = cursor.getInt(3);
+ pw.println(indent + "post_frequency{user_id=" + userId + ",pkg=" + pkg +
+ ",day=" + day + ",count=" + count + "}");
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+
+ private void writeEvent(long eventTimeMs, int eventType, NotificationRecord r,
+ boolean populateNotificationDetails) {
+ 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) {
+ putNotificationDetails(r, cv);
+ }
+ SQLiteDatabase db = mHelper.getWritableDatabase();
+ if (db.insert(TAB_LOG, null, cv) < 0) {
+ Log.wtf(TAG, "Error while trying to insert values: " + cv);
+ }
+ sNumWrites++;
+ pruneIfNecessary(db);
+ }
+
+ private void pruneIfNecessary(SQLiteDatabase db) {
+ // Prune if we haven't in a while.
+ long nowMs = System.currentTimeMillis();
+ if (sNumWrites > PRUNE_MIN_WRITES ||
+ nowMs - sLastPruneMs > PRUNE_MIN_DELAY_MS) {
+ sNumWrites = 0;
+ sLastPruneMs = nowMs;
+ long horizonStartMs = nowMs - HORIZON_MS;
+ int deletedRows = db.delete(TAB_LOG, COL_EVENT_TIME + " < ?",
+ new String[] { String.valueOf(horizonStartMs) });
+ Log.d(TAG, "Pruned event entries: " + deletedRows);
+ }
+ }
+
+ private static void putNotificationIdentifiers(NotificationRecord r, ContentValues outCv) {
+ outCv.put(COL_KEY, r.sbn.getKey());
+ outCv.put(COL_PKG, r.sbn.getPackageName());
+ }
+
+ private static void putNotificationDetails(NotificationRecord r, ContentValues outCv) {
+ outCv.put(COL_NOTIFICATION_ID, r.sbn.getId());
+ if (r.sbn.getTag() != null) {
+ outCv.put(COL_TAG, r.sbn.getTag());
+ }
+ outCv.put(COL_WHEN_MS, r.sbn.getPostTime());
+ outCv.put(COL_FLAGS, r.getNotification().flags);
+ outCv.put(COL_PRIORITY, r.getNotification().priority);
+ if (r.getNotification().category != null) {
+ outCv.put(COL_CATEGORY, r.getNotification().category);
+ }
+ outCv.put(COL_ACTION_COUNT, r.getNotification().actions != null ?
+ r.getNotification().actions.length : 0);
+ }
+
+ public void dump(PrintWriter pw, String indent) {
+ printPostFrequencies(pw, indent);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
new file mode 100644
index 0000000..f2db791
--- /dev/null
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -0,0 +1,91 @@
+/*
+ * 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 android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Log;
+
+import java.util.HashSet;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * {@hide}
+ */
+public class BackgroundDexOptService {
+
+ static final String TAG = "BackgroundDexOptService";
+
+ private final BroadcastReceiver mIdleMaintenanceReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)) {
+ onIdleStart();
+ } else if (Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) {
+ onIdleStop();
+ }
+ }
+ };
+
+ final PackageManagerService mPackageManager;
+
+ final AtomicBoolean mIdleTime = new AtomicBoolean(false);
+
+ public BackgroundDexOptService(Context context) {
+ mPackageManager = (PackageManagerService)ServiceManager.getService("package");
+
+ IntentFilter idleMaintenanceFilter = new IntentFilter();
+ idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_START);
+ idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_END);
+ context.registerReceiverAsUser(mIdleMaintenanceReceiver, UserHandle.ALL,
+ idleMaintenanceFilter, null, null);
+ }
+
+ public boolean onIdleStart() {
+ Log.i(TAG, "onIdleStart");
+ if (mPackageManager.isStorageLow()) {
+ return false;
+ }
+ final HashSet<String> pkgs = mPackageManager.getPackagesThatNeedDexOpt();
+ if (pkgs == null) {
+ return false;
+ }
+ mIdleTime.set(true);
+ new Thread("BackgroundDexOptService_DexOpter") {
+ @Override
+ public void run() {
+ for (String pkg : pkgs) {
+ if (!mIdleTime.get()) {
+ break;
+ }
+ mPackageManager.performDexOpt(pkg, false);
+ }
+ }
+ }.start();
+ return true;
+ }
+
+ public void onIdleStop() {
+ Log.i(TAG, "onIdleStop");
+ mIdleTime.set(false);
+ }
+}
diff --git a/services/core/java/com/android/server/pm/ForwardingIntentFilter.java b/services/core/java/com/android/server/pm/ForwardingIntentFilter.java
index aba796b..85bde98 100644
--- a/services/core/java/com/android/server/pm/ForwardingIntentFilter.java
+++ b/services/core/java/com/android/server/pm/ForwardingIntentFilter.java
@@ -32,22 +32,29 @@
*/
class ForwardingIntentFilter extends IntentFilter {
private static final String ATTR_USER_ID_DEST = "userIdDest";
+ private static final String ATTR_REMOVABLE = "removable";
private static final String ATTR_FILTER = "filter";
private static final String TAG = "ForwardingIntentFilter";
// If the intent matches the IntentFilter, then it can be forwarded to this userId.
final int mUserIdDest;
+ boolean mRemovable;
- ForwardingIntentFilter(IntentFilter filter, int userIdDest) {
+ ForwardingIntentFilter(IntentFilter filter, boolean removable, int userIdDest) {
super(filter);
mUserIdDest = userIdDest;
+ mRemovable = removable;
}
public int getUserIdDest() {
return mUserIdDest;
}
+ public boolean isRemovable() {
+ return mRemovable;
+ }
+
ForwardingIntentFilter(XmlPullParser parser) throws XmlPullParserException, IOException {
String userIdDestString = parser.getAttributeValue(null, ATTR_USER_ID_DEST);
if (userIdDestString == null) {
@@ -58,6 +65,10 @@
} else {
mUserIdDest = Integer.parseInt(userIdDestString);
}
+ String removableString = parser.getAttributeValue(null, ATTR_REMOVABLE);
+ if (removableString != null) {
+ mRemovable = Boolean.parseBoolean(removableString);
+ }
int outerDepth = parser.getDepth();
String tagName = parser.getName();
int type;
@@ -89,6 +100,7 @@
public void writeToXml(XmlSerializer serializer) throws IOException {
serializer.attribute(null, ATTR_USER_ID_DEST, Integer.toString(mUserIdDest));
+ serializer.attribute(null, ATTR_REMOVABLE, Boolean.toString(mRemovable));
serializer.startTag(null, ATTR_FILTER);
super.writeToXml(serializer);
serializer.endTag(null, ATTR_FILTER);
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index ab63c9c..bd28e04 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -38,6 +38,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.Log;
import android.util.Slog;
import com.android.internal.content.PackageMonitor;
@@ -50,7 +51,7 @@
* managed profiles.
*/
public class LauncherAppsService extends ILauncherApps.Stub {
-
+ private static final boolean DEBUG = false;
private static final String TAG = "LauncherAppsService";
private final Context mContext;
private final PackageManager mPm;
@@ -73,11 +74,17 @@
@Override
public void addOnAppsChangedListener(IOnAppsChangedListener listener) throws RemoteException {
synchronized (mListeners) {
+ if (DEBUG) {
+ Log.d(TAG, "Adding listener from " + Binder.getCallingUserHandle());
+ }
if (mListeners.getRegisteredCallbackCount() == 0) {
+ if (DEBUG) {
+ Log.d(TAG, "Starting package monitoring");
+ }
startWatchingPackageBroadcasts();
}
mListeners.unregister(listener);
- mListeners.register(listener);
+ mListeners.register(listener, Binder.getCallingUserHandle());
}
}
@@ -89,6 +96,9 @@
public void removeOnAppsChangedListener(IOnAppsChangedListener listener)
throws RemoteException {
synchronized (mListeners) {
+ if (DEBUG) {
+ Log.d(TAG, "Removing listener from " + Binder.getCallingUserHandle());
+ }
mListeners.unregister(listener);
if (mListeners.getRegisteredCallbackCount() == 0) {
stopWatchingPackageBroadcasts();
@@ -107,11 +117,17 @@
* Unregister package broadcast receiver
*/
private void stopWatchingPackageBroadcasts() {
+ if (DEBUG) {
+ Log.d(TAG, "Stopped watching for packages");
+ }
mPackageMonitor.unregister();
}
void checkCallbackCount() {
- synchronized (LauncherAppsService.this) {
+ synchronized (mListeners) {
+ if (DEBUG) {
+ Log.d(TAG, "Callback count = " + mListeners.getRegisteredCallbackCount());
+ }
if (mListeners.getRegisteredCallbackCount() == 0) {
stopWatchingPackageBroadcasts();
}
@@ -223,13 +239,47 @@
private class MyPackageMonitor extends PackageMonitor {
+ /** Checks if user is a profile of or same as listeningUser.
+ * and the user is enabled. */
+ private boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser,
+ String debugMsg) {
+ if (user.getIdentifier() == listeningUser.getIdentifier()) {
+ if (DEBUG) Log.d(TAG, "Delivering msg to same user " + debugMsg);
+ return true;
+ }
+ long ident = Binder.clearCallingIdentity();
+ try {
+ UserInfo userInfo = mUm.getUserInfo(user.getIdentifier());
+ UserInfo listeningUserInfo = mUm.getUserInfo(listeningUser.getIdentifier());
+ if (userInfo == null || listeningUserInfo == null
+ || userInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID
+ || userInfo.profileGroupId != listeningUserInfo.profileGroupId
+ || !userInfo.isEnabled()) {
+ if (DEBUG) {
+ Log.d(TAG, "Not delivering msg from " + user + " to " + listeningUser + ":"
+ + debugMsg);
+ }
+ return false;
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "Delivering msg from " + user + " to " + listeningUser + ":"
+ + debugMsg);
+ }
+ return true;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
@Override
public void onPackageAdded(String packageName, int uid) {
UserHandle user = new UserHandle(getChangingUserId());
- // TODO: if (!isProfile(user)) return;
final int n = mListeners.beginBroadcast();
for (int i = 0; i < n; i++) {
IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+ UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
+ if (!isEnabledProfileOf(user, listeningUser, "onPackageAdded")) continue;
try {
listener.onPackageAdded(user, packageName);
} catch (RemoteException re) {
@@ -244,10 +294,11 @@
@Override
public void onPackageRemoved(String packageName, int uid) {
UserHandle user = new UserHandle(getChangingUserId());
- // TODO: if (!isCurrentProfile(user)) return;
final int n = mListeners.beginBroadcast();
for (int i = 0; i < n; i++) {
IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+ UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
+ if (!isEnabledProfileOf(user, listeningUser, "onPackageRemoved")) continue;
try {
listener.onPackageRemoved(user, packageName);
} catch (RemoteException re) {
@@ -262,10 +313,11 @@
@Override
public void onPackageModified(String packageName) {
UserHandle user = new UserHandle(getChangingUserId());
- // TODO: if (!isProfile(user)) return;
final int n = mListeners.beginBroadcast();
for (int i = 0; i < n; i++) {
IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+ UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
+ if (!isEnabledProfileOf(user, listeningUser, "onPackageModified")) continue;
try {
listener.onPackageChanged(user, packageName);
} catch (RemoteException re) {
@@ -280,10 +332,11 @@
@Override
public void onPackagesAvailable(String[] packages) {
UserHandle user = new UserHandle(getChangingUserId());
- // TODO: if (!isProfile(user)) return;
final int n = mListeners.beginBroadcast();
for (int i = 0; i < n; i++) {
IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+ UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
+ if (!isEnabledProfileOf(user, listeningUser, "onPackagesAvailable")) continue;
try {
listener.onPackagesAvailable(user, packages, isReplacing());
} catch (RemoteException re) {
@@ -298,10 +351,11 @@
@Override
public void onPackagesUnavailable(String[] packages) {
UserHandle user = new UserHandle(getChangingUserId());
- // TODO: if (!isProfile(user)) return;
final int n = mListeners.beginBroadcast();
for (int i = 0; i < n; i++) {
IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+ UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
+ if (!isEnabledProfileOf(user, listeningUser, "onPackagesUnavailable")) continue;
try {
listener.onPackagesUnavailable(user, packages, isReplacing());
} catch (RemoteException re) {
@@ -316,7 +370,6 @@
}
class PackageCallbackList<T extends IInterface> extends RemoteCallbackList<T> {
-
@Override
public void onCallbackDied(T callback, Object cookie) {
checkCallbackCount();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a133d42..c8b61f1 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -23,17 +23,19 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.system.OsConstants.S_IRWXU;
+import static android.os.Process.PACKAGE_INFO_GID;
+import static android.os.Process.SYSTEM_UID;
import static android.system.OsConstants.S_IRGRP;
-import static android.system.OsConstants.S_IXGRP;
import static android.system.OsConstants.S_IROTH;
+import static android.system.OsConstants.S_IRWXU;
+import static android.system.OsConstants.S_IXGRP;
import static android.system.OsConstants.S_IXOTH;
-import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_USER_OWNER;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
+import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_USER_OWNER;
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.ArrayUtils.removeInt;
-import android.content.pm.PackageParser.*;
+import com.android.internal.R;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.NativeLibraryHelper;
@@ -43,10 +45,13 @@
import com.android.internal.util.XmlUtils;
import com.android.server.EventLogTags;
import com.android.server.IntentResolver;
-import com.android.server.ServiceThread;
-
import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
import com.android.server.Watchdog;
+import com.android.server.pm.Settings.DatabaseVersion;
+import com.android.server.storage.DeviceStorageMonitorInternal;
+import com.android.server.storage.DeviceStorageMonitorInternal;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -82,6 +87,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageManager;
+import android.content.pm.PackageParser.ActivityIntentInfo;
import android.content.pm.PackageParser;
import android.content.pm.PackageStats;
import android.content.pm.PackageUserState;
@@ -125,6 +131,7 @@
import android.system.Os;
import android.system.StructStat;
import android.text.TextUtils;
+import android.util.AtomicFile;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -135,6 +142,7 @@
import android.util.Xml;
import android.view.Display;
+import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
@@ -144,7 +152,9 @@
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
+import java.io.InputStream;
import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.Certificate;
@@ -163,14 +173,14 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import dalvik.system.DexFile;
+import dalvik.system.StaleDexCacheError;
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
-import com.android.internal.R;
-import com.android.server.pm.Settings.DatabaseVersion;
-import com.android.server.storage.DeviceStorageMonitorInternal;
-
/**
* Keep track of all those .apks everywhere.
*
@@ -197,6 +207,7 @@
private static final boolean DEBUG_PACKAGE_SCANNING = false;
private static final boolean DEBUG_APP_DIR_OBSERVER = false;
private static final boolean DEBUG_VERIFY = false;
+ private static final boolean DEBUG_DEXOPT = false;
private static final int RADIO_UID = Process.PHONE_UID;
private static final int LOG_UID = Process.LOG_UID;
@@ -287,7 +298,6 @@
final Context mContext;
final boolean mFactoryTest;
final boolean mOnlyCore;
- final boolean mNoDexOpt;
final DisplayMetrics mMetrics;
final int mDefParseFlags;
final String[] mSeparateProcesses;
@@ -593,6 +603,139 @@
private final String mRequiredVerifierPackage;
+ private final PackageUsage mPackageUsage = new PackageUsage();
+
+ private class PackageUsage {
+ private static final int WRITE_INTERVAL
+ = (DEBUG_DEXOPT) ? 0 : 30*60*1000; // 30m in ms
+
+ private final Object mFileLock = new Object();
+ private final AtomicLong mLastWritten = new AtomicLong(0);
+ private final AtomicBoolean mBackgroundWriteRunning = new AtomicBoolean(false);
+
+ void write(boolean force) {
+ if (force) {
+ write();
+ return;
+ }
+ if (SystemClock.elapsedRealtime() - mLastWritten.get() < WRITE_INTERVAL
+ && !DEBUG_DEXOPT) {
+ return;
+ }
+ if (mBackgroundWriteRunning.compareAndSet(false, true)) {
+ new Thread("PackageUsage_DiskWriter") {
+ @Override
+ public void run() {
+ try {
+ write(true);
+ } finally {
+ mBackgroundWriteRunning.set(false);
+ }
+ }
+ }.start();
+ }
+ }
+
+ private void write() {
+ synchronized (mPackages) {
+ synchronized (mFileLock) {
+ AtomicFile file = getFile();
+ FileOutputStream f = null;
+ try {
+ f = file.startWrite();
+ BufferedOutputStream out = new BufferedOutputStream(f);
+ FileUtils.setPermissions(file.getBaseFile().getPath(), 0660, SYSTEM_UID, PACKAGE_INFO_GID);
+ StringBuilder sb = new StringBuilder();
+ for (PackageParser.Package pkg : mPackages.values()) {
+ if (pkg.mLastPackageUsageTimeInMills == 0) {
+ continue;
+ }
+ sb.setLength(0);
+ sb.append(pkg.packageName);
+ sb.append(' ');
+ sb.append((long)pkg.mLastPackageUsageTimeInMills);
+ sb.append('\n');
+ out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
+ }
+ out.flush();
+ file.finishWrite(f);
+ } catch (IOException e) {
+ if (f != null) {
+ file.failWrite(f);
+ }
+ Log.e(TAG, "Failed to write package usage times", e);
+ }
+ }
+ }
+ mLastWritten.set(SystemClock.elapsedRealtime());
+ }
+
+ void readLP() {
+ synchronized (mFileLock) {
+ AtomicFile file = getFile();
+ BufferedInputStream in = null;
+ try {
+ in = new BufferedInputStream(file.openRead());
+ StringBuffer sb = new StringBuffer();
+ while (true) {
+ String packageName = readToken(in, sb, ' ');
+ if (packageName == null) {
+ break;
+ }
+ String timeInMillisString = readToken(in, sb, '\n');
+ if (timeInMillisString == null) {
+ throw new IOException("Failed to find last usage time for package "
+ + packageName);
+ }
+ PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ continue;
+ }
+ long timeInMillis;
+ try {
+ timeInMillis = Long.parseLong(timeInMillisString.toString());
+ } catch (NumberFormatException e) {
+ throw new IOException("Failed to parse " + timeInMillisString
+ + " as a long.", e);
+ }
+ pkg.mLastPackageUsageTimeInMills = timeInMillis;
+ }
+ } catch (FileNotFoundException expected) {
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to read package usage times", e);
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ }
+ mLastWritten.set(SystemClock.elapsedRealtime());
+ }
+
+ private String readToken(InputStream in, StringBuffer sb, char endOfToken)
+ throws IOException {
+ sb.setLength(0);
+ while (true) {
+ int ch = in.read();
+ if (ch == -1) {
+ if (sb.length() == 0) {
+ return null;
+ }
+ throw new IOException("Unexpected EOF");
+ }
+ if (ch == endOfToken) {
+ return sb.toString();
+ }
+ sb.append((char)ch);
+ }
+ }
+
+ private AtomicFile getFile() {
+ File dataDir = Environment.getDataDirectory();
+ File systemDir = new File(dataDir, "system");
+ File fname = new File(systemDir, "package-usage.list");
+ return new AtomicFile(fname);
+ }
+ }
+
class PackageHandler extends Handler {
private boolean mBound = false;
final ArrayList<HandlerParams> mPendingInstalls =
@@ -1137,7 +1280,6 @@
mContext = context;
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
- mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
mMetrics = new DisplayMetrics();
mSettings = new Settings(context);
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
@@ -1223,10 +1365,6 @@
// Set flag to monitor and not change apk file paths when
// scanning install directories.
int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
- if (mNoDexOpt) {
- Slog.w(TAG, "Running ENG build: no pre-dexopt!");
- scanMode |= SCAN_NO_DEX;
- }
final HashSet<String> alreadyDexOpted = new HashSet<String>();
@@ -1245,7 +1383,7 @@
Slog.w(TAG, "No BOOTCLASSPATH found!");
}
- boolean didDexOpt = false;
+ boolean didDexOptLibraryOrTool = false;
final List<String> instructionSets = getAllInstructionSets();
@@ -1265,13 +1403,12 @@
}
try {
- if (dalvik.system.DexFile.isDexOptNeededInternal(
- lib, null, instructionSet, false)) {
+ if (DexFile.isDexOptNeededInternal(lib, null, instructionSet, false)) {
alreadyDexOpted.add(lib);
// The list of "shared libraries" we have at this point is
mInstaller.dexopt(lib, Process.SYSTEM_UID, true, instructionSet);
- didDexOpt = true;
+ didDexOptLibraryOrTool = true;
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Library not found: " + lib);
@@ -1317,9 +1454,9 @@
continue;
}
try {
- if (dalvik.system.DexFile.isDexOptNeededInternal(path, null, instructionSet, false)) {
+ if (DexFile.isDexOptNeededInternal(path, null, instructionSet, false)) {
mInstaller.dexopt(path, Process.SYSTEM_UID, true, instructionSet);
- didDexOpt = true;
+ didDexOptLibraryOrTool = true;
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Jar not found: " + path);
@@ -1330,7 +1467,7 @@
}
}
- if (didDexOpt) {
+ if (didDexOptLibraryOrTool) {
pruneDexFiles(new File(dataDir, "dalvik-cache"));
}
@@ -1509,12 +1646,15 @@
// the correct library paths.
updateAllSharedLibrariesLPw();
-
for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
adjustCpuAbisForSharedUserLPw(setting.packages, true /* do dexopt */,
false /* force dexopt */, false /* defer dexopt */);
}
+ // Now that we know all the packages we are keeping,
+ // read and update their last usage times.
+ mPackageUsage.readLP();
+
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: "
@@ -1573,6 +1713,14 @@
//
// Additionally, delete all dex files from the root directory
// since there shouldn't be any there anyway.
+ //
+ // Note: This isn't as good an indicator as it used to be. It
+ // used to include the boot classpath but at some point
+ // DexFile.isDexOptNeeded started returning false for the boot
+ // class path files in all cases. It is very possible in a
+ // small maintenance release update that the library and tool
+ // jars may be unchanged but APK could be removed resulting in
+ // unused dalvik-cache files.
File[] files = cacheDir.listFiles();
if (files != null) {
for (File file : files) {
@@ -1595,10 +1743,12 @@
}
}
+ @Override
public boolean isFirstBoot() {
return !mRestoredSettings;
}
+ @Override
public boolean isOnlyCoreApps() {
return mOnlyCore;
}
@@ -1895,6 +2045,7 @@
state, userId);
}
+ @Override
public boolean isPackageAvailable(String packageName, int userId) {
if (!sUserManager.exists(userId)) return false;
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "is package available");
@@ -1932,6 +2083,7 @@
return null;
}
+ @Override
public String[] currentToCanonicalPackageNames(String[] names) {
String[] out = new String[names.length];
// reader
@@ -1944,6 +2096,7 @@
return out;
}
+ @Override
public String[] canonicalToCurrentPackageNames(String[] names) {
String[] out = new String[names.length];
// reader
@@ -2004,6 +2157,7 @@
return pi;
}
+ @Override
public PermissionInfo getPermissionInfo(String name, int flags) {
// reader
synchronized (mPackages) {
@@ -2015,6 +2169,7 @@
}
}
+ @Override
public List<PermissionInfo> queryPermissionsByGroup(String group, int flags) {
// reader
synchronized (mPackages) {
@@ -2038,6 +2193,7 @@
}
}
+ @Override
public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) {
// reader
synchronized (mPackages) {
@@ -2046,6 +2202,7 @@
}
}
+ @Override
public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
// reader
synchronized (mPackages) {
@@ -2131,6 +2288,7 @@
}
+ @Override
public void freeStorageAndNotify(final long freeStorageSize, final IPackageDataObserver observer) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CLEAR_APP_CACHE, null);
@@ -2156,6 +2314,7 @@
});
}
+ @Override
public void freeStorage(final long freeStorageSize, final IntentSender pi) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CLEAR_APP_CACHE, null);
@@ -2277,6 +2436,7 @@
return null;
}
+ @Override
public String[] getSystemSharedLibraryNames() {
Set<String> libSet;
synchronized (mPackages) {
@@ -2291,6 +2451,7 @@
return null;
}
+ @Override
public FeatureInfo[] getSystemAvailableFeatures() {
Collection<FeatureInfo> featSet;
synchronized (mPackages) {
@@ -2309,6 +2470,7 @@
return null;
}
+ @Override
public boolean hasSystemFeature(String name) {
synchronized (mPackages) {
return mAvailableFeatures.containsKey(name);
@@ -2323,6 +2485,7 @@
+ " is not privileged to communicate with user=" + userId);
}
+ @Override
public int checkPermission(String permName, String pkgName) {
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(pkgName);
@@ -2340,6 +2503,7 @@
return PackageManager.PERMISSION_DENIED;
}
+ @Override
public int checkUidPermission(String permName, int uid) {
synchronized (mPackages) {
Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
@@ -2514,18 +2678,21 @@
return added;
}
+ @Override
public boolean addPermission(PermissionInfo info) {
synchronized (mPackages) {
return addPermissionLocked(info, false);
}
}
+ @Override
public boolean addPermissionAsync(PermissionInfo info) {
synchronized (mPackages) {
return addPermissionLocked(info, true);
}
}
+ @Override
public void removePermission(String name) {
synchronized (mPackages) {
checkPermissionTreeLP(name);
@@ -2570,6 +2737,7 @@
}
}
+ @Override
public void grantPermission(String packageName, String permissionName) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, null);
@@ -2599,6 +2767,7 @@
}
}
+ @Override
public void revokePermission(String packageName, String permissionName) {
int changedAppId = -1;
@@ -2657,12 +2826,14 @@
}
}
+ @Override
public boolean isProtectedBroadcast(String actionName) {
synchronized (mPackages) {
return mProtectedBroadcasts.contains(actionName);
}
}
+ @Override
public int checkSignatures(String pkg1, String pkg2) {
synchronized (mPackages) {
final PackageParser.Package p1 = mPackages.get(pkg1);
@@ -2675,6 +2846,7 @@
}
}
+ @Override
public int checkUidSignatures(int uid1, int uid2) {
// Map to base uids.
uid1 = UserHandle.getAppId(uid1);
@@ -2814,6 +2986,7 @@
return PackageManager.SIGNATURE_NO_MATCH;
}
+ @Override
public String[] getPackagesForUid(int uid) {
uid = UserHandle.getAppId(uid);
// reader
@@ -2837,6 +3010,7 @@
return null;
}
+ @Override
public String getNameForUid(int uid) {
// reader
synchronized (mPackages) {
@@ -2852,6 +3026,7 @@
return null;
}
+ @Override
public int getUidForSharedUser(String sharedUserName) {
if(sharedUserName == null) {
return -1;
@@ -2866,6 +3041,7 @@
}
}
+ @Override
public int getFlagsForUid(int uid) {
synchronized (mPackages) {
Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
@@ -3797,6 +3973,7 @@
}
}
+ @Override
public List<ProviderInfo> queryContentProviders(String processName,
int uid, int flags) {
ArrayList<ProviderInfo> finalList = null;
@@ -3834,6 +4011,7 @@
return finalList;
}
+ @Override
public InstrumentationInfo getInstrumentationInfo(ComponentName name,
int flags) {
// reader
@@ -3843,6 +4021,7 @@
}
}
+ @Override
public List<InstrumentationInfo> queryInstrumentation(String targetPackage,
int flags) {
ArrayList<InstrumentationInfo> finalList =
@@ -4289,21 +4468,60 @@
}
if (pkgs != null) {
+ // Filter out packages that aren't recently used.
+ //
+ // The exception is first boot of a non-eng device, which
+ // should do a full dexopt.
+ boolean eng = "eng".equals(SystemProperties.get("ro.build.type"));
+ if (eng || !isFirstBoot()) {
+ // TODO: add a property to control this?
+ long dexOptLRUThresholdInMinutes;
+ if (eng) {
+ dexOptLRUThresholdInMinutes = 30; // only last 30 minutes of apps for eng builds.
+ } else {
+ dexOptLRUThresholdInMinutes = 7 * 24 * 60; // apps used in the 7 days for users.
+ }
+ long dexOptLRUThresholdInMills = dexOptLRUThresholdInMinutes * 60 * 1000;
+
+ int total = pkgs.size();
+ int skipped = 0;
+ long now = System.currentTimeMillis();
+ for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) {
+ PackageParser.Package pkg = i.next();
+ long then = pkg.mLastPackageUsageTimeInMills;
+ if (then + dexOptLRUThresholdInMills < now) {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " +
+ ((then == 0) ? "never" : new Date(then)));
+ }
+ i.remove();
+ skipped++;
+ }
+ }
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Skipped optimizing " + skipped + " of " + total);
+ }
+ }
+
int i = 0;
for (PackageParser.Package pkg : pkgs) {
+ i++;
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, "Optimizing app " + i + " of " + pkgs.size()
+ + ": " + pkg.packageName);
+ }
if (!isFirstBoot()) {
- i++;
try {
ActivityManagerNative.getDefault().showBootMessage(
mContext.getResources().getString(
- com.android.internal.R.string.android_upgrading_apk,
+ R.string.android_upgrading_apk,
i, pkgs.size()), true);
} catch (RemoteException e) {
}
}
PackageParser.Package p = pkg;
synchronized (mInstallLock) {
- if (!p.mDidDexOpt) {
+ if (p.mDexOptNeeded) {
performDexOptLI(p, false /* force dex */, false /* defer */,
true /* include dependencies */);
}
@@ -4315,25 +4533,57 @@
@Override
public boolean performDexOpt(String packageName) {
enforceSystemOrRoot("Only the system can request dexopt be performed");
- if (!mNoDexOpt) {
- return false;
- }
+ return performDexOpt(packageName, true);
+ }
+
+ public boolean performDexOpt(String packageName, boolean updateUsage) {
PackageParser.Package p;
synchronized (mPackages) {
p = mPackages.get(packageName);
- if (p == null || p.mDidDexOpt) {
+ if (p == null) {
+ return false;
+ }
+ if (updateUsage) {
+ p.mLastPackageUsageTimeInMills = System.currentTimeMillis();
+ }
+ mPackageUsage.write();
+ if (!p.mDexOptNeeded) {
return false;
}
}
+
synchronized (mInstallLock) {
return performDexOptLI(p, false /* force dex */, false /* defer */,
true /* include dependencies */) == DEX_OPT_PERFORMED;
}
}
- private void performDexOptLibsLI(ArrayList<String> libs, String instructionSet, boolean forceDex,
- boolean defer, HashSet<String> done) {
+ public HashSet<String> getPackagesThatNeedDexOpt() {
+ HashSet<String> pkgs = null;
+ synchronized (mPackages) {
+ for (PackageParser.Package p : mPackages.values()) {
+ if (DEBUG_DEXOPT) {
+ Log.i(TAG, p.packageName + " mDexOptNeeded=" + p.mDexOptNeeded);
+ }
+ if (!p.mDexOptNeeded) {
+ continue;
+ }
+ if (pkgs == null) {
+ pkgs = new HashSet<String>();
+ }
+ pkgs.add(p.packageName);
+ }
+ }
+ return pkgs;
+ }
+
+ public void shutdown() {
+ mPackageUsage.write(true);
+ }
+
+ private void performDexOptLibsLI(ArrayList<String> libs, String instructionSet,
+ boolean forceDex, boolean defer, HashSet<String> done) {
for (int i=0; i<libs.size(); i++) {
PackageParser.Package libPkg;
String libName;
@@ -4358,8 +4608,7 @@
static final int DEX_OPT_FAILED = -1;
private int performDexOptLI(PackageParser.Package pkg, String instructionSetOverride,
- boolean forceDex,
- boolean defer, HashSet<String> done) {
+ boolean forceDex, boolean defer, HashSet<String> done) {
final String instructionSet = instructionSetOverride != null ?
instructionSetOverride : getAppInstructionSet(pkg.applicationInfo);
@@ -4376,47 +4625,52 @@
boolean performed = false;
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
String path = pkg.mScanPath;
- int ret = 0;
try {
- if (forceDex || dalvik.system.DexFile.isDexOptNeededInternal(path,
- pkg.packageName, instructionSet, defer)) {
- if (!forceDex && defer) {
- if (mDeferredDexOpt == null) {
- mDeferredDexOpt = new HashSet<PackageParser.Package>();
- }
- mDeferredDexOpt.add(pkg);
- return DEX_OPT_DEFERRED;
- } else {
- Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName +
- " (instructionSet=" + instructionSet + ")");
-
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
+ boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path,
+ pkg.packageName,
+ instructionSet,
+ defer);
+ // There are three basic cases here:
+ // 1.) we need to dexopt, either because we are forced or it is needed
+ // 2.) we are defering a needed dexopt
+ // 3.) we are skipping an unneeded dexopt
+ if (forceDex || (!defer && isDexOptNeededInternal)) {
+ Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName);
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
pkg.packageName, instructionSet);
- pkg.mDidDexOpt = true;
- performed = true;
+ // Note that we ran dexopt, since rerunning will
+ // probably just result in an error again.
+ pkg.mDexOptNeeded = false;
+ if (ret < 0) {
+ return DEX_OPT_FAILED;
}
+ return DEX_OPT_PERFORMED;
}
+ if (defer && isDexOptNeededInternal) {
+ if (mDeferredDexOpt == null) {
+ mDeferredDexOpt = new HashSet<PackageParser.Package>();
+ }
+ mDeferredDexOpt.add(pkg);
+ return DEX_OPT_DEFERRED;
+ }
+ pkg.mDexOptNeeded = false;
+ return DEX_OPT_SKIPPED;
} catch (FileNotFoundException e) {
Slog.w(TAG, "Apk not found for dexopt: " + path);
- ret = -1;
+ return DEX_OPT_FAILED;
} catch (IOException e) {
Slog.w(TAG, "IOException reading apk: " + path, e);
- ret = -1;
- } catch (dalvik.system.StaleDexCacheError e) {
+ return DEX_OPT_FAILED;
+ } catch (StaleDexCacheError e) {
Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
- ret = -1;
+ return DEX_OPT_FAILED;
} catch (Exception e) {
Slog.w(TAG, "Exception when doing dexopt : ", e);
- ret = -1;
- }
- if (ret < 0) {
- //error from installer
return DEX_OPT_FAILED;
}
}
-
- return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
+ return DEX_OPT_SKIPPED;
}
private String getAppInstructionSet(ApplicationInfo info) {
@@ -4705,7 +4959,7 @@
mResolveActivity.processName = "system:ui";
mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
- mResolveActivity.theme = com.android.internal.R.style.Theme_Holo_Dialog_Alert;
+ mResolveActivity.theme = R.style.Theme_Holo_Dialog_Alert;
mResolveActivity.exported = true;
mResolveActivity.enabled = true;
mResolveInfo.activityInfo = mResolveActivity;
@@ -7064,6 +7318,7 @@
return mMediaMounted || Environment.isExternalStorageEmulated();
}
+ @Override
public PackageCleanItem nextPackageToClean(PackageCleanItem lastPackage) {
// writer
synchronized (mPackages) {
@@ -7249,6 +7504,7 @@
}
/* Called when a downloaded package installation has been confirmed by the user */
+ @Override
public void installPackage(
final Uri packageURI, final IPackageInstallObserver observer, final int flags,
final String installerPackageName) {
@@ -7266,6 +7522,7 @@
installerPackageName, verificationParams, encryptionParams);
}
+ @Override
public void installPackageWithVerificationAndEncryption(Uri packageURI,
IPackageInstallObserver observer, int flags, String installerPackageName,
VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
@@ -7479,11 +7736,7 @@
null);
PackageSetting pkgSetting;
final int uid = Binder.getCallingUid();
- if (UserHandle.getUserId(uid) != userId) {
- mContext.enforceCallingPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- "installExistingPackage for user " + userId);
- }
+ enforceCrossUserPermission(uid, userId, true, "installExistingPackage for user " + userId);
if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
}
@@ -7679,6 +7932,7 @@
}
}
+ @Override
public void finishPackageInstall(int token) {
enforceSystemOrRoot("Only the system is allowed to finish installs");
@@ -7750,6 +8004,7 @@
-1);
}
+ @Override
public void setInstallerPackageName(String targetPackage, String installerPackageName) {
final int uid = Binder.getCallingUid();
// writer
@@ -9705,22 +9960,22 @@
// Utility method used to move dex files during install.
private int moveDexFilesLI(PackageParser.Package newPackage) {
- int retCode;
if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
- retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath,
- getAppInstructionSet(newPackage.applicationInfo));
+ final String instructionSet = getAppInstructionSet(newPackage.applicationInfo);
+ int retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath,
+ instructionSet);
if (retCode != 0) {
- if (mNoDexOpt) {
- /*
- * If we're in an engineering build, programs are lazily run
- * through dexopt. If the .dex file doesn't exist yet, it
- * will be created when the program is run next.
- */
- Slog.i(TAG, "dex file doesn't exist, skipping move: " + newPackage.mPath);
- } else {
- Slog.e(TAG, "Couldn't rename dex file: " + newPackage.mPath);
- return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- }
+ /*
+ * Programs may be lazily run through dexopt, so the
+ * source may not exist. However, something seems to
+ * have gone wrong, so note that dexopt needs to be
+ * run again and remove the source file. In addition,
+ * remove the target to make sure there isn't a stale
+ * file from a previous version of the package.
+ */
+ newPackage.mDexOptNeeded = true;
+ mInstaller.rmdex(newPackage.mScanPath, instructionSet);
+ mInstaller.rmdex(newPackage.mPath, instructionSet);
}
}
return PackageManager.INSTALL_SUCCEEDED;
@@ -10684,6 +10939,7 @@
}
}
+ @Override
public void deleteApplicationCacheFiles(final String packageName,
final IPackageDataObserver observer) {
mContext.enforceCallingOrSelfPermission(
@@ -10736,6 +10992,7 @@
return true;
}
+ @Override
public void getPackageSizeInfo(final String packageName, int userHandle,
final IPackageStatsObserver observer) {
mContext.enforceCallingOrSelfPermission(
@@ -10815,14 +11072,17 @@
}
+ @Override
public void addPackageToPreferred(String packageName) {
Slog.w(TAG, "addPackageToPreferred: this is now a no-op");
}
+ @Override
public void removePackageFromPreferred(String packageName) {
Slog.w(TAG, "removePackageFromPreferred: this is now a no-op");
}
+ @Override
public List<PackageInfo> getPreferredPackages(int flags) {
return new ArrayList<PackageInfo>();
}
@@ -10850,6 +11110,7 @@
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
+ @Override
public void addPreferredActivity(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity, int userId) {
addPreferredActivityInternal(filter, match, set, activity, true, userId);
@@ -10886,6 +11147,7 @@
}
}
+ @Override
public void replacePreferredActivity(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity) {
if (filter.countActions() != 1) {
@@ -10942,6 +11204,7 @@
}
}
+ @Override
public void clearPackagePreferredActivities(String packageName) {
final int uid = Binder.getCallingUid();
// writer
@@ -11005,6 +11268,7 @@
return changed;
}
+ @Override
public void resetPreferredActivities(int userId) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
@@ -11018,6 +11282,7 @@
}
}
+ @Override
public int getPreferredActivities(List<IntentFilter> outFilters,
List<ComponentName> outActivities, String packageName) {
@@ -11112,42 +11377,32 @@
}
}
- /*
- * For filters that are added with this method:
- * if an intent for the user whose id is userIdOrig matches the filter, then this intent can
- * also be resolved in the user whose id is userIdDest.
- */
@Override
- public void addForwardingIntentFilter(IntentFilter filter, int userIdOrig, int userIdDest) {
- int callingUid = Binder.getCallingUid();
- if (callingUid != Process.SYSTEM_UID) {
- throw new SecurityException(
- "addForwardingIntentFilter can only be run by the system");
- }
+ public void addForwardingIntentFilter(IntentFilter filter, boolean removable, int userIdOrig,
+ int userIdDest) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
if (filter.countActions() == 0) {
Slog.w(TAG, "Cannot set a forwarding intent filter with no filter actions");
return;
}
synchronized (mPackages) {
mSettings.editForwardingIntentResolverLPw(userIdOrig).addFilter(
- new ForwardingIntentFilter(filter, userIdDest));
+ new ForwardingIntentFilter(filter, removable, userIdDest));
mSettings.writePackageRestrictionsLPr(userIdOrig);
}
}
@Override
public void clearForwardingIntentFilters(int userIdOrig) {
- int callingUid = Binder.getCallingUid();
- if (callingUid != Process.SYSTEM_UID) {
- throw new SecurityException(
- "clearForwardingIntentFilter can only be run by the system");
- }
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
synchronized (mPackages) {
ForwardingIntentResolver fir = mSettings.editForwardingIntentResolverLPw(userIdOrig);
HashSet<ForwardingIntentFilter> set =
new HashSet<ForwardingIntentFilter>(fir.filterSet());
for (ForwardingIntentFilter fif : set) {
- fir.removeFilter(fif);
+ if (fif.isRemovable()) fir.removeFilter(fif);
}
mSettings.writePackageRestrictionsLPr(userIdOrig);
}
@@ -11335,6 +11590,7 @@
new int[] {UserHandle.getUserId(packageUid)});
}
+ @Override
public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
if (!sUserManager.exists(userId)) return;
final int uid = Binder.getCallingUid();
@@ -11351,6 +11607,7 @@
}
}
+ @Override
public String getInstallerPackageName(String packageName) {
// reader
synchronized (mPackages) {
@@ -11380,6 +11637,7 @@
}
}
+ @Override
public void enterSafeMode() {
enforceSystemOrRoot("Only the system can request entering safe mode");
@@ -11388,6 +11646,7 @@
}
}
+ @Override
public void systemReady() {
mSystemReady = true;
@@ -11433,10 +11692,12 @@
sUserManager.systemReady();
}
+ @Override
public boolean isSafeMode() {
return mSafeMode;
}
+ @Override
public boolean hasSystemUidErrors() {
return mHasSystemUidErrors;
}
@@ -11934,6 +12195,7 @@
/*
* Update media status on PackageManager.
*/
+ @Override
public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
int callingUid = Binder.getCallingUid();
if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
@@ -12528,6 +12790,7 @@
});
}
+ @Override
public boolean setInstallLocation(int loc) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
null);
@@ -12543,6 +12806,7 @@
return false;
}
+ @Override
public int getInstallLocation() {
return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
android.provider.Settings.Global.DEFAULT_INSTALL_LOCATION,
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 14df347..4f5326f 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -734,6 +734,15 @@
writeBoolean(serializer, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS);
writeBoolean(serializer, restrictions, UserManager.DISALLOW_REMOVE_USER);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_DEBUGGING_FEATURES);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_VPN);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_TETHERING);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_FACTORY_RESET);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_ADD_USER);
+ writeBoolean(serializer, restrictions, UserManager.ENSURE_VERIFY_APPS);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_APPS);
serializer.endTag(null, TAG_RESTRICTIONS);
}
serializer.endTag(null, TAG_USER);
@@ -873,6 +882,15 @@
readBoolean(parser, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_CREDENTIALS);
readBoolean(parser, restrictions, UserManager.DISALLOW_REMOVE_USER);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_DEBUGGING_FEATURES);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_VPN);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_TETHERING);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_FACTORY_RESET);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_ADD_USER);
+ readBoolean(parser, restrictions, UserManager.ENSURE_VERIFY_APPS);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_APPS);
}
}
}
@@ -1092,6 +1110,9 @@
// on next startup, in case the runtime stops now before stopping and
// removing the user completely.
user.partial = true;
+ // Mark it as disabled, so that it isn't returned any more when
+ // profiles are queried.
+ user.flags |= UserInfo.FLAG_DISABLED;
writeUserLocked(user);
}
if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);
@@ -1120,6 +1141,7 @@
// wiping the user's system directory and removing from the user list
long ident = Binder.clearCallingIdentity();
try {
+ final boolean isManaged = getUserInfo(userHandle).isManagedProfile();
Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
mContext.sendOrderedBroadcastAsUser(addedIntent, UserHandle.ALL,
@@ -1140,6 +1162,11 @@
removeUserStateLocked(userHandle);
}
}
+ // Send broadcast to notify system that the user removed was a
+ // managed user.
+ if (isManaged) {
+ sendProfileRemovedBroadcast(userHandle);
+ }
}
}.start();
}
@@ -1191,6 +1218,13 @@
parent.delete();
}
+ private void sendProfileRemovedBroadcast(int userHandle) {
+ Intent managedProfileIntent = new Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED);
+ managedProfileIntent.putExtra(Intent.EXTRA_USER, new UserHandle(userHandle));
+ // Note: This makes an assumption that the parent owner is user 0.
+ mContext.sendBroadcastAsUser(managedProfileIntent, UserHandle.OWNER, null);
+ }
+
@Override
public Bundle getApplicationRestrictions(String packageName) {
return getApplicationRestrictionsForUser(packageName, UserHandle.getCallingUserId());
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index d84e8e1..2d6cc7c 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -132,6 +132,11 @@
mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
mScreenOffIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
+
+ // Initialize interactive state for battery stats.
+ try {
+ mBatteryStats.noteInteractive(true);
+ } catch (RemoteException ex) { }
}
/**
@@ -259,7 +264,14 @@
// Going to sleep...
mLastGoToSleepReason = reason;
}
- mInputManagerInternal.setInteractive(interactive);
+ }
+
+ mInputManagerInternal.setInteractive(interactive);
+
+ if (interactive) {
+ try {
+ mBatteryStats.noteInteractive(true);
+ } catch (RemoteException ex) { }
}
}
@@ -289,6 +301,12 @@
}
}
}
+
+ if (!interactive) {
+ try {
+ mBatteryStats.noteInteractive(false);
+ } catch (RemoteException ex) { }
+ }
}
/**
@@ -409,7 +427,7 @@
EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
- mPolicy.screenTurningOn(mScreenOnListener);
+ mPolicy.wakingUp(mScreenOnListener);
mActivityManagerInternal.wakingUp();
if (ActivityManagerNative.isSystemReady()) {
@@ -460,7 +478,7 @@
EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
- mPolicy.screenTurnedOff(why);
+ mPolicy.goingToSleep(why);
mActivityManagerInternal.goingToSleep();
if (ActivityManagerNative.isSystemReady()) {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index cfe24fe..6d2e8592 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -496,6 +496,7 @@
filter = new IntentFilter();
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiver(new BootCompletedReceiver(), filter, null, mHandler);
filter = new IntentFilter();
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 8fed79f..956e3e6 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -45,6 +45,7 @@
import android.os.storage.IMountShutdownObserver;
import com.android.internal.telephony.ITelephony;
+import com.android.server.pm.PackageManagerService;
import android.util.Log;
import android.view.WindowManager;
@@ -329,6 +330,14 @@
}
}
+ Log.i(TAG, "Shutting down package manager...");
+
+ final PackageManagerService pm = (PackageManagerService)
+ ServiceManager.getService("package");
+ if (pm != null) {
+ pm.shutdown();
+ }
+
// Shutdown radios.
shutdownRadios(MAX_RADIO_WAIT_TIME);
diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java
index 486477a..5deb2b8 100644
--- a/services/core/java/com/android/server/search/SearchManagerService.java
+++ b/services/core/java/com/android/server/search/SearchManagerService.java
@@ -70,8 +70,9 @@
*/
public SearchManagerService(Context context) {
mContext = context;
- mContext.registerReceiver(new BootCompletedReceiver(),
- new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+ IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ mContext.registerReceiver(new BootCompletedReceiver(), filter);
mContext.registerReceiver(new UserReceiver(),
new IntentFilter(Intent.ACTION_USER_REMOVED));
new MyPackageMonitor().register(context, null, UserHandle.ALL, true);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 91f796b..738ad32 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -74,6 +74,7 @@
private boolean mMenuVisible = false;
private int mImeWindowVis = 0;
private int mImeBackDisposition;
+ private boolean mShowImeSwitcher;
private IBinder mImeToken = null;
private int mCurrentUserId;
@@ -346,7 +347,8 @@
}
@Override
- public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition) {
+ public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition,
+ final boolean showImeSwitcher) {
enforceStatusBar();
if (SPEW) {
@@ -360,11 +362,12 @@
mImeWindowVis = vis;
mImeBackDisposition = backDisposition;
mImeToken = token;
+ mShowImeSwitcher = showImeSwitcher;
mHandler.post(new Runnable() {
public void run() {
if (mBar != null) {
try {
- mBar.setImeWindowStatus(token, vis, backDisposition);
+ mBar.setImeWindowStatus(token, vis, backDisposition, showImeSwitcher);
} catch (RemoteException ex) {
}
}
@@ -512,6 +515,7 @@
switches[2] = mMenuVisible ? 1 : 0;
switches[3] = mImeWindowVis;
switches[4] = mImeBackDisposition;
+ switches[7] = mShowImeSwitcher ? 1 : 0;
binders.add(mImeToken);
}
switches[5] = mWindowManager.isHardKeyboardAvailable() ? 1 : 0;
@@ -546,13 +550,13 @@
}
@Override
- public void onNotificationClick(String pkg, String tag, int id, int userId) {
+ public void onNotificationClick(String key) {
enforceStatusBarService();
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
long identity = Binder.clearCallingIdentity();
try {
- mNotificationDelegate.onNotificationClick(callingUid, callingPid, pkg, tag, id, userId);
+ mNotificationDelegate.onNotificationClick(callingUid, callingPid, key);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4318b0e..e746c1a 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -299,6 +299,7 @@
boolean mHasSurface = false;
+ boolean mNotOnAppsDisplay = false;
DisplayContent mDisplayContent;
/** When true this window can be displayed on screens owther than mOwnerUid's */
@@ -430,6 +431,10 @@
}
mRootToken = appToken;
mAppToken = appToken.appWindowToken;
+ if (mAppToken != null) {
+ final DisplayContent appDisplay = getDisplayContent();
+ mNotOnAppsDisplay = displayContent != appDisplay;
+ }
mWinAnimator = new WindowStateAnimator(this);
mWinAnimator.mAlpha = a.alpha;
@@ -717,7 +722,8 @@
}
public DisplayContent getDisplayContent() {
- return mAppToken == null ? mDisplayContent : getStack().getDisplayContent();
+ return mAppToken == null || mNotOnAppsDisplay ?
+ mDisplayContent : getStack().getDisplayContent();
}
public int getDisplayId() {
diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
index 163692b..163225e 100644
--- a/services/core/jni/com_android_server_AssetAtlasService.cpp
+++ b/services/core/jni/com_android_server_AssetAtlasService.cpp
@@ -46,33 +46,16 @@
// ----------------------------------------------------------------------------
static struct {
- jfieldID mFinalizer;
- jfieldID mNativeCanvas;
+ jmethodID safeCanvasSwap;
} gCanvasClassInfo;
-static struct {
- jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
-#define GET_LONG(object, field) \
- env->GetLongField(object, field)
-
-#define SET_LONG(object, field, value) \
- env->SetLongField(object, field, value)
+#define INVOKEV(object, method, ...) \
+ env->CallVoidMethod(object, method, __VA_ARGS__)
// ----------------------------------------------------------------------------
// Canvas management
// ----------------------------------------------------------------------------
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
- jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
- SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
- GET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas));
- SET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas, (long) newCanvas);
- SET_LONG(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (long) newCanvas);
- SkSafeUnref(previousCanvas);
-}
-
static jlong com_android_server_AssetAtlasService_acquireCanvas(JNIEnv* env, jobject,
jobject canvas, jint width, jint height) {
@@ -82,7 +65,7 @@
bitmap->eraseColor(0);
SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (*bitmap));
- swapCanvasPtr(env, canvas, nativeCanvas);
+ INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
return reinterpret_cast<jlong>(bitmap);
}
@@ -92,7 +75,7 @@
SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
SkCanvas* nativeCanvas = SkNEW(SkCanvas);
- swapCanvasPtr(env, canvas, nativeCanvas);
+ INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
delete bitmap;
}
@@ -242,9 +225,9 @@
var = env->FindClass(className); \
LOG_FATAL_IF(! var, "Unable to find class " className);
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
- var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
- LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+ var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+ LOG_FATAL_IF(!var, "Unable to find method " methodName);
const char* const kClassPathName = "com/android/server/AssetAtlasService";
@@ -261,12 +244,7 @@
jclass clazz;
FIND_CLASS(clazz, "android/graphics/Canvas");
- GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
- "Landroid/graphics/Canvas$CanvasFinalizer;");
- GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
-
- FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
- GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
+ GET_METHOD_ID(gCanvasClassInfo.safeCanvasSwap, clazz, "safeCanvasSwap", "(JZ)V");
return jniRegisterNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index f3e8f3c..27c8876 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -19,57 +19,250 @@
#define LOG_NDEBUG 1
#include "JNIHelp.h"
+#include "ScopedPrimitiveArray.h"
+
+#include <string>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
#include <hardware/hdmi_cec.h>
+#include <sys/param.h>
namespace android {
static struct {
- jmethodID handleMessage;
+ jmethodID handleIncomingCecCommand;
+ jmethodID handleHotplug;
} gHdmiCecControllerClassInfo;
-
class HdmiCecController {
public:
- HdmiCecController(jobject callbacksObj);
+ HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj);
+
+ void init();
+
+ // Send message to other device. Note that it runs in IO thread.
+ int sendMessage(const cec_message_t& message);
+ // Add a logical address to device.
+ int addLogicalAddress(cec_logical_address_t address);
+ // Clear all logical address registered to the device.
+ void clearLogicaladdress();
+ // Get physical address of device.
+ int getPhysicalAddress();
+ // Get CEC version from driver.
+ int getVersion();
+ // Get vendor id used for vendor command.
+ uint32_t getVendorId();
private:
- static void onReceived(const hdmi_event_t* event, void* arg);
+ // Propagate the message up to Java layer.
+ void propagateCecCommand(const cec_message_t& message);
+ void propagateHotplugEvent(const hotplug_event_t& event);
+ static void onReceived(const hdmi_event_t* event, void* arg);
+ static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
+
+ hdmi_cec_device_t* mDevice;
jobject mCallbacksObj;
};
-HdmiCecController::HdmiCecController(jobject callbacksObj) :
+HdmiCecController::HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj) :
+ mDevice(device),
mCallbacksObj(callbacksObj) {
}
+void HdmiCecController::init() {
+ mDevice->register_event_callback(mDevice, HdmiCecController::onReceived, this);
+}
+
+void HdmiCecController::propagateCecCommand(const cec_message_t& message) {
+ jint srcAddr = message.initiator;
+ jint dstAddr = message.destination;
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jbyteArray body = env->NewByteArray(message.length);
+ const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body);
+ env->SetByteArrayRegion(body, 0, message.length, bodyPtr);
+
+ env->CallVoidMethod(mCallbacksObj,
+ gHdmiCecControllerClassInfo.handleIncomingCecCommand,
+ srcAddr, dstAddr, body);
+ env->DeleteLocalRef(body);
+
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+void HdmiCecController::propagateHotplugEvent(const hotplug_event_t& event) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mCallbacksObj,
+ gHdmiCecControllerClassInfo.handleHotplug, event.connected);
+
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+int HdmiCecController::sendMessage(const cec_message_t& message) {
+ // TODO: propagate send_message's return value.
+ return mDevice->send_message(mDevice, &message);
+}
+
+int HdmiCecController::addLogicalAddress(cec_logical_address_t address) {
+ return mDevice->add_logical_address(mDevice, address);
+}
+
+void HdmiCecController::clearLogicaladdress() {
+ mDevice->clear_logical_address(mDevice);
+}
+
+int HdmiCecController::getPhysicalAddress() {
+ uint16_t physicalAddress = 0xFFFF;
+ if (mDevice->get_physical_address(mDevice, &physicalAddress) == 0) {
+ return physicalAddress;
+ }
+ return -1;
+}
+
+int HdmiCecController::getVersion() {
+ int version = 0;
+ mDevice->get_version(mDevice, &version);
+ return version;
+}
+
+uint32_t HdmiCecController::getVendorId() {
+ uint32_t vendorId = 0;
+ mDevice->get_vendor_id(mDevice, &vendorId);
+ return vendorId;
+}
+
+// static
+void HdmiCecController::checkAndClearExceptionFromCallback(JNIEnv* env,
+ const char* methodName) {
+ if (env->ExceptionCheck()) {
+ ALOGE("An exception was thrown by callback '%s'.", methodName);
+ LOGE_EX(env);
+ env->ExceptionClear();
+ }
+}
+
// static
void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) {
- HdmiCecController* handler = static_cast<HdmiCecController*>(arg);
- if (handler == NULL) {
+ HdmiCecController* controller = static_cast<HdmiCecController*>(arg);
+ if (controller == NULL) {
return;
}
- // TODO: propagate message to Java layer.
+ switch (event->type) {
+ case HDMI_EVENT_CEC_MESSAGE:
+ controller->propagateCecCommand(event->cec);
+ break;
+ case HDMI_EVENT_HOT_PLUG:
+ controller->propagateHotplugEvent(event->hotplug);
+ break;
+ default:
+ ALOGE("Unsupported event type: %d", event->type);
+ break;
+ }
}
-
//------------------------------------------------------------------------------
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+ var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find method " methodName);
+
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj) {
- // TODO: initialize hal and pass it to controller if ready.
+ int err;
+ // If use same hardware module id between HdmiCecService and
+ // HdmiControlSservice it may conflict and cause abnormal state of HAL.
+ // TODO: use HDMI_CEC_HARDWARE_MODULE_ID of hdmi_cec.h for module id
+ // once migration to HdmiControlService is done.
+ hw_module_t* module;
+ err = hw_get_module("hdmi_cec_module",
+ const_cast<const hw_module_t **>(&module));
+ if (err != 0) {
+ ALOGE("Error acquiring hardware module: %d", err);
+ return 0;
+ }
+ hw_device_t* device;
+ // TODO: use HDMI_CEC_HARDWARE_INTERFACE of hdmi_cec.h for interface name
+ // once migration to HdmiControlService is done.
+ err = module->methods->open(module, "hdmi_cec_module_hw_if", &device);
+ if (err != 0) {
+ ALOGE("Error opening hardware module: %d", err);
+ return 0;
+ }
HdmiCecController* controller = new HdmiCecController(
+ reinterpret_cast<hdmi_cec_device*>(device),
env->NewGlobalRef(callbacksObj));
+ controller->init();
+
+ GET_METHOD_ID(gHdmiCecControllerClassInfo.handleIncomingCecCommand, clazz,
+ "handleIncomingCecCommand", "(II[B)V");
+ GET_METHOD_ID(gHdmiCecControllerClassInfo.handleHotplug, clazz,
+ "handleHotplug", "(Z)V");
return reinterpret_cast<jlong>(controller);
}
+static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr,
+ jint srcAddr, jint dstAddr, jbyteArray body) {
+ cec_message_t message;
+ message.initiator = static_cast<cec_logical_address_t>(srcAddr);
+ message.destination = static_cast<cec_logical_address_t>(dstAddr);
+
+ jsize len = env->GetArrayLength(body);
+ message.length = MIN(len, CEC_MESSAGE_BODY_MAX_LENGTH);
+ ScopedByteArrayRO bodyPtr(env, body);
+ std::memcpy(message.body, bodyPtr.get(), len);
+
+ HdmiCecController* controller =
+ reinterpret_cast<HdmiCecController*>(controllerPtr);
+ return controller->sendMessage(message);
+}
+
+static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz,
+ jlong controllerPtr, jint logicalAddress) {
+ HdmiCecController* controller =
+ reinterpret_cast<HdmiCecController*>(controllerPtr);
+ return controller->addLogicalAddress(
+ static_cast<cec_logical_address_t>(logicalAddress));
+}
+
+static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz,
+ jlong controllerPtr) {
+ HdmiCecController* controller =
+ reinterpret_cast<HdmiCecController*>(controllerPtr);
+ controller->clearLogicaladdress();
+}
+
+static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz,
+ jlong controllerPtr) {
+ HdmiCecController* controller =
+ reinterpret_cast<HdmiCecController*>(controllerPtr);
+ return controller->getPhysicalAddress();
+}
+
+static jint nativeGetVersion(JNIEnv* env, jclass clazz,
+ jlong controllerPtr) {
+ HdmiCecController* controller =
+ reinterpret_cast<HdmiCecController*>(controllerPtr);
+ return controller->getVersion();
+}
+
+static jint nativeGetVendorId(JNIEnv* env, jclass clazz, jlong controllerPtr) {
+ HdmiCecController* controller =
+ reinterpret_cast<HdmiCecController*>(controllerPtr);
+ return controller->getVendorId();
+}
+
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit", "(Lcom/android/server/hdmi/HdmiCecController;)J",
(void *) nativeInit },
+ { "nativeSendCecCommand", "(JII[B)I", (void *) nativeSendCecCommand },
+ { "nativeAddLogicalAddress", "(JI)I", (void *) nativeAddLogicalAddress },
+ { "nativeClearLogicalAddress", "(J)V", (void *) nativeClearLogicalAddress },
+ { "nativeGetPhysicalAddress", "(J)I", (void *) nativeGetPhysicalAddress },
+ { "nativeGetVersion", "(J)I", (void *) nativeGetVersion },
+ { "nativeGetVendorId", "(J)I", (void *) nativeGetVendorId },
};
#define CLASS_PATH "com/android/server/hdmi/HdmiCecController"
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index aaa97eb..9a9f1c8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -44,12 +44,13 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -99,6 +100,7 @@
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -231,6 +233,8 @@
static class ActiveAdmin {
private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
private static final String TAG_DISABLE_CAMERA = "disable-camera";
+ private static final String TAG_DISABLE_ACCOUNT_MANAGEMENT = "disable-account-management";
+ private static final String TAG_ACCOUNT_TYPE = "account-type";
private static final String TAG_ENCRYPTION_REQUESTED = "encryption-requested";
private static final String TAG_PASSWORD_EXPIRATION_DATE = "password-expiration-date";
private static final String TAG_PASSWORD_EXPIRATION_TIMEOUT = "password-expiration-timeout";
@@ -296,6 +300,7 @@
boolean encryptionRequested = false;
boolean disableCamera = false;
+ Set<String> accountTypesWithManagementDisabled = new HashSet<String>();
// TODO: review implementation decisions with frameworks team
boolean specifiesGlobalProxy = false;
@@ -412,6 +417,15 @@
out.attribute(null, ATTR_VALUE, Integer.toString(disabledKeyguardFeatures));
out.endTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
}
+ if (!accountTypesWithManagementDisabled.isEmpty()) {
+ out.startTag(null, TAG_DISABLE_ACCOUNT_MANAGEMENT);
+ for (String ac : accountTypesWithManagementDisabled) {
+ out.startTag(null, TAG_ACCOUNT_TYPE);
+ out.attribute(null, ATTR_VALUE, ac);
+ out.endTag(null, TAG_ACCOUNT_TYPE);
+ }
+ out.endTag(null, TAG_DISABLE_ACCOUNT_MANAGEMENT);
+ }
}
void readFromXml(XmlPullParser parser)
@@ -483,6 +497,23 @@
} else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) {
disabledKeyguardFeatures = Integer.parseInt(
parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_DISABLE_ACCOUNT_MANAGEMENT.equals(tag)) {
+ int outerDepthDAM = parser.getDepth();
+ int typeDAM;
+ while ((typeDAM=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (typeDAM != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepthDAM)) {
+ if (typeDAM == XmlPullParser.END_TAG || typeDAM == XmlPullParser.TEXT) {
+ continue;
+ }
+ String tagDAM = parser.getName();
+ if (TAG_ACCOUNT_TYPE.equals(tagDAM)) {
+ accountTypesWithManagementDisabled.add(
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else {
+ Slog.w(LOG_TAG, "Unknown tag under " + tag + ": " + tagDAM);
+ }
+ }
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
}
@@ -588,6 +619,7 @@
filter.addAction(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_STARTED);
filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
@@ -2531,7 +2563,7 @@
exclusionList = exclusionList.trim();
ContentResolver res = mContext.getContentResolver();
- ProxyProperties proxyProperties = new ProxyProperties(data[0], proxyPort, exclusionList);
+ ProxyInfo proxyProperties = new ProxyInfo(data[0], proxyPort, exclusionList);
if (!proxyProperties.isValid()) {
Slog.e(LOG_TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
return;
@@ -3022,6 +3054,7 @@
}
}
+ @Override
public void addPersistentPreferredActivity(ComponentName who, IntentFilter filter,
ComponentName activity) {
synchronized (this) {
@@ -3042,6 +3075,7 @@
}
}
+ @Override
public void clearPackagePersistentPreferredActivities(ComponentName who, String packageName) {
synchronized (this) {
if (who == null) {
@@ -3081,7 +3115,7 @@
}
}
- public void forwardMatchingIntents(ComponentName who, IntentFilter filter, int flags) {
+ public void addForwardingIntentFilter(ComponentName who, IntentFilter filter, int flags) {
int callingUserId = UserHandle.getCallingUserId();
synchronized (this) {
if (who == null) {
@@ -3093,10 +3127,12 @@
long id = Binder.clearCallingIdentity();
try {
if ((flags & DevicePolicyManager.FLAG_TO_PRIMARY_USER) != 0) {
- pm.addForwardingIntentFilter(filter, callingUserId, UserHandle.USER_OWNER);
+ pm.addForwardingIntentFilter(filter, true /*removable*/, callingUserId,
+ UserHandle.USER_OWNER);
}
if ((flags & DevicePolicyManager.FLAG_TO_MANAGED_PROFILE) != 0) {
- pm.addForwardingIntentFilter(filter, UserHandle.USER_OWNER, callingUserId);
+ pm.addForwardingIntentFilter(filter, true /*removable*/, UserHandle.USER_OWNER,
+ callingUserId);
}
} catch (RemoteException re) {
// Shouldn't happen
@@ -3165,4 +3201,147 @@
}
}
}
+
+ @Override
+ public void enableSystemApp(ComponentName who, String packageName) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+ int userId = UserHandle.getCallingUserId();
+ long id = Binder.clearCallingIdentity();
+
+ try {
+ UserManager um = UserManager.get(mContext);
+ if (!um.getUserInfo(userId).isManagedProfile()) {
+ throw new IllegalStateException(
+ "Only call this method from a managed profile.");
+ }
+
+ // TODO: Use UserManager::getProfileParent when available.
+ UserInfo primaryUser = um.getUserInfo(UserHandle.USER_OWNER);
+
+ if (DBG) {
+ Slog.v(LOG_TAG, "installing " + packageName + " for "
+ + userId);
+ }
+
+ IPackageManager pm = AppGlobals.getPackageManager();
+ if (!isSystemApp(pm, packageName, primaryUser.id)) {
+ throw new IllegalArgumentException("Only system apps can be enabled this way.");
+ }
+
+ // Install the app.
+ pm.installExistingPackageAsUser(packageName, userId);
+
+ } catch (RemoteException re) {
+ // shouldn't happen
+ Slog.wtf(LOG_TAG, "Failed to install " + packageName, re);
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ }
+ }
+
+ @Override
+ public int enableSystemAppWithIntent(ComponentName who, Intent intent) {
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+ int userId = UserHandle.getCallingUserId();
+ long id = Binder.clearCallingIdentity();
+
+ try {
+ UserManager um = UserManager.get(mContext);
+ if (!um.getUserInfo(userId).isManagedProfile()) {
+ throw new IllegalStateException(
+ "Only call this method from a managed profile.");
+ }
+
+ // TODO: Use UserManager::getProfileParent when available.
+ UserInfo primaryUser = um.getUserInfo(UserHandle.USER_OWNER);
+
+ IPackageManager pm = AppGlobals.getPackageManager();
+ List<ResolveInfo> activitiesToEnable = pm.queryIntentActivities(intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ 0, // no flags
+ primaryUser.id);
+
+ if (DBG) Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable);
+ int numberOfAppsInstalled = 0;
+ if (activitiesToEnable != null) {
+ for (ResolveInfo info : activitiesToEnable) {
+ if (info.activityInfo != null) {
+
+ if (!isSystemApp(pm, info.activityInfo.packageName, primaryUser.id)) {
+ throw new IllegalArgumentException(
+ "Only system apps can be enabled this way.");
+ }
+
+
+ numberOfAppsInstalled++;
+ pm.installExistingPackageAsUser(info.activityInfo.packageName, userId);
+ }
+ }
+ }
+ return numberOfAppsInstalled;
+ } catch (RemoteException e) {
+ // shouldn't happen
+ Slog.wtf(LOG_TAG, "Failed to resolve intent for: " + intent);
+ return 0;
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ }
+ }
+
+ private boolean isSystemApp(IPackageManager pm, String packageName, int userId)
+ throws RemoteException {
+ ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0, userId);
+ return (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) > 0;
+ }
+
+ @Override
+ public void setAccountManagementDisabled(ComponentName who, String accountType,
+ boolean disabled) {
+ if (!mHasFeature) {
+ return;
+ }
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (disabled) {
+ ap.accountTypesWithManagementDisabled.add(accountType);
+ } else {
+ ap.accountTypesWithManagementDisabled.remove(accountType);
+ }
+ saveSettingsLocked(UserHandle.getCallingUserId());
+ }
+ }
+
+ @Override
+ public String[] getAccountTypesWithManagementDisabled() {
+ if (!mHasFeature) {
+ return null;
+ }
+ synchronized (this) {
+ DevicePolicyData policy = getUserData(UserHandle.getCallingUserId());
+ final int N = policy.mAdminList.size();
+ HashSet<String> resultSet = new HashSet<String>();
+ for (int i = 0; i < N; i++) {
+ ActiveAdmin admin = policy.mAdminList.get(i);
+ resultSet.addAll(admin.accountTypesWithManagementDisabled);
+ }
+ return resultSet.toArray(new String[resultSet.size()]);
+ }
+ }
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3d82027..716823c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -73,6 +73,7 @@
import com.android.server.net.NetworkStatsService;
import com.android.server.notification.NotificationManagerService;
import com.android.server.os.SchedulingPolicyService;
+import com.android.server.pm.BackgroundDexOptService;
import com.android.server.pm.Installer;
import com.android.server.pm.LauncherAppsService;
import com.android.server.pm.PackageManagerService;
@@ -604,6 +605,14 @@
if (!disableNetwork) {
try {
+ Slog.i(TAG, "Network Score Service");
+ networkScore = new NetworkScoreService(context);
+ ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore);
+ } catch (Throwable e) {
+ reportWtf("starting Network Score Service", e);
+ }
+
+ try {
Slog.i(TAG, "NetworkStats Service");
networkStats = new NetworkStatsService(context, networkManagement, alarm);
ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
@@ -641,6 +650,15 @@
}
try {
+ Slog.i(TAG, "Wi-Fi Scanning Service");
+ mSystemServiceManager.startService(
+ "com.android.server.wifi.WifiScanningService");
+
+ } catch (Throwable e) {
+ reportWtf("starting Wi-Fi Scanning Service", e);
+ }
+
+ try {
Slog.i(TAG, "Connectivity Service");
connectivity = new ConnectivityService(
context, networkManagement, networkStats, networkPolicy);
@@ -652,14 +670,6 @@
}
try {
- Slog.i(TAG, "Network Score Service");
- networkScore = new NetworkScoreService(context);
- ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore);
- } catch (Throwable e) {
- reportWtf("starting Network Score Service", e);
- }
-
- try {
Slog.i(TAG, "Network Service Discovery Service");
serviceDiscovery = NsdService.create(context);
ServiceManager.addService(
@@ -923,7 +933,6 @@
}
try {
- Slog.i(TAG, "MediaSessionService");
mSystemServiceManager.startService(MediaSessionService.class);
} catch (Throwable e) {
reportWtf("starting MediaSessionService", e);
@@ -963,6 +972,13 @@
} catch (Throwable e) {
Slog.e(TAG, "Failure starting TrustManagerService", e);
}
+
+ try {
+ Slog.i(TAG, "BackgroundDexOptService");
+ new BackgroundDexOptService(context);
+ } catch (Throwable e) {
+ reportWtf("starting BackgroundDexOptService", e);
+ }
}
try {
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index f5ac178..6822ee3 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -373,8 +373,9 @@
mUEventObserver.startObserving(USB_STATE_MATCH);
mUEventObserver.startObserving(ACCESSORY_START_MATCH);
- mContext.registerReceiver(
- mBootCompletedReceiver, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+ IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ mContext.registerReceiver(mBootCompletedReceiver, filter);
mContext.registerReceiver(
mUserSwitchedReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED));
} catch (Exception e) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 045c0f6..16afc8f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -28,6 +28,8 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionService;
@@ -88,6 +90,21 @@
private boolean mSafeMode;
private int mCurUser;
+ @Override
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ try {
+ return super.onTransact(code, data, reply, flags);
+ } catch (RuntimeException e) {
+ // The activity manager only throws security exceptions, so let's
+ // log all others.
+ if (!(e instanceof SecurityException)) {
+ Slog.wtf(TAG, "VoiceInteractionManagerService Crash", e);
+ }
+ throw e;
+ }
+ }
+
public void systemRunning(boolean safeMode) {
mSafeMode = safeMode;
@@ -97,18 +114,18 @@
synchronized (this) {
mCurUser = ActivityManager.getCurrentUser();
- switchImplementationIfNeededLocked();
+ switchImplementationIfNeededLocked(false);
}
}
public void switchUser(int userHandle) {
synchronized (this) {
mCurUser = userHandle;
- switchImplementationIfNeededLocked();
+ switchImplementationIfNeededLocked(false);
}
}
- void switchImplementationIfNeededLocked() {
+ void switchImplementationIfNeededLocked(boolean force) {
if (!mSafeMode) {
String curService = Settings.Secure.getStringForUser(
mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
@@ -121,7 +138,7 @@
serviceComponent = null;
}
}
- if (mImpl == null || mImpl.mUser != mCurUser
+ if (force || mImpl == null || mImpl.mUser != mCurUser
|| !mImpl.mComponent.equals(serviceComponent)) {
if (mImpl != null) {
mImpl.shutdownLocked();
@@ -138,10 +155,10 @@
}
@Override
- public void startVoiceActivity(Intent intent, String resolvedType,
- IVoiceInteractionService service, Bundle args) {
+ public void startSession(IVoiceInteractionService service, Bundle args) {
synchronized (this) {
- if (mImpl == null || service.asBinder() != mImpl.mService.asBinder()) {
+ if (mImpl == null || mImpl.mService == null
+ || service.asBinder() != mImpl.mService.asBinder()) {
throw new SecurityException(
"Caller is not the current voice interaction service");
}
@@ -149,8 +166,7 @@
final int callingUid = Binder.getCallingUid();
final long caller = Binder.clearCallingIdentity();
try {
- mImpl.startVoiceActivityLocked(callingPid, callingUid,
- intent, resolvedType, args);
+ mImpl.startSessionLocked(callingPid, callingUid, args);
} finally {
Binder.restoreCallingIdentity(caller);
}
@@ -158,12 +174,12 @@
}
@Override
- public int deliverNewSession(IBinder token, IVoiceInteractionSession session,
+ public boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
IVoiceInteractor interactor) {
synchronized (this) {
if (mImpl == null) {
- Slog.w(TAG, "deliverNewSession without running voice interaction service");
- return ActivityManager.START_CANCELED;
+ throw new SecurityException(
+ "deliverNewSession without running voice interaction service");
}
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
@@ -175,7 +191,43 @@
Binder.restoreCallingIdentity(caller);
}
}
+ }
+ @Override
+ public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "startVoiceActivity without running voice interaction service");
+ return ActivityManager.START_CANCELED;
+ }
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ return mImpl.startVoiceActivityLocked(callingPid, callingUid, token,
+ intent, resolvedType);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+ }
+
+ @Override
+ public void finish(IBinder token) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "finish without running voice interaction service");
+ return;
+ }
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ mImpl.finishLocked(callingPid, callingUid, token);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
}
@Override
@@ -207,7 +259,7 @@
@Override public void onChange(boolean selfChange) {
synchronized (VoiceInteractionManagerServiceStub.this) {
- switchImplementationIfNeededLocked();
+ switchImplementationIfNeededLocked(false);
}
}
}
@@ -220,27 +272,25 @@
@Override
public void onHandleUserStop(Intent intent, int userHandle) {
- super.onHandleUserStop(intent, userHandle);
}
@Override
public void onPackageDisappeared(String packageName, int reason) {
- super.onPackageDisappeared(packageName, reason);
}
@Override
public void onPackageAppeared(String packageName, int reason) {
- super.onPackageAppeared(packageName, reason);
+ if (mImpl != null && packageName.equals(mImpl.mComponent.getPackageName())) {
+ switchImplementationIfNeededLocked(true);
+ }
}
@Override
public void onPackageModified(String packageName) {
- super.onPackageModified(packageName);
}
@Override
public void onSomePackagesChanged() {
- super.onSomePackagesChanged();
}
};
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 6bbd1c1..9b6daad 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -19,9 +19,11 @@
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
@@ -30,6 +32,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionSession;
@@ -37,6 +40,8 @@
import android.service.voice.VoiceInteractionService;
import android.service.voice.VoiceInteractionServiceInfo;
import android.util.Slog;
+import android.view.IWindowManager;
+import android.view.WindowManager;
import com.android.internal.app.IVoiceInteractor;
import java.io.FileDescriptor;
@@ -55,11 +60,28 @@
final IActivityManager mAm;
final VoiceInteractionServiceInfo mInfo;
final ComponentName mSessionComponentName;
+ final IWindowManager mIWindowManager;
boolean mBound = false;
IVoiceInteractionService mService;
SessionConnection mActiveSession;
+ final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+ synchronized (mLock) {
+ if (mActiveSession != null && mActiveSession.mSession != null) {
+ try {
+ mActiveSession.mSession.closeSystemDialogs();
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+ }
+ };
+
final ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
@@ -76,23 +98,26 @@
final class SessionConnection implements ServiceConnection {
final IBinder mToken = new Binder();
- final Intent mIntent;
- final String mResolvedType;
final Bundle mArgs;
boolean mBound;
IVoiceInteractionSessionService mService;
IVoiceInteractionSession mSession;
IVoiceInteractor mInteractor;
- SessionConnection(Intent intent, String resolvedType, Bundle args) {
- mIntent = intent;
- mResolvedType = resolvedType;
+ SessionConnection(Bundle args) {
mArgs = args;
Intent serviceIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
serviceIntent.setComponent(mSessionComponentName);
mBound = mContext.bindServiceAsUser(serviceIntent, this,
Context.BIND_AUTO_CREATE, new UserHandle(mUser));
- if (!mBound) {
+ if (mBound) {
+ try {
+ mIWindowManager.addWindowToken(mToken,
+ WindowManager.LayoutParams.TYPE_INPUT_METHOD);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed adding window token", e);
+ }
+ } else {
Slog.w(TAG, "Failed binding to voice interaction session service " + mComponent);
}
}
@@ -105,7 +130,7 @@
try {
mService.newSession(mToken, mArgs);
} catch (RemoteException e) {
- Slog.w(TAG, "Failed making new session", e);
+ Slog.w(TAG, "Failed adding window token", e);
}
}
}
@@ -118,7 +143,19 @@
public void cancel() {
if (mBound) {
+ if (mSession != null) {
+ try {
+ mSession.destroy();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Voice interation session already dead");
+ }
+ }
mContext.unbindService(this);
+ try {
+ mIWindowManager.removeWindowToken(mToken);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed removing window token", e);
+ }
mBound = false;
mService = null;
mSession = null;
@@ -128,8 +165,6 @@
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("mToken="); pw.println(mToken);
- pw.print(prefix); pw.print("mIntent="); pw.println(mIntent);
- pw.print(" mResolvedType="); pw.println(mResolvedType);
pw.print(prefix); pw.print("mArgs="); pw.println(mArgs);
pw.print(prefix); pw.print("mBound="); pw.println(mBound);
if (mBound) {
@@ -155,6 +190,7 @@
Slog.w(TAG, "Voice interaction service not found: " + service);
mInfo = null;
mSessionComponentName = null;
+ mIWindowManager = null;
mValid = false;
return;
}
@@ -162,43 +198,67 @@
if (mInfo.getParseError() != null) {
Slog.w(TAG, "Bad voice interaction service: " + mInfo.getParseError());
mSessionComponentName = null;
+ mIWindowManager = null;
mValid = false;
return;
}
mValid = true;
mSessionComponentName = new ComponentName(service.getPackageName(),
mInfo.getSessionService());
+ mIWindowManager = IWindowManager.Stub.asInterface(
+ ServiceManager.getService(Context.WINDOW_SERVICE));
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ mContext.registerReceiver(mBroadcastReceiver, filter, null, handler);
}
- public void startVoiceActivityLocked(int callingPid, int callingUid, Intent intent,
- String resolvedType, Bundle args) {
+ public void startSessionLocked(int callingPid, int callingUid, Bundle args) {
if (mActiveSession != null) {
mActiveSession.cancel();
mActiveSession = null;
}
- mActiveSession = new SessionConnection(intent, resolvedType, args);
- intent.addCategory(Intent.CATEGORY_VOICE);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ mActiveSession = new SessionConnection(args);
}
- public int deliverNewSessionLocked(int callingPid, int callingUid, IBinder token,
+ public boolean deliverNewSessionLocked(int callingPid, int callingUid, IBinder token,
IVoiceInteractionSession session, IVoiceInteractor interactor) {
+ if (mActiveSession == null || token != mActiveSession.mToken) {
+ Slog.w(TAG, "deliverNewSession does not match active session");
+ return false;
+ }
+ mActiveSession.mSession = session;
+ mActiveSession.mInteractor = interactor;
+ return true;
+ }
+
+ public int startVoiceActivityLocked(int callingPid, int callingUid, IBinder token,
+ Intent intent, String resolvedType) {
try {
if (mActiveSession == null || token != mActiveSession.mToken) {
- Slog.w(TAG, "deliverNewSession does not match active session");
+ Slog.w(TAG, "startVoiceActivity does not match active session");
return ActivityManager.START_CANCELED;
}
- mActiveSession.mSession = session;
- mActiveSession.mInteractor = interactor;
+ intent = new Intent(intent);
+ intent.addCategory(Intent.CATEGORY_VOICE);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
return mAm.startVoiceActivity(mComponent.getPackageName(), callingPid, callingUid,
- mActiveSession.mIntent, mActiveSession.mResolvedType,
- mActiveSession.mSession, mActiveSession.mInteractor,
+ intent, resolvedType, mActiveSession.mSession, mActiveSession.mInteractor,
0, null, null, null, mUser);
} catch (RemoteException e) {
throw new IllegalStateException("Unexpected remote error", e);
}
}
+
+ public void finishLocked(int callingPid, int callingUid, IBinder token) {
+ if (mActiveSession == null || token != mActiveSession.mToken) {
+ Slog.w(TAG, "finish does not match active session");
+ return;
+ }
+ mActiveSession.cancel();
+ mActiveSession = null;
+ }
+
public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!mValid) {
pw.print(" NOT VALID: ");
@@ -234,5 +294,8 @@
mContext.unbindService(mConnection);
mBound = false;
}
+ if (mValid) {
+ mContext.unregisterReceiver(mBroadcastReceiver);
+ }
}
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 606fcb4..1ee390f 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -797,6 +797,8 @@
return TelephonyManager.NETWORK_TYPE_LTE;
case ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP:
return TelephonyManager.NETWORK_TYPE_HSPAP;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_GSM:
+ return TelephonyManager.NETWORK_TYPE_GSM;
default:
return TelephonyManager.NETWORK_TYPE_UNKNOWN;
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 407a8d1..df972d5 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -911,6 +911,8 @@
public static final int NETWORK_TYPE_EHRPD = 14;
/** Current network is HSPA+ */
public static final int NETWORK_TYPE_HSPAP = 15;
+ /** Current network is GSM {@hide} */
+ public static final int NETWORK_TYPE_GSM = 16;
/**
* @return the NETWORK_TYPE_xxxx for current data connection.
@@ -1002,6 +1004,7 @@
public static int getNetworkClass(int networkType) {
switch (networkType) {
case NETWORK_TYPE_GPRS:
+ case NETWORK_TYPE_GSM:
case NETWORK_TYPE_EDGE:
case NETWORK_TYPE_CDMA:
case NETWORK_TYPE_1xRTT:
@@ -1068,6 +1071,8 @@
return "iDEN";
case NETWORK_TYPE_HSPAP:
return "HSPA+";
+ case NETWORK_TYPE_GSM:
+ return "GSM";
default:
return "UNKNOWN";
}
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 992ef4b..a016933 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -701,4 +701,21 @@
VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
throw new UnsupportedOperationException();
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public void addForwardingIntentFilter(IntentFilter filter, boolean removable, int userIdOrig,
+ int userIdDest) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void clearForwardingIntentFilters(int userIdOrig) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 5c2583b..3e9cf43c 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -232,6 +232,15 @@
<category android:name="com.android.test.hwui.TEST" />
</intent-filter>
</activity>
+
+ <activity
+ android:name="LooperAcceleration"
+ android:label="Misc/LooperAcceleration">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.hwui.TEST" />
+ </intent-filter>
+ </activity>
<activity
android:name="TextFadeActivity"
@@ -288,6 +297,15 @@
</activity>
<activity
+ android:name="CirclePropActivity"
+ android:label="Draw/Circle Props">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.hwui.TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="ClearActivity"
android:label="Window/Clear">
<intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
new file mode 100644
index 0000000..5c273de1
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
@@ -0,0 +1,146 @@
+/*
+ * 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.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.os.Bundle;
+import android.os.Trace;
+import android.view.HardwareCanvas;
+import android.view.RenderNodeAnimator;
+import android.view.View;
+import android.webkit.WebChromeClient;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+import android.widget.ProgressBar;
+
+import java.util.ArrayList;
+
+public class CirclePropActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+ ProgressBar spinner = new ProgressBar(this, null, android.R.attr.progressBarStyleLarge);
+ layout.addView(spinner, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+ // For testing with a functor in the tree
+// WebView wv = new WebView(this);
+// wv.setWebViewClient(new WebViewClient());
+// wv.setWebChromeClient(new WebChromeClient());
+// wv.loadUrl("http://theverge.com");
+// layout.addView(wv, new LayoutParams(LayoutParams.MATCH_PARENT, 100));
+
+ layout.addView(new CircleView(this),
+ new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+
+ setContentView(layout);
+ }
+
+ static class CircleView extends View {
+ static final int DURATION = 500;
+
+ private boolean mToggle = false;
+ ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<RenderNodeAnimator>();
+
+ CanvasProperty<Float> mX;
+ CanvasProperty<Float> mY;
+ CanvasProperty<Float> mRadius;
+ CanvasProperty<Paint> mPaint;
+
+ CircleView(Context c) {
+ super(c);
+ setClickable(true);
+
+ mX = CanvasProperty.createFloat(200.0f);
+ mY = CanvasProperty.createFloat(200.0f);
+ mRadius = CanvasProperty.createFloat(150.0f);
+
+ Paint p = new Paint();
+ p.setAntiAlias(true);
+ p.setColor(0xFFFF0000);
+ p.setStyle(Style.STROKE);
+ p.setStrokeWidth(60.0f);
+ mPaint = CanvasProperty.createPaint(p);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (canvas.isHardwareAccelerated()) {
+ HardwareCanvas hwcanvas = (HardwareCanvas) canvas;
+ hwcanvas.drawCircle(mX, mY, mRadius, mPaint);
+ }
+ }
+
+ @Override
+ public boolean performClick() {
+ for (int i = 0; i < mRunningAnimations.size(); i++) {
+ mRunningAnimations.get(i).cancel();
+ }
+ mRunningAnimations.clear();
+
+ mToggle = !mToggle;
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mX, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 400.0f : 200.0f));
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mY, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 600.0f : 200.0f));
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mRadius, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 250.0f : 150.0f));
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mPaint, RenderNodeAnimator.PAINT_ALPHA,
+ RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 64.0f : 255.0f));
+
+ mRunningAnimations.add(new RenderNodeAnimator(
+ mPaint, RenderNodeAnimator.PAINT_STROKE_WIDTH,
+ RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 5.0f : 60.0f));
+
+ for (int i = 0; i < mRunningAnimations.size(); i++) {
+ mRunningAnimations.get(i).start(this);
+ }
+
+ if (mToggle) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "pretendBusy");
+ try {
+ Thread.sleep(DURATION);
+ } catch (InterruptedException e) {
+ }
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ });
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java b/tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java
new file mode 100644
index 0000000..20d8e11
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.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.test.hwui;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.graphics.Canvas;
+import android.os.Bundle;
+import android.os.Looper;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.webkit.WebChromeClient;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.LinearLayout;
+
+public class LooperAcceleration extends Activity {
+
+ static final boolean INCLUDE_WEBVIEW = false;
+
+ static class IsAcceleratedView extends View {
+
+ public IsAcceleratedView(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (canvas.isHardwareAccelerated()) {
+ canvas.drawARGB(0xFF, 0x00, 0xFF, 0x00);
+ } else {
+ canvas.drawARGB(0xFF, 0xFF, 0x00, 0x00);
+ }
+ }
+
+ }
+
+ private View makeView() {
+ LinearLayout layout = new LinearLayout(this);
+ layout.addView(new IsAcceleratedView(this), LayoutParams.MATCH_PARENT, 60);
+
+ if (INCLUDE_WEBVIEW) {
+ WebView wv = new WebView(this);
+ wv.setWebViewClient(new WebViewClient());
+ wv.setWebChromeClient(new WebChromeClient());
+ wv.loadUrl("http://www.webkit.org/blog-files/3d-transforms/poster-circle.html");
+ layout.addView(wv, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ }
+ return layout;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(makeView());
+
+ new Thread() {
+ @Override
+ public void run() {
+ Looper.prepare();
+ final Context context = LooperAcceleration.this;
+ Dialog dlg = new Dialog(context);
+ dlg.addContentView(makeView(), new LayoutParams(300, 400));
+ dlg.setCancelable(true);
+ dlg.setCanceledOnTouchOutside(true);
+ dlg.setOnDismissListener(new DialogInterface.OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ Looper.myLooper().quit();
+ }
+ });
+ dlg.setTitle("Not Looper.getMainLooper() check");
+ dlg.show();
+ Looper.loop();
+ }
+ }.start();
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java
index 8c02539..a3f4ddc 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java
@@ -57,7 +57,7 @@
mPaint = new Paint();
mPaint.setAntiAlias(true);
- mPaint.setColor(0xffffffff);
+ mPaint.setColor(0xff00ffff);
}
@Override
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
index 5dc3904..b7dcef7 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
@@ -84,11 +84,12 @@
Log.d(TAG, "Creating session for package " + mContext.getBasePackageName());
mSession = man.createSession("OneMedia");
mSession.addCallback(mCallback);
- mPerformer = mSession.setTransportPerformerEnabled();
+ mPerformer = mSession.getTransportPerformer();
mPerformer.addListener(new TransportListener());
mPerformer.setPlaybackState(mPlaybackState);
+ mSession.setFlags(Session.FLAG_HANDLES_TRANSPORT_CONTROLS);
mSession.setRouteOptions(mRouteOptions);
- mSession.publish();
+ mSession.setActive(true);
}
public void onDestroy() {
@@ -119,7 +120,9 @@
}
private void updateState(int newState) {
- mPlaybackState.setState(newState);
+ float rate = newState == PlaybackState.PLAYSTATE_PLAYING ? 1 : 0;
+ long position = mRenderer == null ? -1 : mRenderer.getSeekPosition();
+ mPlaybackState.setState(newState, position, rate);
mPerformer.setPlaybackState(mPlaybackState);
}
@@ -132,7 +135,7 @@
@Override
public void onError(int type, int extra, Bundle extras, Throwable error) {
Log.d(TAG, "Sending onError with type " + type + " and extra " + extra);
- mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR);
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR, -1, 0);
if (error != null) {
mPlaybackState.setErrorMessage(error.getLocalizedMessage());
}
@@ -147,34 +150,33 @@
if (newState != Renderer.STATE_ERROR) {
mPlaybackState.setErrorMessage(null);
}
+ long position = -1;
+ if (mRenderer != null) {
+ position = mRenderer.getSeekPosition();
+ }
switch (newState) {
case Renderer.STATE_ENDED:
case Renderer.STATE_STOPPED:
- mPlaybackState.setState(PlaybackState.PLAYSTATE_STOPPED);
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_STOPPED, position, 0);
break;
case Renderer.STATE_INIT:
case Renderer.STATE_PREPARING:
- mPlaybackState.setState(PlaybackState.PLAYSTATE_BUFFERING);
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_BUFFERING, position, 0);
break;
case Renderer.STATE_ERROR:
- mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR);
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR, position, 0);
break;
case Renderer.STATE_PAUSED:
- mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED);
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED, position, 0);
break;
case Renderer.STATE_PLAYING:
- mPlaybackState.setState(PlaybackState.PLAYSTATE_PLAYING);
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_PLAYING, position, 1);
break;
default:
- mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR);
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR, position, 0);
mPlaybackState.setErrorMessage("unkown state");
break;
}
- if (mRenderer != null) {
- mPlaybackState.setPosition(mRenderer.getSeekPosition());
- } else {
- mPlaybackState.setPosition(-1);
- }
mPerformer.setPlaybackState(mPlaybackState);
if (mListener != null) {
mListener.onPlayStateChanged(mPlaybackState);
@@ -188,8 +190,8 @@
@Override
public void onFocusLost() {
Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED);
- mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED);
- mPlaybackState.setPosition(mRenderer.getSeekPosition());
+ long position = mRenderer == null ? -1 : mRenderer.getSeekPosition();
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED, position, 0);
mPerformer.setPlaybackState(mPlaybackState);
if (mListener != null) {
mListener.onPlayStateChanged(mPlaybackState);
diff --git a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
index 6edcd7d..6537d49 100644
--- a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
+++ b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
@@ -158,30 +158,33 @@
if (newState != Renderer.STATE_ERROR) {
mPlaybackState.setErrorMessage(null);
}
+ long position = -1;
+ if (mRenderer != null) {
+ position = mRenderer.getSeekPosition();
+ }
switch (newState) {
case Renderer.STATE_ENDED:
case Renderer.STATE_STOPPED:
- mPlaybackState.setState(PlaybackState.PLAYSTATE_STOPPED);
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_STOPPED, position, 0);
break;
case Renderer.STATE_INIT:
case Renderer.STATE_PREPARING:
- mPlaybackState.setState(PlaybackState.PLAYSTATE_BUFFERING);
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_BUFFERING, position, 0);
break;
case Renderer.STATE_ERROR:
- mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR);
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR, position, 0);
break;
case Renderer.STATE_PAUSED:
- mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED);
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED, position, 0);
break;
case Renderer.STATE_PLAYING:
- mPlaybackState.setState(PlaybackState.PLAYSTATE_PLAYING);
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_PLAYING, position, 1);
break;
default:
- mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR);
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR, position, 0);
mPlaybackState.setErrorMessage("unkown state");
break;
}
- mPlaybackState.setPosition(mRenderer.getSeekPosition());
mControls.sendPlaybackChangeEvent(mPlaybackState.getState());
}
@@ -193,8 +196,8 @@
@Override
public void onFocusLost() {
Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED);
- mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED);
- mPlaybackState.setPosition(mRenderer.getSeekPosition());
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED, mRenderer.getSeekPosition(), 0);
+ mRenderer.onPause();
}
@Override
diff --git a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
index 1d209dd..8f9cf58 100644
--- a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
+++ b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
@@ -19,8 +19,6 @@
public class MainActivity extends Activity implements OnItemClickListener {
- static final int TRANSLATION_Y = 1;
- static final int DELTA_TYPE_DELTA = 1;
static final int DURATION = 400;
static final String KEY_NAME = "name";
@@ -75,7 +73,7 @@
float delta = (pos - clickedPosition) * 1.1f;
if (delta == 0) delta = -1;
RenderNodeAnimator animator = new RenderNodeAnimator(
- TRANSLATION_Y, DELTA_TYPE_DELTA, dy * delta);
+ RenderNodeAnimator.TRANSLATION_Y, RenderNodeAnimator.DELTA_TYPE_DELTA, dy * delta);
animator.setDuration(DURATION);
animator.start(child);
}
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
index 88ae398..7ba01b1 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
@@ -22,7 +22,7 @@
import android.widget.GridLayout;
@SuppressWarnings({"UnusedDeclaration"})
-public class VectorDrawable01 extends Activity implements View.OnClickListener {
+public class VectorDrawable01 extends Activity {
private static final String LOGCAT = "VectorDrawable1";
int[] icon = {
R.drawable.vector_drawable01,
@@ -61,28 +61,10 @@
button.setWidth(200);
button.setBackgroundResource(icon[i]);
container.addView(button);
- button.setOnClickListener(this);
}
- Button b = new Button(this);
- b.setText("Run All");
- b.setOnClickListener(new View.OnClickListener(){
- @Override
- public void onClick(View v) {
- for (int i = 0; i < bArray.length; i++) {
- VectorDrawable d = (VectorDrawable) bArray[i].getBackground();
- d.start();
- }
- }});
- container.addView(b);
setContentView(container);
}
- @Override
- public void onClick(View v) {
- VectorDrawable d = (VectorDrawable) v.getBackground();
- d.start();
- }
-
}
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
index 3929298..b918cdd 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -25,7 +25,7 @@
import java.text.DecimalFormat;
@SuppressWarnings({"UnusedDeclaration"})
-public class VectorDrawablePerformance extends Activity implements View.OnClickListener {
+public class VectorDrawablePerformance extends Activity {
private static final String LOGCAT = "VectorDrawable1";
protected int[] icon = {
R.drawable.vector_drawable01,
@@ -76,7 +76,6 @@
button.setWidth(200);
button.setBackgroundResource(icon[i]);
container.addView(button);
- button.setOnClickListener(this);
}
setContentView(scrollView);
time = android.os.SystemClock.elapsedRealtimeNanos()-time;
@@ -85,10 +84,4 @@
t.setBackgroundColor(0xFF000000);
container.addView(t);
}
-
- @Override
- public void onClick(View v) {
- VectorDrawable d = (VectorDrawable) v.getBackground();
- d.start();
- }
}
diff --git a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
new file mode 100644
index 0000000..9fcbf3e
--- /dev/null
+++ b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
@@ -0,0 +1,38 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:background="#ffffffff"
+ >
+
+ <TextView android:id="@+id/text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="32dp"
+ />
+
+ <Button android:id="@+id/start"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/start"
+ />
+
+</LinearLayout>
+
+
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
index 008d97b..d40b05f 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
@@ -17,6 +17,7 @@
package com.android.test.voiceinteraction;
import android.content.Intent;
+import android.os.Bundle;
import android.service.voice.VoiceInteractionService;
import android.util.Log;
@@ -31,7 +32,9 @@
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
- startVoiceActivity(new Intent(this, TestInteractionActivity.class), null);
+ Bundle args = new Bundle();
+ args.putParcelable("intent", new Intent(this, TestInteractionActivity.class));
+ startSession(args);
stopSelf(startId);
return START_NOT_STICKY;
}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index 0fc563b3..a3af284 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -17,18 +17,59 @@
package com.android.test.voiceinteraction;
import android.content.Context;
+import android.content.Intent;
import android.os.Bundle;
import android.service.voice.VoiceInteractionSession;
import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
-public class MainInteractionSession extends VoiceInteractionSession {
+public class MainInteractionSession extends VoiceInteractionSession
+ implements View.OnClickListener {
static final String TAG = "MainInteractionSession";
- final Bundle mArgs;
+ Intent mStartIntent;
+ View mContentView;
+ TextView mText;
+ Button mStartButton;
- MainInteractionSession(Context context, Bundle args) {
+ Request mPendingRequest;
+ boolean mPendingConfirm;
+
+ MainInteractionSession(Context context) {
super(context);
- mArgs = args;
+ }
+
+ @Override
+ public void onCreate(Bundle args) {
+ super.onCreate(args);
+ showWindow();
+ mStartIntent = args.getParcelable("intent");
+ }
+
+ @Override
+ public View onCreateContentView() {
+ mContentView = getLayoutInflater().inflate(R.layout.voice_interaction_session, null);
+ mText = (TextView)mContentView.findViewById(R.id.text);
+ mStartButton = (Button)mContentView.findViewById(R.id.start);
+ mStartButton.setOnClickListener(this);
+ return mContentView;
+ }
+
+ public void onClick(View v) {
+ if (mPendingRequest == null) {
+ mStartButton.setEnabled(false);
+ startVoiceActivity(mStartIntent);
+ } else {
+ if (mPendingConfirm) {
+ mPendingRequest.sendConfirmResult(true, null);
+ } else {
+ mPendingRequest.sendCommandResult(true, null);
+ }
+ mPendingRequest = null;
+ mStartButton.setText("Start");
+ }
}
@Override
@@ -38,14 +79,22 @@
@Override
public void onConfirm(Caller caller, Request request, String prompt, Bundle extras) {
- Log.i(TAG, "onConform: prompt=" + prompt + " extras=" + extras);
- request.sendConfirmResult(true, null);
+ Log.i(TAG, "onConfirm: prompt=" + prompt + " extras=" + extras);
+ mText.setText(prompt);
+ mStartButton.setEnabled(true);
+ mStartButton.setText("Confirm");
+ mPendingRequest = request;
+ mPendingConfirm = true;
}
@Override
public void onCommand(Caller caller, Request request, String command, Bundle extras) {
Log.i(TAG, "onCommand: command=" + command + " extras=" + extras);
- request.sendCommandResult(true, null);
+ mText.setText("Command: " + command);
+ mStartButton.setEnabled(true);
+ mStartButton.setText("Finish Command");
+ mPendingRequest = request;
+ mPendingConfirm = false;
}
@Override
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java
index 8864d71..7cf8178 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java
@@ -23,6 +23,6 @@
public class MainInteractionSessionService extends VoiceInteractionSessionService {
@Override
public VoiceInteractionSession onNewSession(Bundle args) {
- return new MainInteractionSession(this, args);
+ return new MainInteractionSession(this);
}
}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index d0581f6..1348be3 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1261,12 +1261,13 @@
while ((err=it.next()) == NO_ERROR) {
String8 src = it.getFile()->getPrintableSource();
err = compileXmlFile(assets, it.getFile(), &table, xmlFlags);
- if (err != NO_ERROR) {
+ if (err == NO_ERROR) {
+ ResXMLTree block;
+ block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true);
+ checkForIds(src, block);
+ } else {
hasErrors = true;
}
- ResXMLTree block;
- block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true);
- checkForIds(src, block);
}
if (err < NO_ERROR) {
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index b445b8a..6eab65b 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -865,6 +865,21 @@
pseudoBidiParams.country[0] = 'X';
pseudoBidiParams.country[1] = 'B';
+ // We should skip resources for pseudolocales if they were
+ // already added automatically. This is a fix for a transition period when
+ // manually pseudolocalized resources may be expected.
+ // TODO: remove this check after next SDK version release.
+ if ((bundle->getPseudolocalize() & PSEUDO_ACCENTED &&
+ curParams.locale == pseudoParams.locale) ||
+ (bundle->getPseudolocalize() & PSEUDO_BIDI &&
+ curParams.locale == pseudoBidiParams.locale)) {
+ SourcePos(in->getPrintableSource(), 0).warning(
+ "Resource file %s is skipped as pseudolocalization"
+ " was done automatically.",
+ in->getPrintableSource().string());
+ return NO_ERROR;
+ }
+
while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::START_TAG) {
const String16* curTag = NULL;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index bb05d45..aede236 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -71,7 +71,7 @@
* Returns the native delegate associated to a given {@link Canvas} object.
*/
public static Canvas_Delegate getDelegate(Canvas canvas) {
- return sManager.getDelegate(canvas.mNativeCanvas);
+ return sManager.getDelegate(canvas.getNativeCanvas());
}
/**
@@ -102,7 +102,7 @@
@LayoutlibDelegate
/*package*/ static boolean isOpaque(Canvas thisCanvas) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return false;
}
@@ -113,7 +113,7 @@
@LayoutlibDelegate
/*package*/ static int getWidth(Canvas thisCanvas) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return 0;
}
@@ -124,7 +124,7 @@
@LayoutlibDelegate
/*package*/ static int getHeight(Canvas thisCanvas) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return 0;
}
@@ -135,7 +135,7 @@
@LayoutlibDelegate
/*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -146,7 +146,7 @@
@LayoutlibDelegate
/*package*/ static void rotate(Canvas thisCanvas, float degrees) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -157,7 +157,7 @@
@LayoutlibDelegate
/*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -168,7 +168,7 @@
@LayoutlibDelegate
/*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -204,7 +204,7 @@
/*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
float bottom) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return false;
}
@@ -227,7 +227,7 @@
@LayoutlibDelegate
/*package*/ static int save(Canvas thisCanvas, int saveFlags) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return 0;
}
@@ -238,7 +238,7 @@
@LayoutlibDelegate
/*package*/ static void restore(Canvas thisCanvas) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -249,7 +249,7 @@
@LayoutlibDelegate
/*package*/ static int getSaveCount(Canvas thisCanvas) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return 0;
}
@@ -260,7 +260,7 @@
@LayoutlibDelegate
/*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
// get the delegate from the native int.
- Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
if (canvasDelegate == null) {
return;
}
@@ -287,7 +287,7 @@
/*package*/ static void drawLines(Canvas thisCanvas,
final float[] pts, final int offset, final int count,
Paint paint) {
- draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/,
+ draw(thisCanvas.getNativeCanvas(), paint.mNativePaint, false /*compositeOnly*/,
false /*forceSrcMode*/, new GcSnapshot.Drawable() {
@Override
public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
diff --git a/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
index 4bef424..cdb839ad 100644
--- a/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
@@ -16,6 +16,12 @@
package com.android.internal.view.menu;
+import com.android.layoutlib.bridge.android.BridgeContext;
+
+import android.content.Context;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+
/**
* An extension of the {@link MenuItemImpl} to store the view cookie also.
*/
@@ -27,6 +33,7 @@
* at the time of rendering.
*/
private Object viewCookie;
+ private BridgeContext mContext;
/**
* Instantiates this menu item.
@@ -34,14 +41,28 @@
BridgeMenuItemImpl(MenuBuilder menu, int group, int id, int categoryOrder, int ordering,
CharSequence title, int showAsAction) {
super(menu, group, id, categoryOrder, ordering, title, showAsAction);
+ Context context = menu.getContext();
+ if (context instanceof ContextThemeWrapper) {
+ context = ((ContextThemeWrapper) context).getBaseContext();
+ }
+ if (context instanceof BridgeContext) {
+ mContext = ((BridgeContext) context);
+ }
}
-
public Object getViewCookie() {
return viewCookie;
}
public void setViewCookie(Object viewCookie) {
+ // If the menu item has an associated action provider view,
+ // directly set the cookie in the view to cookie map stored in BridgeContext.
+ View actionView = getActionView();
+ if (actionView != null && mContext != null) {
+ mContext.addViewKey(actionView, viewCookie);
+ // We don't need to add the view cookie to the this item now. But there's no harm in
+ // storing it, in case we need it in the future.
+ }
this.viewCookie = viewCookie;
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
index 08512e7..936ab4f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
@@ -50,6 +50,7 @@
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ActionMenuView;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
@@ -179,8 +180,9 @@
Predicate<View> overflowMenuButtonTest = new Predicate<View>() {
@Override
public boolean apply(View view) {
- return view.getClass().getName()
- .equals("android.widget.ActionMenuPresenter$OverflowMenuButton");
+ ViewGroup.LayoutParams lp = view.getLayoutParams();
+ return lp instanceof ActionMenuView.LayoutParams &&
+ ((ActionMenuView.LayoutParams) lp).isOverflowButton;
}
};
View overflowMenu = null;
diff --git a/core/res/res/drawable/stat_sys_adb.xml b/wifi/java/android/net/wifi/IWifiScanner.aidl
similarity index 61%
copy from core/res/res/drawable/stat_sys_adb.xml
copy to wifi/java/android/net/wifi/IWifiScanner.aidl
index dfc8563..fef2d117 100644
--- a/core/res/res/drawable/stat_sys_adb.xml
+++ b/wifi/java/android/net/wifi/IWifiScanner.aidl
@@ -1,13 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
/*
- * Copyright 2013, The Android Open Source Project
+ * 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
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,9 +13,15 @@
* 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/stat_sys_adb_am"
- android:autoMirrored="true">
-</bitmap>
+package android.net.wifi;
+
+import android.os.Messenger;
+
+/**
+ * {@hide}
+ */
+interface IWifiScanner
+{
+ Messenger getMessenger();
+}
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index d7ecaff..1cb9546 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -56,6 +56,13 @@
public long timestamp;
/**
+ * Timestamp representing date when this result was last seen, in milliseconds from 1970
+ * {@hide}
+ */
+ public long seen;
+
+
+ /**
* The approximate distance to the AP in centimeter, if available. Else
* {@link UNSPECIFIED}.
* {@hide}
@@ -114,9 +121,17 @@
timestamp = source.timestamp;
distanceCm = source.distanceCm;
distanceSdCm = source.distanceSdCm;
+ seen = source.seen;
}
}
+ /** empty scan result
+ *
+ * {@hide}
+ * */
+ public ScanResult() {
+ }
+
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 6562462..ce8c8b8 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -21,6 +21,7 @@
import android.os.Parcel;
import android.text.TextUtils;
+import java.util.HashMap;
import java.util.BitSet;
/**
@@ -302,6 +303,156 @@
/**
* @hide
+ * dhcp server MAC address if known
+ */
+ public String dhcpServer;
+
+ /**
+ * @hide
+ * default Gateway MAC address if known
+ */
+ public String defaultGwMacAddress;
+
+ /**
+ * @hide
+ * BSSID list on which this configuration was seen.
+ * TODO: prevent this list to grow infinitely, age-out the results
+ */
+ public HashMap<String, ScanResult> scanResultCache;
+
+ /** @hide **/
+ public static int INVALID_RSSI = -127;
+
+ /**
+ * @hide
+ * A summary of the RSSI and Band status for that configuration
+ * This is used as a temporary value by the auto-join controller
+ */
+ public final class Visibility
+ {
+ public int rssi5; // strongest 5GHz RSSI
+ public int rssi24; // strongest 2.4GHz RSSI
+ public int num5; // number of BSSIDs on 5GHz
+ public int num24; // number of BSSIDs on 2.4GHz
+ public long age5; // timestamp of the strongest 5GHz BSSID (last time it was seen)
+ public long age24; // timestamp of the strongest 2.4GHz BSSID (last time it was seen)
+ public Visibility()
+ {
+ rssi5 = INVALID_RSSI;
+ rssi24 = INVALID_RSSI;
+ }
+ public Visibility(Visibility source)
+ {
+ rssi5 = source.rssi5;
+ rssi24 = source.rssi24;
+ age24 = source.age24;
+ age5 = source.age5;
+ num24 = source.num24;
+ num5 = source.num5;
+ }
+ }
+
+ /** @hide
+ * Cache the visibility status of this configuration.
+ * Visibility can change at any time depending on scan results availability.
+ * Owner of the WifiConfiguration is responsible to set this field based on
+ * recent scan results.
+ ***/
+ public Visibility visibility;
+
+ /** @hide
+ * calculate and set Visibility for that configuration.
+ *
+ * age in milliseconds: we will consider only ScanResults that are more recent,
+ * i.e. younger.
+ ***/
+ public Visibility setVisibility(long age) {
+ if (scanResultCache == null) {
+ visibility = null;
+ return null;
+ }
+
+ Visibility status = new Visibility();
+
+ long now_ms = System.currentTimeMillis();
+ for(ScanResult result : scanResultCache.values()) {
+ if (result.seen == 0)
+ continue;
+
+ if ((result.frequency > 4900) && (result.frequency < 5900)) {
+ //strictly speaking: [4915, 5825]
+ //number of known BSSID on 5GHz band
+ status.num5 = status.num5 + 1;
+ } else if ((result.frequency > 2400) && (result.frequency < 2500)) {
+ //strictly speaking: [2412, 2482]
+ //number of known BSSID on 2.4Ghz band
+ status.num24 = status.num24 + 1;
+ }
+
+ if ((now_ms - result.seen) > age) continue;
+
+ if ((result.frequency > 4900) && (result.frequency < 5900)) {
+ if (result.level > status.rssi5) {
+ status.rssi5 = result.level;
+ status.age5 = result.seen;
+ }
+ } else if ((result.frequency > 2400) && (result.frequency < 2500)) {
+ if (result.level > status.rssi24) {
+ status.rssi24 = result.level;
+ status.age24 = result.seen;
+ }
+ }
+ }
+ visibility = status;
+ return status;
+ }
+
+ /** @hide */
+ public static final int AUTO_JOIN_ENABLED = 0;
+ /** @hide */
+ public static final int AUTO_JOIN_DISABLED_ON_AUTH_FAILURE = 1;
+ /**
+ * @hide
+ */
+ public int autoJoinStatus;
+
+ /**
+ * @hide
+ * Indicate that a WifiConfiguration is temporary and should not be saved
+ * nor considered by AutoJoin.
+ */
+ public boolean ephemeral;
+
+ /**
+ * @hide
+ * Connect choices
+ *
+ * remember the keys identifying the known WifiConfiguration over which this configuration
+ * was preferred by user or a "WiFi Network Management app", that is,
+ * a WifiManager.CONNECT_NETWORK or SELECT_NETWORK was received while this configuration
+ * was visible to the user:
+ * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP
+ *
+ * The integer represents the configuration's RSSI at that time (useful?)
+ *
+ * The overall auto-join algorithm make use of past connect choice so as to sort configuration,
+ * the exact algorithm still fluctuating as of 5/7/2014
+ *
+ */
+ public HashMap<String, Integer> connectChoices;
+
+ /**
+ * @hide
+ * Linked Configurations: represent the set of Wificonfigurations that are equivalent
+ * regarding roaming and auto-joining.
+ * The linked configuration may or may not have same SSID, and may or may not have same
+ * credentials.
+ * For instance, linked configurations will have same defaultGwMacAddress or same dhcp server.
+ */
+ public HashMap<String, Integer> linkedConfigurations;
+
+ /**
+ * @hide
*/
public enum ProxySettings {
/* No proxy is to be used. Any existing proxy settings
@@ -346,6 +497,7 @@
ipAssignment = IpAssignment.UNASSIGNED;
proxySettings = ProxySettings.UNASSIGNED;
linkProperties = new LinkProperties();
+ autoJoinStatus = AUTO_JOIN_ENABLED;
}
/**
@@ -369,6 +521,32 @@
// TODO: Add more checks
return true;
+
+ }
+
+ /**
+ * most recent time we have seen this configuration
+ * @return most recent scanResult
+ * @hide
+ */
+ public ScanResult lastSeen() {
+ ScanResult mostRecent = null;
+
+ if (scanResultCache == null) {
+ return null;
+ }
+
+ for (ScanResult result : scanResultCache.values()) {
+ if (mostRecent == null) {
+ if (result.seen != 0)
+ mostRecent = result;
+ } else {
+ if (result.seen > mostRecent.seen) {
+ mostRecent = result;
+ }
+ }
+ }
+ return mostRecent;
}
@Override
@@ -570,7 +748,48 @@
return KeyMgmt.NONE;
}
- /** Implement the Parcelable interface {@hide} */
+ /* @hide
+ * Cache the config key, this seems useful as a speed up since a lot of
+ * lookups in the config store are done and based on this key.
+ */
+ String mCachedConfigKey;
+
+ /** @hide
+ * return the string used to calculate the hash in WifiConfigStore
+ * and uniquely identify this WifiConfiguration
+ */
+ public String configKey(boolean allowCached) {
+ String key;
+ if (allowCached && mCachedConfigKey != null) {
+ key = mCachedConfigKey;
+ } else {
+ key = this.SSID;
+ if (key == null)
+ key = "";
+ if (this.wepKeys[0] != null) {
+ key = key + "-WEP";
+ }
+ if (this.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
+ key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK];
+ }
+ if (this.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
+ this.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
+ key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+ }
+ mCachedConfigKey = key;
+ }
+ return key;
+ }
+
+ /** @hide
+ * get configKey, force calculating the config string
+ */
+ public String configKey() {
+ return configKey(false);
+ }
+
+
+ /** Implement the Parcelable interface {@hide} */
public int describeContents() {
return 0;
}
@@ -603,8 +822,32 @@
ipAssignment = source.ipAssignment;
proxySettings = source.proxySettings;
+
+ defaultGwMacAddress = source.defaultGwMacAddress;
+
linkProperties = new LinkProperties(source.linkProperties);
- }
+ if ((source.scanResultCache != null) && (source.scanResultCache.size() > 0)) {
+ scanResultCache = new HashMap<String, ScanResult>();
+ scanResultCache.putAll(source.scanResultCache);
+ }
+
+ if ((source.connectChoices != null) && (source.connectChoices.size() > 0)) {
+ connectChoices = new HashMap<String, Integer>();
+ connectChoices.putAll(source.connectChoices);
+ }
+
+ if ((source.linkedConfigurations != null)
+ && (source.linkedConfigurations.size() > 0)) {
+ linkedConfigurations = new HashMap<String, Integer>();
+ linkedConfigurations.putAll(source.linkedConfigurations);
+ }
+ mCachedConfigKey = null; //force null configKey
+ autoJoinStatus = source.autoJoinStatus;
+
+ if (source.visibility != null) {
+ visibility = new Visibility(source.visibility);
+ }
+ }
}
/** Implement the Parcelable interface {@hide} */
@@ -633,6 +876,10 @@
dest.writeString(ipAssignment.name());
dest.writeString(proxySettings.name());
dest.writeParcelable(linkProperties, flags);
+
+ dest.writeString(dhcpServer);
+ dest.writeString(defaultGwMacAddress);
+ dest.writeInt(autoJoinStatus);
}
/** Implement the Parcelable interface {@hide} */
@@ -664,6 +911,10 @@
config.proxySettings = ProxySettings.valueOf(in.readString());
config.linkProperties = in.readParcelable(null);
+ config.dhcpServer = in.readString();
+ config.defaultGwMacAddress = in.readString();
+ config.autoJoinStatus = in.readInt();
+
return config;
}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
new file mode 100644
index 0000000..e02e14c
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -0,0 +1,584 @@
+/*
+ * 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 android.net.wifi;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+
+/**
+ * This class provides a way to scan the Wifi universe around the device
+ * Get an instance of this class by calling
+ * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context
+ * .WIFI_SCANNING_SERVICE)}.
+ * @hide
+ */
+public class WifiScanner {
+
+ public static final int WIFI_BAND_UNSPECIFIED = 0; /* not specified */
+ public static final int WIFI_BAND_24_GHZ = 1; /* 2.4 GHz band */
+ public static final int WIFI_BAND_5_GHZ = 2; /* 5 GHz band without DFS channels */
+ public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4; /* 5 GHz band with DFS channels */
+ public static final int WIFI_BAND_5_GHZ_WITH_DFS = 6; /* 5 GHz band with DFS channels */
+ public static final int WIFI_BAND_BOTH = 3; /* both bands without DFS channels */
+ public static final int WIFI_BAND_BOTH_WITH_DFS = 7; /* both bands with DFS channels */
+
+ public static final int MIN_SCAN_PERIOD_MS = 300; /* minimum supported period */
+ public static final int MAX_SCAN_PERIOD_MS = 1024000; /* maximum supported period */
+
+ public static final int REASON_SUCCEEDED = 0;
+ public static final int REASON_UNSPECIFIED = -1;
+ public static final int REASON_INVALID_LISTENER = -2;
+ public static final int REASON_INVALID_REQUEST = -3;
+ public static final int REASON_CONFLICTING_REQUEST = -4;
+
+ public static interface ActionListener {
+ public void onSuccess(Object result);
+ public void onFailure(int reason, Object exception);
+ }
+
+ /**
+ * gives you all the possible channels; channel is specified as an
+ * integer with frequency in MHz i.e. channel 1 is 2412
+ */
+ public List<Integer> getAvailableChannels(int band) {
+ return null;
+ }
+
+ /**
+ * provides channel specification to the APIs
+ */
+ public static class ChannelSpec {
+ public int frequency;
+ public boolean passive; /* ignored on DFS channels */
+ public int dwellTimeMS; /* not supported for now */
+
+ public ChannelSpec(int frequency) {
+ this.frequency = frequency;
+ passive = false;
+ dwellTimeMS = 0;
+ }
+ }
+
+ public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0;
+ public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1;
+ public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2;
+
+ /**
+ * scan configuration parameters
+ */
+ public static class ScanSettings implements Parcelable {
+
+ public int band; /* ignore channels if specified */
+ public ChannelSpec[] channels; /* list of channels to scan */
+ public int periodInMs; /* period of scan */
+ public int reportEvents; /* a valid REPORT_EVENT value */
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(band);
+ dest.writeInt(periodInMs);
+ dest.writeInt(channels.length);
+
+ for (int i = 0; i < channels.length; i++) {
+ dest.writeInt(channels[i].frequency);
+ dest.writeInt(channels[i].dwellTimeMS);
+ dest.writeInt(channels[i].passive ? 1 : 0);
+ }
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<ScanSettings> CREATOR =
+ new Creator<ScanSettings>() {
+ public ScanSettings createFromParcel(Parcel in) {
+
+ ScanSettings settings = new ScanSettings();
+ settings.band = in.readInt();
+ settings.periodInMs = in.readInt();
+ int num_channels = in.readInt();
+ settings.channels = new ChannelSpec[num_channels];
+ for (int i = 0; i < num_channels; i++) {
+ int frequency = in.readInt();
+
+ ChannelSpec spec = new ChannelSpec(frequency);
+ spec.dwellTimeMS = in.readInt();
+ spec.passive = in.readInt() == 1;
+ settings.channels[i] = spec;
+ }
+
+ return settings;
+ }
+
+ public ScanSettings[] newArray(int size) {
+ return new ScanSettings[size];
+ }
+ };
+
+ }
+
+ public static class InformationElement {
+ public int id;
+ public byte[] bytes;
+ }
+
+ public static class FullScanResult {
+ public ScanResult result;
+ public InformationElement informationElements[];
+ }
+
+ /** @hide */
+ public static class ParcelableScanResults implements Parcelable {
+ public ScanResult mResults[];
+
+ public ParcelableScanResults(ScanResult[] results) {
+ mResults = results;
+ }
+
+ public ScanResult[] getResults() {
+ return mResults;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mResults.length);
+ for (int i = 0; i < mResults.length; i++) {
+ ScanResult result = mResults[i];
+ result.writeToParcel(dest, flags);
+ }
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<ParcelableScanResults> CREATOR =
+ new Creator<ParcelableScanResults>() {
+ public ParcelableScanResults createFromParcel(Parcel in) {
+ int n = in.readInt();
+ ScanResult results[] = new ScanResult[n];
+ for (int i = 0; i < n; i++) {
+ results[i] = ScanResult.CREATOR.createFromParcel(in);
+ }
+ return new ParcelableScanResults(results);
+ }
+
+ public ParcelableScanResults[] newArray(int size) {
+ return new ParcelableScanResults[size];
+ }
+ };
+ }
+
+ /**
+ * Framework is co-ordinating scans across multiple apps; so it may not give exactly the
+ * same period requested. The period granted is stated on the onSuccess() event; and
+ * onPeriodChanged() will be called if/when it is changed because of multiple conflicting
+ * requests. This is similar to the way timers are handled.
+ */
+ public interface ScanListener extends ActionListener {
+ public void onPeriodChanged(int periodInMs);
+ public void onResults(ScanResult[] results);
+ public void onFullResult(FullScanResult fullScanResult);
+ }
+
+ public void scan(ScanSettings settings, ScanListener listener) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_SCAN, 0, putListener(listener), settings);
+ }
+ public void startBackgroundScan(ScanSettings settings, ScanListener listener) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, putListener(listener), settings);
+ }
+ public void stopBackgroundScan(boolean flush, ScanListener listener) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, removeListener(listener));
+ }
+ public void retrieveScanResults(boolean flush, ScanListener listener) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_GET_SCAN_RESULTS, 0, getListenerKey(listener));
+ }
+
+ public static class HotspotInfo {
+ public String bssid;
+ public int low; /* minimum RSSI */
+ public int high; /* maximum RSSI */
+ }
+
+ public static class WifiChangeSettings {
+ public int rssiSampleSize; /* sample size for RSSI averaging */
+ public int lostApSampleSize; /* samples to confirm AP's loss */
+ public int unchangedSampleSize; /* samples to confirm no change */
+ public int minApsBreachingThreshold; /* change threshold to trigger event */
+ public HotspotInfo[] hotspotInfos;
+ }
+
+ /* overrides the significant wifi change state machine configuration */
+ public void configureSignificantWifiChange(
+ int rssiSampleSize, /* sample size for RSSI averaging */
+ int lostApSampleSize, /* samples to confirm AP's loss */
+ int unchangedSampleSize, /* samples to confirm no change */
+ int minApsBreachingThreshold, /* change threshold to trigger event */
+ HotspotInfo[] hotspotInfos /* signal thresholds to crosss */
+ )
+ {
+ validateChannel();
+ WifiChangeSettings settings = new WifiChangeSettings();
+ settings.rssiSampleSize = rssiSampleSize;
+ settings.lostApSampleSize = lostApSampleSize;
+ settings.unchangedSampleSize = unchangedSampleSize;
+ settings.minApsBreachingThreshold = minApsBreachingThreshold;
+ settings.hotspotInfos = hotspotInfos;
+
+ sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
+ }
+
+ public interface SignificantWifiChangeListener extends ActionListener {
+ public void onChanging(ScanResult[] results); /* changes are found */
+ public void onQuiescence(ScanResult[] results); /* changes settled down */
+ }
+
+ public void trackSignificantWifiChange(SignificantWifiChangeListener listener) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, putListener(listener));
+ }
+ public void untrackSignificantWifiChange(SignificantWifiChangeListener listener) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, removeListener(listener));
+ }
+
+ public void configureSignificantWifiChange(WifiChangeSettings settings) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
+ }
+
+ public static interface HotlistListener extends ActionListener {
+ public void onFound(ScanResult[] results);
+ }
+
+ /** @hide */
+ public static class HotlistSettings implements Parcelable {
+ public HotspotInfo[] hotspotInfos;
+ public int apLostThreshold;
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(apLostThreshold);
+ dest.writeInt(hotspotInfos.length);
+ for (int i = 0; i < hotspotInfos.length; i++) {
+ HotspotInfo info = hotspotInfos[i];
+ dest.writeString(info.bssid);
+ dest.writeInt(info.low);
+ dest.writeInt(info.high);
+ }
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<HotlistSettings> CREATOR =
+ new Creator<HotlistSettings>() {
+ public HotlistSettings createFromParcel(Parcel in) {
+ HotlistSettings settings = new HotlistSettings();
+ settings.apLostThreshold = in.readInt();
+ int n = in.readInt();
+ settings.hotspotInfos = new HotspotInfo[n];
+ for (int i = 0; i < n; i++) {
+ HotspotInfo info = new HotspotInfo();
+ info.bssid = in.readString();
+ info.low = in.readInt();
+ info.high = in.readInt();
+ settings.hotspotInfos[i] = info;
+ }
+ return settings;
+ }
+
+ public HotlistSettings[] newArray(int size) {
+ return new HotlistSettings[size];
+ }
+ };
+ }
+
+ public void setHotlist(HotspotInfo[] hotspots,
+ int apLostThreshold, HotlistListener listener) {
+ validateChannel();
+ HotlistSettings settings = new HotlistSettings();
+ settings.hotspotInfos = hotspots;
+ sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, putListener(listener), settings);
+ }
+
+ public void resetHotlist(HotlistListener listener) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, removeListener(listener));
+ }
+
+
+ /* private members and methods */
+
+ private static final String TAG = "WifiScanner";
+ private static final boolean DBG = true;
+
+ /* commands for Wifi Service */
+ private static final int BASE = Protocol.BASE_WIFI_SCANNER;
+
+ /** @hide */
+ public static final int CMD_SCAN = BASE + 0;
+ /** @hide */
+ public static final int CMD_START_BACKGROUND_SCAN = BASE + 2;
+ /** @hide */
+ public static final int CMD_STOP_BACKGROUND_SCAN = BASE + 3;
+ /** @hide */
+ public static final int CMD_GET_SCAN_RESULTS = BASE + 4;
+ /** @hide */
+ public static final int CMD_SCAN_RESULT = BASE + 5;
+ /** @hide */
+ public static final int CMD_SET_HOTLIST = BASE + 6;
+ /** @hide */
+ public static final int CMD_RESET_HOTLIST = BASE + 7;
+ /** @hide */
+ public static final int CMD_AP_FOUND = BASE + 9;
+ /** @hide */
+ public static final int CMD_AP_LOST = BASE + 10;
+ /** @hide */
+ public static final int CMD_START_TRACKING_CHANGE = BASE + 11;
+ /** @hide */
+ public static final int CMD_STOP_TRACKING_CHANGE = BASE + 12;
+ /** @hide */
+ public static final int CMD_CONFIGURE_WIFI_CHANGE = BASE + 13;
+ /** @hide */
+ public static final int CMD_WIFI_CHANGE_DETECTED = BASE + 15;
+ /** @hide */
+ public static final int CMD_WIFI_CHANGES_STABILIZED = BASE + 16;
+ /** @hide */
+ public static final int CMD_OP_SUCCEEDED = BASE + 17;
+ /** @hide */
+ public static final int CMD_OP_FAILED = BASE + 18;
+ /** @hide */
+ public static final int CMD_PERIOD_CHANGED = BASE + 19;
+ /** @hide */
+ public static final int CMD_FULL_SCAN_RESULT = BASE + 20;
+
+ private Context mContext;
+ private IWifiScanner mService;
+
+ private static final int INVALID_KEY = 0;
+ private static int sListenerKey = 1;
+
+ private static final SparseArray sListenerMap = new SparseArray();
+ private static final Object sListenerMapLock = new Object();
+
+ private static AsyncChannel sAsyncChannel;
+ private static CountDownLatch sConnected;
+
+ private static final Object sThreadRefLock = new Object();
+ private static int sThreadRefCount;
+ private static HandlerThread sHandlerThread;
+
+ /**
+ * Create a new WifiScanner instance.
+ * Applications will almost always want to use
+ * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
+ * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
+ * @param context the application context
+ * @param service the Binder interface
+ * @hide
+ */
+ public WifiScanner(Context context, IWifiScanner service) {
+ mContext = context;
+ mService = service;
+ init();
+ }
+
+ private void init() {
+ synchronized (sThreadRefLock) {
+ if (++sThreadRefCount == 1) {
+ Messenger messenger = null;
+ try {
+ messenger = mService.getMessenger();
+ } catch (RemoteException e) {
+ /* do nothing */
+ } catch (SecurityException e) {
+ /* do nothing */
+ }
+
+ if (messenger == null) {
+ sAsyncChannel = null;
+ return;
+ }
+
+ sHandlerThread = new HandlerThread("WifiScanner");
+ sAsyncChannel = new AsyncChannel();
+ sConnected = new CountDownLatch(1);
+
+ sHandlerThread.start();
+ Handler handler = new ServiceHandler(sHandlerThread.getLooper());
+ sAsyncChannel.connect(mContext, handler, messenger);
+ try {
+ sConnected.await();
+ } catch (InterruptedException e) {
+ Log.e(TAG, "interrupted wait at init");
+ }
+ }
+ }
+ }
+
+ private void validateChannel() {
+ if (sAsyncChannel == null) throw new IllegalStateException(
+ "No permission to access and change wifi or a bad initialization");
+ }
+
+ private static int putListener(Object listener) {
+ if (listener == null) return INVALID_KEY;
+ int key;
+ synchronized (sListenerMapLock) {
+ do {
+ key = sListenerKey++;
+ } while (key == INVALID_KEY);
+ sListenerMap.put(key, listener);
+ }
+ return key;
+ }
+
+ private static Object getListener(int key) {
+ if (key == INVALID_KEY) return null;
+ synchronized (sListenerMapLock) {
+ Object listener = sListenerMap.get(key);
+ return listener;
+ }
+ }
+
+ private static int getListenerKey(Object listener) {
+ if (listener == null) return INVALID_KEY;
+ synchronized (sListenerMapLock) {
+ int index = sListenerMap.indexOfValue(listener);
+ if (index == -1) {
+ return INVALID_KEY;
+ } else {
+ return sListenerMap.keyAt(index);
+ }
+ }
+ }
+
+ private static Object removeListener(int key) {
+ if (key == INVALID_KEY) return null;
+ synchronized (sListenerMapLock) {
+ Object listener = sListenerMap.get(key);
+ sListenerMap.remove(key);
+ return listener;
+ }
+ }
+
+ private static int removeListener(Object listener) {
+ int key = getListenerKey(listener);
+ if (key == INVALID_KEY) return key;
+ synchronized (sListenerMapLock) {
+ sListenerMap.remove(key);
+ return key;
+ }
+ }
+
+ private static class ServiceHandler extends Handler {
+ ServiceHandler(Looper looper) {
+ super(looper);
+ }
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+ if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+ sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+ } else {
+ Log.e(TAG, "Failed to set up channel connection");
+ // This will cause all further async API calls on the WifiManager
+ // to fail and throw an exception
+ sAsyncChannel = null;
+ }
+ sConnected.countDown();
+ return;
+ case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
+ return;
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
+ Log.e(TAG, "Channel connection lost");
+ // This will cause all further async API calls on the WifiManager
+ // to fail and throw an exception
+ sAsyncChannel = null;
+ getLooper().quit();
+ return;
+ }
+
+ Object listener = getListener(msg.arg2);
+ if (DBG) Log.d(TAG, "listener key = " + msg.arg2);
+
+ switch (msg.what) {
+ /* ActionListeners grouped together */
+ case CMD_OP_SUCCEEDED :
+ ((ActionListener) listener).onSuccess(msg.obj);
+ break;
+ case CMD_OP_FAILED :
+ ((ActionListener) listener).onFailure(msg.arg1, msg.obj);
+ break;
+ case CMD_SCAN_RESULT :
+ ((ScanListener) listener).onResults(
+ ((ParcelableScanResults) msg.obj).getResults());
+ return;
+ case CMD_FULL_SCAN_RESULT :
+ FullScanResult result = (FullScanResult) msg.obj;
+ ((ScanListener) listener).onFullResult(result);
+ return;
+ case CMD_AP_FOUND:
+ ((HotlistListener) listener).onFound(
+ ((ParcelableScanResults) msg.obj).getResults());
+ return;
+ case CMD_WIFI_CHANGE_DETECTED:
+ ((SignificantWifiChangeListener) listener).onChanging(
+ ((ParcelableScanResults) msg.obj).getResults());
+ return;
+ case CMD_WIFI_CHANGES_STABILIZED:
+ ((SignificantWifiChangeListener) listener).onQuiescence(
+ ((ParcelableScanResults) msg.obj).getResults());
+ return;
+ default:
+ if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
+ return;
+ }
+ }
+ }
+}